static bool TryConvertArgument(IntPtr op, Type parameterType, bool needsResolution, out object arg, out bool isOut) { arg = null; isOut = false; var clrtype = TryComputeClrArgumentType(parameterType, op, needsResolution: needsResolution); if (clrtype == null) { return(false); } if (!Converter.ToManaged(op, clrtype, out arg, false)) { // Arturo Rodriguez -- Start // Needed to allow Python objects to be passed from python code to CLR functions. var pyobj = new PyObject(op); var ptype = pyobj.GetPythonType(); arg = pyobj; clrtype = arg.GetType(); isOut = clrtype.IsByRef; return(true); // Arturo Rodriguez -- End // Repo code // Exceptions.Clear(); // return false; } isOut = clrtype.IsByRef; return(true); }
/// <summary> /// Descriptor __set__ implementation. This method sets the value of /// a field based on the given Python value. The Python value must be /// convertible to the type of the field. /// </summary> public new static int tp_descr_set(IntPtr ds, IntPtr ob, IntPtr val) { var self = (FieldObject)GetManagedObject(ds); object newval; if (self == null) { return(-1); } if (val == IntPtr.Zero) { Exceptions.SetError(Exceptions.TypeError, "cannot delete field"); return(-1); } FieldInfo info = self.info; if (info.IsLiteral || info.IsInitOnly) { Exceptions.SetError(Exceptions.TypeError, "field is read-only"); return(-1); } bool is_static = info.IsStatic; if (ob == IntPtr.Zero || ob == Runtime.PyNone) { if (!is_static) { Exceptions.SetError(Exceptions.TypeError, "instance attribute must be set through a class instance"); return(-1); } } if (!Converter.ToManaged(val, info.FieldType, out newval, true)) { return(-1); } try { if (!is_static) { var co = (CLRObject)GetManagedObject(ob); info.SetValue(co.inst, newval); } else { info.SetValue(null, newval); } return(0); } catch (Exception e) { Exceptions.SetError(Exceptions.TypeError, e.Message); return(-1); } }
/// <summary> /// Implements __new__ for reflected classes and value types. /// </summary> public static IntPtr tp_new(IntPtr tp, IntPtr args, IntPtr kw) { var self = GetManagedObject(tp) as ClassObject; // Sanity check: this ensures a graceful error if someone does // something intentially wrong like use the managed metatype for // a class that is not really derived from a managed class. if (self == null) { return(Exceptions.RaiseTypeError("invalid object")); } Type type = self.type; // Primitive types do not have constructors, but they look like // they do from Python. If the ClassObject represents one of the // convertible primitive types, just convert the arg directly. if (type.IsPrimitive || type == typeof(string)) { if (Runtime.PyTuple_Size(args) != 1) { Exceptions.SetError(Exceptions.TypeError, "no constructors match given arguments"); return(IntPtr.Zero); } IntPtr op = Runtime.PyTuple_GetItem(args, 0); object result; if (!Converter.ToManaged(op, type, out result, true)) { return(IntPtr.Zero); } return(CLRObject.GetInstHandle(result, tp)); } if (type.IsAbstract) { Exceptions.SetError(Exceptions.TypeError, "cannot instantiate abstract class"); return(IntPtr.Zero); } if (type.IsEnum) { Exceptions.SetError(Exceptions.TypeError, "cannot instantiate enumeration"); return(IntPtr.Zero); } object obj = self.binder.InvokeRaw(IntPtr.Zero, args, kw); if (obj == null) { return(IntPtr.Zero); } return(CLRObject.GetInstHandle(obj, tp)); }
public static IntPtr tp_new(IntPtr tpRaw, IntPtr args, IntPtr kw) { if (kw != IntPtr.Zero) { return(Exceptions.RaiseTypeError("array constructor takes no keyword arguments")); } var tp = new BorrowedReference(tpRaw); var self = GetManagedObject(tp) as ArrayObject; if (!self.type.Valid) { return(Exceptions.RaiseTypeError(self.type.DeletedMessage)); } Type arrType = self.type.Value; long[] dimensions = new long[Runtime.PyTuple_Size(args)]; if (dimensions.Length == 0) { return(Exceptions.RaiseTypeError("array constructor requires at least one integer argument or an object convertible to array")); } if (dimensions.Length != 1) { return(CreateMultidimensional(arrType.GetElementType(), dimensions, shapeTuple: new BorrowedReference(args), pyType: tp) .DangerousMoveToPointerOrNull()); } IntPtr op = Runtime.PyTuple_GetItem(args, 0); // create single dimensional array if (Runtime.PyInt_Check(op)) { dimensions[0] = Runtime.PyLong_AsSignedSize_t(op); if (dimensions[0] == -1 && Exceptions.ErrorOccurred()) { Exceptions.Clear(); } else { return(NewInstance(arrType.GetElementType(), tp, dimensions) .DangerousMoveToPointerOrNull()); } } object result; // this implements casting to Array[T] if (!Converter.ToManaged(op, arrType, out result, true)) { return(IntPtr.Zero); } return(CLRObject.GetInstHandle(result, tp) .DangerousGetAddress()); }
/// <summary> /// AsManagedObject Method /// </summary> /// <remarks> /// Return a managed object of the given type, based on the /// value of the Python object. /// </remarks> public object AsManagedObject(Type t) { object result; if (!Converter.ToManaged(obj, t, out result, false)) { throw new InvalidCastException("cannot convert object to target type"); } return(result); }
/// <summary> /// Helper function for ToArray and ToList that creates a IList out of iterable objects /// </summary> /// <param name="value"></param> /// <param name="IterObject"></param> /// <param name="obType"></param> /// <param name="elementType"></param> /// <param name="setError"></param> /// <returns></returns> private static IList MakeList(IntPtr value, IntPtr IterObject, Type obType, Type elementType, bool setError) { IList list; try { // MakeGenericType can throw because elementType may not be a valid generic argument even though elementType[] is a valid array type. // For example, if elementType is a pointer type. // See https://docs.microsoft.com/en-us/dotnet/api/system.type.makegenerictype#System_Type_MakeGenericType_System_Type var constructedListType = typeof(List <>).MakeGenericType(elementType); bool IsSeqObj = Runtime.PySequence_Check(value); if (IsSeqObj) { var len = Runtime.PySequence_Size(value); list = (IList)Activator.CreateInstance(constructedListType, new Object[] { (int)len }); } else { // CreateInstance can throw even if MakeGenericType succeeded. // See https://docs.microsoft.com/en-us/dotnet/api/system.activator.createinstance#System_Activator_CreateInstance_System_Type_ list = (IList)Activator.CreateInstance(constructedListType); } } catch (Exception e) { if (setError) { Exceptions.SetError(e); SetConversionError(value, obType); } return(null); } IntPtr item; var usedImplicit = false; while ((item = Runtime.PyIter_Next(IterObject)) != IntPtr.Zero) { object obj; if (!Converter.ToManaged(item, elementType, out obj, setError, out usedImplicit)) { Runtime.XDecref(item); return(null); } list.Add(obj); Runtime.XDecref(item); } Runtime.XDecref(IterObject); return(list); }
private static NewReference NewEnum(Type type, BorrowedReference args, BorrowedReference tp) { nint argCount = Runtime.PyTuple_Size(args); bool allowUnchecked = false; if (argCount == 2) { var allow = Runtime.PyTuple_GetItem(args, 1); if (!Converter.ToManaged(allow, typeof(bool), out var allowObj, true) || allowObj is null) { Exceptions.RaiseTypeError("second argument to enum constructor must be a boolean"); return(default);
public static NewReference tp_new(BorrowedReference tp, BorrowedReference args, BorrowedReference kw) { if (kw != null) { return(Exceptions.RaiseTypeError("array constructor takes no keyword arguments")); } var self = (ArrayObject)GetManagedObject(tp) !; if (!self.type.Valid) { return(Exceptions.RaiseTypeError(self.type.DeletedMessage)); } Type arrType = self.type.Value; long[] dimensions = new long[Runtime.PyTuple_Size(args)]; if (dimensions.Length == 0) { return(Exceptions.RaiseTypeError("array constructor requires at least one integer argument or an object convertible to array")); } if (dimensions.Length != 1) { return(CreateMultidimensional(arrType.GetElementType(), dimensions, shapeTuple: args, pyType: tp)); } BorrowedReference op = Runtime.PyTuple_GetItem(args, 0); // create single dimensional array if (Runtime.PyInt_Check(op)) { dimensions[0] = Runtime.PyLong_AsSignedSize_t(op); if (dimensions[0] == -1 && Exceptions.ErrorOccurred()) { Exceptions.Clear(); } else { return(NewInstance(arrType.GetElementType(), tp, dimensions)); } } // this implements casting to Array[T] if (Converter.ToManaged(op, arrType, out object?result, true)) { return(CLRObject.GetReference(result !, tp)); } else { return(default);
/// <summary> /// As Method /// </summary> /// <remarks> /// Return a managed object of the given type, based on the /// value of the Python object. /// </remarks> public T As <T>() { if (typeof(T) == typeof(PyObject) || typeof(T) == typeof(object)) { return((T)(this as object)); } object result; if (!Converter.ToManaged(obj, typeof(T), out result, false)) { throw new InvalidCastException("cannot convert object to target type"); } return((T)result); }
/// <summary> /// Convert a Python value to a correctly typed managed array instance. /// The Python value must support the Python iterator protocol or and the /// items in the sequence must be convertible to the target array type. /// </summary> private static bool ToArray(IntPtr value, Type obType, out object result, bool setError) { Type elementType = obType.GetElementType(); result = null; bool IsSeqObj = Runtime.PySequence_Check(value); var len = IsSeqObj ? Runtime.PySequence_Size(value) : -1; IntPtr IterObject = Runtime.PyObject_GetIter(value); if (IterObject == IntPtr.Zero) { if (setError) { SetConversionError(value, obType); } return(false); } Array items; var listType = typeof(List <>); var constructedListType = listType.MakeGenericType(elementType); IList list = IsSeqObj ? (IList)Activator.CreateInstance(constructedListType, new Object[] { (int)len }) : (IList)Activator.CreateInstance(constructedListType); IntPtr item; while ((item = Runtime.PyIter_Next(IterObject)) != IntPtr.Zero) { object obj = null; if (!Converter.ToManaged(item, elementType, out obj, true)) { Runtime.XDecref(item); return(false); } list.Add(obj); Runtime.XDecref(item); } Runtime.XDecref(IterObject); items = Array.CreateInstance(elementType, list.Count); list.CopyTo(items, 0); result = items; return(true); }
//==================================================================== // Convert a Python value to a correctly typed managed array instance. // The Python value must support the Python sequence protocol and the // items in the sequence must be convertible to the target array type. //==================================================================== static bool ToArray(IntPtr value, Type obType, out Object result, bool setError) { Type elementType = obType.GetElementType(); int size = Runtime.PySequence_Size(value); result = null; if (size < 0) { if (setError) { SetConversionError(value, obType); } return(false); } Array items = Array.CreateInstance(elementType, size); // XXX - is there a better way to unwrap this if it is a real // array? for (int i = 0; i < size; i++) { Object obj = null; IntPtr item = Runtime.PySequence_GetItem(value, i); if (item == IntPtr.Zero) { if (setError) { SetConversionError(value, obType); return(false); } } if (!Converter.ToManaged(item, elementType, out obj, true)) { Runtime.Decref(item); return(false); } items.SetValue(obj, i); Runtime.Decref(item); } result = items; return(true); }
public static IntPtr tp_new(IntPtr tp, IntPtr args, IntPtr kw) { var self = GetManagedObject(tp) as ArrayObject; if (Runtime.Interop.PyTuple_Size(args) != 1) { return(Exceptions.RaiseTypeError("array expects 1 argument")); } IntPtr op = Runtime.Interop.PyTuple_GetItem(args, 0); object result; if (!Converter.ToManaged(op, self.type, out result, true)) { return(IntPtr.Zero); } return(CLRObject.GetInstHandle(result, tp)); }
public object TrueDispatch(ArrayList args) { MethodInfo method = dtype.GetMethod("Invoke"); ParameterInfo[] pi = method.GetParameters(); IntPtr pyargs = Runtime.PyTuple_New(pi.Length); Type rtype = method.ReturnType; for (int i = 0; i < pi.Length; i++) { // Here we own the reference to the Python value, and we // give the ownership to the arg tuple. IntPtr arg = Converter.ToPython(args[i], pi[i].ParameterType); Runtime.PyTuple_SetItem(pyargs, i, arg); } IntPtr op = Runtime.PyObject_Call(target, pyargs, IntPtr.Zero); Runtime.Decref(pyargs); if (op == IntPtr.Zero) { PythonException e = new PythonException(); throw e; } if (rtype == typeof(void)) { return(null); } Object result = null; if (!Converter.ToManaged(op, rtype, out result, false)) { string s = "could not convert Python result to " + rtype.ToString(); Runtime.Decref(op); throw new ConversionException(s); } Runtime.Decref(op); return(result); }
/// <summary> /// Implements __contains__ for dictionary types. /// </summary> public static int sq_contains(BorrowedReference ob, BorrowedReference v) { var obj = (CLRObject)GetManagedObject(ob); var self = obj.inst; var key = Tuple.Create(self.GetType(), "ContainsKey"); var methodInfo = methodsByType[key]; var parameters = methodInfo.GetParameters(); object arg; if (!Converter.ToManaged(v, parameters[0].ParameterType, out arg, false)) { Exceptions.SetError(Exceptions.TypeError, $"invalid parameter type for sq_contains: should be {Converter.GetTypeByAlias(v)}, found {parameters[0].ParameterType}"); } return((bool)methodInfo.Invoke(self, new[] { arg }) ? 1 : 0); }
/// <summary> /// Implements __contains__ for array types. /// </summary> public static int sq_contains(IntPtr ob, IntPtr v) { var obj = (CLRObject)GetManagedObject(ob); Type itemType = obj.inst.GetType().GetElementType(); var items = obj.inst as IList; object value; if (!Converter.ToManaged(v, itemType, out value, false)) { return(0); } if (items.Contains(value)) { return(1); } return(0); }
/// <summary> /// Try to convert a Python argument object to a managed CLR type. /// If unsuccessful, may set a Python error. /// </summary> /// <param name="op">Pointer to the Python argument object.</param> /// <param name="parameterType">That parameter's managed type.</param> /// <param name="arg">Converted argument.</param> /// <param name="isOut">Whether the CLR type is passed by reference.</param> /// <returns>true on success</returns> static bool TryConvertArgument(IntPtr op, Type parameterType, out object arg, out bool isOut) { arg = null; isOut = false; var clrtype = TryComputeClrArgumentType(parameterType, op); if (clrtype == null) { return(false); } if (!Converter.ToManaged(op, clrtype, out arg, true)) { return(false); } isOut = clrtype.IsByRef; return(true); }
/// <summary> /// Helper method that will enumerate a Python sequence convert its values to the given /// type and send them to the provided action /// </summary> private static bool ApplyActionToPySequence(IntPtr value, Type obType, bool setError, int size, Type elementType, Action <object> action) { if (size < 0) { if (setError) { SetConversionError(value, obType); } return(false); } for (var i = 0; i < size; i++) { object obj = null; IntPtr item = Runtime.PySequence_GetItem(value, i); if (item == IntPtr.Zero) { if (setError) { SetConversionError(value, obType); return(false); } } if (!Converter.ToManaged(item, elementType, out obj, true)) { Runtime.XDecref(item); return(false); } action(obj); Runtime.XDecref(item); } return(true); }
static bool TryConvertArgument(IntPtr op, Type parameterType, bool needsResolution, out object arg, out bool isOut) { arg = null; isOut = false; var clrtype = TryComputeClrArgumentType(parameterType, op, needsResolution: needsResolution); if (clrtype == null) { return(false); } if (!Converter.ToManaged(op, clrtype, out arg, false)) { Exceptions.Clear(); return(false); } isOut = clrtype.IsByRef; return(true); }
//==================================================================== // Implements __new__ for reflected classes and value types. //==================================================================== public static IntPtr tp_new(IntPtr tp, IntPtr args, IntPtr kw) { ClassObject self = GetManagedObject(tp) as ClassObject; // Sanity check: this ensures a graceful error if someone does // something intentially wrong like use the managed metatype for // a class that is not really derived from a managed class. if (self == null) { return(Exceptions.RaiseTypeError("invalid object")); } Type type = self.type; // Primitive types do not have constructors, but they look like // they do from Python. If the ClassObject represents one of the // convertible primitive types, just convert the arg directly. if (type.IsPrimitive || type == typeof(String)) { if (Runtime.PyTuple_Size(args) != 1) { Exceptions.SetError(Exceptions.TypeError, "no constructors match given arguments" ); return(IntPtr.Zero); } IntPtr op = Runtime.PyTuple_GetItem(args, 0); Object result; if (!Converter.ToManaged(op, type, out result, true)) { return(IntPtr.Zero); } return(CLRObject.GetInstHandle(result, tp)); } if (type.IsAbstract) { Exceptions.SetError(Exceptions.TypeError, "cannot instantiate abstract class" ); return(IntPtr.Zero); } if (type.IsEnum) { Exceptions.SetError(Exceptions.TypeError, "cannot instantiate enumeration" ); return(IntPtr.Zero); } Object obj = self.binder.InvokeRaw(IntPtr.Zero, args, kw); if (obj == null) { // It is possible for __new__ to be invoked on construction // of a Python subclass of a managed class, so args may // reflect more args than are required to instantiate the // class. So if we cant find a ctor that matches, we'll see // if there is a default constructor and, if so, assume that // any extra args are intended for the subclass' __init__. IntPtr eargs = Runtime.PyTuple_New(0); obj = self.binder.InvokeRaw(IntPtr.Zero, eargs, kw); Runtime.Decref(eargs); if (obj == null) { return(IntPtr.Zero); } } return(CLRObject.GetInstHandle(obj, tp)); }
internal Binding Bind(IntPtr inst, IntPtr args, IntPtr kw, MethodBase info, MethodInfo[] methodinfo) { // loop to find match, return invoker w/ or /wo error MethodBase[] _methods = null; int pynargs = Runtime.PyTuple_Size(args); object arg; bool isGeneric = false; if (info != null) { _methods = (MethodBase[])Array.CreateInstance( typeof(MethodBase), 1 ); _methods.SetValue(info, 0); } else { _methods = GetMethods(); } for (int i = 0; i < _methods.Length; i++) { MethodBase mi = _methods[i]; if (mi.IsGenericMethod) { isGeneric = true; } ParameterInfo[] pi = mi.GetParameters(); int clrnargs = pi.Length; bool match = false; int arrayStart = -1; int outs = 0; if (pynargs == clrnargs) { match = true; } else if ((pynargs > clrnargs) && (clrnargs > 0) && (pi[clrnargs - 1].ParameterType.IsArray)) { // The last argument of the mananged functions seems to // accept multiple arguments as a array. Hopefully it's a // spam(params object[] egg) style method match = true; arrayStart = clrnargs - 1; } if (match) { Object[] margs = new Object[clrnargs]; for (int n = 0; n < clrnargs; n++) { IntPtr op; if (arrayStart == n) { // map remaining Python arguments to a tuple since // the managed function accepts it - hopefully :] op = Runtime.PyTuple_GetSlice(args, arrayStart, pynargs); } else { op = Runtime.PyTuple_GetItem(args, n); } Type type = pi[n].ParameterType; if (pi[n].IsOut || type.IsByRef) { outs++; } if (!Converter.ToManaged(op, type, out arg, false)) { Exceptions.Clear(); margs = null; break; } if (arrayStart == n) { // GetSlice() creates a new reference but GetItem() // returns only a borrow reference. Runtime.Decref(op); } margs[n] = arg; } if (margs == null) { continue; } Object target = null; if ((!mi.IsStatic) && (inst != IntPtr.Zero)) { //CLRObject co = (CLRObject)ManagedType.GetManagedObject(inst); // InvalidCastException: Unable to cast object of type // 'Python.Runtime.ClassObject' to type 'Python.Runtime.CLRObject' CLRObject co = ManagedType.GetManagedObject(inst) as CLRObject; // Sanity check: this ensures a graceful exit if someone does // something intentionally wrong like call a non-static method // on the class rather than on an instance of the class. // XXX maybe better to do this before all the other rigmarole. if (co == null) { return(null); } target = co.inst; } return(new Binding(mi, target, margs, outs)); } } // We weren't able to find a matching method but at least one // is a generic method and info is null. That happens when a generic // method was not called using the [] syntax. Let's introspect the // type of the arguments and use it to construct the correct method. if (isGeneric && (info == null) && (methodinfo != null)) { Type[] types = Runtime.PythonArgsToTypeArray(args, true); MethodInfo mi = MethodBinder.MatchParameters(methodinfo, types); return(Bind(inst, args, kw, mi, null)); } return(null); }
private object?TrueDispatch(object?[] args) { MethodInfo method = dtype.GetMethod("Invoke"); ParameterInfo[] pi = method.GetParameters(); Type rtype = method.ReturnType; NewReference callResult; using (var pyargs = Runtime.PyTuple_New(pi.Length)) { for (var i = 0; i < pi.Length; i++) { // Here we own the reference to the Python value, and we // give the ownership to the arg tuple. using var arg = Converter.ToPython(args[i], pi[i].ParameterType); int res = Runtime.PyTuple_SetItem(pyargs.Borrow(), i, arg.StealOrThrow()); if (res != 0) { throw PythonException.ThrowLastAsClrException(); } } callResult = Runtime.PyObject_Call(target, pyargs.Borrow(), null); } if (callResult.IsNull()) { throw PythonException.ThrowLastAsClrException(); } using (callResult) { BorrowedReference op = callResult.Borrow(); int byRefCount = pi.Count(parameterInfo => parameterInfo.ParameterType.IsByRef); if (byRefCount > 0) { // By symmetry with MethodBinder.Invoke, when there are out // parameters we expect to receive a tuple containing // the result, if any, followed by the out parameters. If there is only // one out parameter and the return type of the method is void, // we instead receive the out parameter as the result from Python. bool isVoid = rtype == typeof(void); int tupleSize = byRefCount + (isVoid ? 0 : 1); if (isVoid && byRefCount == 1) { // The return type is void and there is a single out parameter. for (int i = 0; i < pi.Length; i++) { Type t = pi[i].ParameterType; if (t.IsByRef) { if (!Converter.ToManaged(op, t, out args[i], true)) { Exceptions.RaiseTypeError($"The Python function did not return {t.GetElementType()} (the out parameter type)"); throw PythonException.ThrowLastAsClrException(); } break; } } return(null); } else if (Runtime.PyTuple_Check(op) && Runtime.PyTuple_Size(op) == tupleSize) { int index = isVoid ? 0 : 1; for (int i = 0; i < pi.Length; i++) { Type t = pi[i].ParameterType; if (t.IsByRef) { BorrowedReference item = Runtime.PyTuple_GetItem(op, index++); if (!Converter.ToManaged(item, t, out args[i], true)) { Exceptions.RaiseTypeError($"The Python function returned a tuple where element {i} was not {t.GetElementType()} (the out parameter type)"); throw PythonException.ThrowLastAsClrException(); } } } if (isVoid) { return(null); } BorrowedReference item0 = Runtime.PyTuple_GetItem(op, 0); if (!Converter.ToManaged(item0, rtype, out object?result0, true)) { Exceptions.RaiseTypeError($"The Python function returned a tuple where element 0 was not {rtype} (the return type)"); throw PythonException.ThrowLastAsClrException(); } return(result0); } else { string tpName = Runtime.PyObject_GetTypeName(op); if (Runtime.PyTuple_Check(op)) { tpName += $" of size {Runtime.PyTuple_Size(op)}"; } StringBuilder sb = new StringBuilder(); if (!isVoid) { sb.Append(rtype.FullName); } for (int i = 0; i < pi.Length; i++) { Type t = pi[i].ParameterType; if (t.IsByRef) { if (sb.Length > 0) { sb.Append(","); } sb.Append(t.GetElementType().FullName); } } string returnValueString = isVoid ? "" : "the return value and "; Exceptions.RaiseTypeError($"Expected a tuple ({sb}) of {returnValueString}the values for out and ref parameters, got {tpName}."); throw PythonException.ThrowLastAsClrException(); } } if (rtype == typeof(void)) { return(null); } if (!Converter.ToManaged(op, rtype, out object?result, true)) { throw PythonException.ThrowLastAsClrException(); } return(result); } }
/// <summary> /// Convert a Python value to a correctly typed managed array instance. /// The Python value must support the Python iterator protocol or and the /// items in the sequence must be convertible to the target array type. /// </summary> private static bool ToArray(BorrowedReference value, Type obType, out object?result, bool setError) { Type elementType = obType.GetElementType(); result = null; using var IterObject = Runtime.PyObject_GetIter(value); if (IterObject.IsNull()) { if (setError) { SetConversionError(value, obType); } else { // PyObject_GetIter will have set an error Exceptions.Clear(); } return(false); } IList list; try { // MakeGenericType can throw because elementType may not be a valid generic argument even though elementType[] is a valid array type. // For example, if elementType is a pointer type. // See https://docs.microsoft.com/en-us/dotnet/api/system.type.makegenerictype#System_Type_MakeGenericType_System_Type var constructedListType = typeof(List <>).MakeGenericType(elementType); bool IsSeqObj = Runtime.PySequence_Check(value); object[] constructorArgs = Array.Empty <object>(); if (IsSeqObj) { var len = Runtime.PySequence_Size(value); if (len >= 0) { if (len <= int.MaxValue) { constructorArgs = new object[] { (int)len }; } } else { // for the sequences, that explicitly deny calling __len__() Exceptions.Clear(); } } // CreateInstance can throw even if MakeGenericType succeeded. // See https://docs.microsoft.com/en-us/dotnet/api/system.activator.createinstance#System_Activator_CreateInstance_System_Type_ list = (IList)Activator.CreateInstance(constructedListType, args: constructorArgs); } catch (Exception e) { if (setError) { Exceptions.SetError(e); SetConversionError(value, obType); } return(false); } while (true) { using var item = Runtime.PyIter_Next(IterObject.Borrow()); if (item.IsNull()) { break; } if (!Converter.ToManaged(item.Borrow(), elementType, out var obj, setError)) { return(false); } list.Add(obj); } if (Exceptions.ErrorOccurred()) { if (!setError) { Exceptions.Clear(); } return(false); } Array items = Array.CreateInstance(elementType, list.Count); list.CopyTo(items, 0); result = items; return(true); }
internal Binding Bind(IntPtr inst, IntPtr args, IntPtr kw, MethodBase info, MethodInfo[] methodinfo) { // Relevant function variables used post conversion var isGeneric = false; Binding bindingUsingImplicitConversion = null; // If we have KWArgs create dictionary and collect them Dictionary <string, IntPtr> kwArgDict = null; if (kw != IntPtr.Zero) { var pyKwArgsCount = (int)Runtime.PyDict_Size(kw); kwArgDict = new Dictionary <string, IntPtr>(pyKwArgsCount); IntPtr keylist = Runtime.PyDict_Keys(kw); IntPtr valueList = Runtime.PyDict_Values(kw); for (int i = 0; i < pyKwArgsCount; ++i) { var keyStr = Runtime.GetManagedString(Runtime.PyList_GetItem(new BorrowedReference(keylist), i)); kwArgDict[keyStr] = Runtime.PyList_GetItem(new BorrowedReference(valueList), i).DangerousGetAddress(); } Runtime.XDecref(keylist); Runtime.XDecref(valueList); } // Fetch our methods we are going to attempt to match and bind too. var methods = info == null?GetMethods() : new List <MethodInformation>(1) { new MethodInformation(info, info.GetParameters()) }; foreach (var methodInformation in methods) { // Relevant method variables var mi = methodInformation.MethodBase; var pi = methodInformation.ParameterInfo; isGeneric = mi.IsGenericMethod; int pyArgCount = (int)Runtime.PyTuple_Size(args); // Special case for operators bool isOperator = OperatorMethod.IsOperatorMethod(mi); // Binary operator methods will have 2 CLR args but only one Python arg // (unary operators will have 1 less each), since Python operator methods are bound. isOperator = isOperator && pyArgCount == pi.Length - 1; bool isReverse = isOperator && OperatorMethod.IsReverse((MethodInfo)mi); // Only cast if isOperator. if (isReverse && OperatorMethod.IsComparisonOp((MethodInfo)mi)) { continue; // Comparison operators in Python have no reverse mode. } // Preprocessing pi to remove either the first or second argument. if (isOperator && !isReverse) { // The first Python arg is the right operand, while the bound instance is the left. // We need to skip the first (left operand) CLR argument. pi = pi.Skip(1).ToArray(); } else if (isOperator && isReverse) { // The first Python arg is the left operand. // We need to take the first CLR argument. pi = pi.Take(1).ToArray(); } // Must be done after IsOperator section int clrArgCount = pi.Length; if (CheckMethodArgumentsMatch(clrArgCount, pyArgCount, kwArgDict, pi, out bool paramsArray, out ArrayList defaultArgList)) { var outs = 0; var margs = new object[clrArgCount]; int paramsArrayIndex = paramsArray ? pi.Length - 1 : -1; // -1 indicates no paramsArray var usedImplicitConversion = false; // Conversion loop for each parameter for (int paramIndex = 0; paramIndex < clrArgCount; paramIndex++) { IntPtr op = IntPtr.Zero; // Python object to be converted; not yet set var parameter = pi[paramIndex]; // Clr parameter we are targeting object arg; // Python -> Clr argument // Check our KWargs for this parameter bool hasNamedParam = kwArgDict == null ? false : kwArgDict.TryGetValue(parameter.Name, out op); bool isNewReference = false; // Check if we are going to use default if (paramIndex >= pyArgCount && !(hasNamedParam || (paramsArray && paramIndex == paramsArrayIndex))) { if (defaultArgList != null) { margs[paramIndex] = defaultArgList[paramIndex - pyArgCount]; } continue; } // At this point, if op is IntPtr.Zero we don't have a KWArg and are not using default if (op == IntPtr.Zero) { // If we have reached the paramIndex if (paramsArrayIndex == paramIndex) { op = HandleParamsArray(args, paramsArrayIndex, pyArgCount, out isNewReference); } else { op = Runtime.PyTuple_GetItem(args, paramIndex); } } // this logic below handles cases when multiple overloading methods // are ambiguous, hence comparison between Python and CLR types // is necessary Type clrtype = null; IntPtr pyoptype; if (methods.Count > 1) { pyoptype = IntPtr.Zero; pyoptype = Runtime.PyObject_Type(op); Exceptions.Clear(); if (pyoptype != IntPtr.Zero) { clrtype = Converter.GetTypeByAlias(pyoptype); } Runtime.XDecref(pyoptype); } if (clrtype != null) { var typematch = false; if ((parameter.ParameterType != typeof(object)) && (parameter.ParameterType != clrtype)) { IntPtr pytype = Converter.GetPythonTypeByAlias(parameter.ParameterType); pyoptype = Runtime.PyObject_Type(op); Exceptions.Clear(); if (pyoptype != IntPtr.Zero) { if (pytype != pyoptype) { typematch = false; } else { typematch = true; clrtype = parameter.ParameterType; } } if (!typematch) { // this takes care of nullables var underlyingType = Nullable.GetUnderlyingType(parameter.ParameterType); if (underlyingType == null) { underlyingType = parameter.ParameterType; } // this takes care of enum values TypeCode argtypecode = Type.GetTypeCode(underlyingType); TypeCode paramtypecode = Type.GetTypeCode(clrtype); if (argtypecode == paramtypecode) { typematch = true; clrtype = parameter.ParameterType; } // accepts non-decimal numbers in decimal parameters if (underlyingType == typeof(decimal)) { clrtype = parameter.ParameterType; typematch = Converter.ToManaged(op, clrtype, out arg, false); } // this takes care of implicit conversions var opImplicit = parameter.ParameterType.GetMethod("op_Implicit", new[] { clrtype }); if (opImplicit != null) { usedImplicitConversion = typematch = opImplicit.ReturnType == parameter.ParameterType; clrtype = parameter.ParameterType; } } Runtime.XDecref(pyoptype); if (!typematch) { margs = null; break; } } else { clrtype = parameter.ParameterType; } } else { clrtype = parameter.ParameterType; } if (parameter.IsOut || clrtype.IsByRef) { outs++; } if (!Converter.ToManaged(op, clrtype, out arg, false)) { Exceptions.Clear(); margs = null; break; } if (isNewReference) { // TODO: is this a bug? Should this happen even if the conversion fails? // GetSlice() creates a new reference but GetItem() // returns only a borrow reference. Runtime.XDecref(op); } margs[paramIndex] = arg; } if (margs == null) { continue; } if (isOperator) { if (inst != IntPtr.Zero) { if (ManagedType.GetManagedObject(inst) is CLRObject co) { bool isUnary = pyArgCount == 0; // Postprocessing to extend margs. var margsTemp = isUnary ? new object[1] : new object[2]; // If reverse, the bound instance is the right operand. int boundOperandIndex = isReverse ? 1 : 0; // If reverse, the passed instance is the left operand. int passedOperandIndex = isReverse ? 0 : 1; margsTemp[boundOperandIndex] = co.inst; if (!isUnary) { margsTemp[passedOperandIndex] = margs[0]; } margs = margsTemp; } else { continue; } } } object target = null; if (!mi.IsStatic && inst != IntPtr.Zero) { //CLRObject co = (CLRObject)ManagedType.GetManagedObject(inst); // InvalidCastException: Unable to cast object of type // 'Python.Runtime.ClassObject' to type 'Python.Runtime.CLRObject' var co = ManagedType.GetManagedObject(inst) as CLRObject; // Sanity check: this ensures a graceful exit if someone does // something intentionally wrong like call a non-static method // on the class rather than on an instance of the class. // XXX maybe better to do this before all the other rigmarole. if (co == null) { return(null); } target = co.inst; } var binding = new Binding(mi, target, margs, outs); if (usedImplicitConversion) { // lets just keep the first binding using implicit conversion // this is to respect method order/precedence if (bindingUsingImplicitConversion == null) { // in this case we will not return the binding yet in case there is a match // which does not use implicit conversions, which will return directly bindingUsingImplicitConversion = binding; } } else { return(binding); } } } // if we generated a binding using implicit conversion return it if (bindingUsingImplicitConversion != null) { return(bindingUsingImplicitConversion); } // We weren't able to find a matching method but at least one // is a generic method and info is null. That happens when a generic // method was not called using the [] syntax. Let's introspect the // type of the arguments and use it to construct the correct method. if (isGeneric && info == null && methodinfo != null) { Type[] types = Runtime.PythonArgsToTypeArray(args, true); MethodInfo mi = MatchParameters(methodinfo, types); return(Bind(inst, args, kw, mi, null)); } return(null); }
internal Binding Bind(IntPtr inst, IntPtr args, IntPtr kw, MethodBase info, MethodInfo[] methodinfo) { // loop to find match, return invoker w/ or /wo error int pynargs = Runtime.PyTuple_Size(args); object arg; var isGeneric = false; ArrayList defaultArgList; Type clrtype; Binding bindingUsingImplicitConversion = null; var methods = info == null?GetMethods() : new List <MethodInformation>(1) { new MethodInformation(info, info.GetParameters()) }; // TODO: Clean up foreach (var methodInformation in methods) { var mi = methodInformation.MethodBase; var pi = methodInformation.ParameterInfo; if (mi.IsGenericMethod) { isGeneric = true; } int clrnargs = pi.Length; int arrayStart; if (CheckMethodArgumentsMatch(clrnargs, pynargs, pi, out arrayStart, out defaultArgList)) { var outs = 0; var margs = new object[clrnargs]; var usedImplicitConversion = false; for (var n = 0; n < clrnargs; n++) { IntPtr op; if (n < pynargs) { if (arrayStart == n) { // map remaining Python arguments to a tuple since // the managed function accepts it - hopefully :] op = Runtime.PyTuple_GetSlice(args, arrayStart, pynargs); } else { op = Runtime.PyTuple_GetItem(args, n); } // this logic below handles cases when multiple overloading methods // are ambiguous, hence comparison between Python and CLR types // is necessary clrtype = null; IntPtr pyoptype; if (methods.Count > 1) { pyoptype = IntPtr.Zero; pyoptype = Runtime.PyObject_Type(op); Exceptions.Clear(); if (pyoptype != IntPtr.Zero) { clrtype = Converter.GetTypeByAlias(pyoptype); } Runtime.XDecref(pyoptype); } if (clrtype != null) { var typematch = false; if ((pi[n].ParameterType != typeof(object)) && (pi[n].ParameterType != clrtype)) { IntPtr pytype = Converter.GetPythonTypeByAlias(pi[n].ParameterType); pyoptype = Runtime.PyObject_Type(op); Exceptions.Clear(); if (pyoptype != IntPtr.Zero) { if (pytype != pyoptype) { typematch = false; } else { typematch = true; clrtype = pi[n].ParameterType; } } if (!typematch) { // this takes care of nullables var underlyingType = Nullable.GetUnderlyingType(pi[n].ParameterType); if (underlyingType == null) { underlyingType = pi[n].ParameterType; } // this takes care of enum values TypeCode argtypecode = Type.GetTypeCode(underlyingType); TypeCode paramtypecode = Type.GetTypeCode(clrtype); if (argtypecode == paramtypecode) { typematch = true; clrtype = pi[n].ParameterType; } // accepts non-decimal numbers in decimal parameters if (underlyingType == typeof(decimal)) { clrtype = pi[n].ParameterType; typematch = Converter.ToManaged(op, clrtype, out arg, false); } // this takes care of implicit conversions var opImplicit = pi[n].ParameterType.GetMethod("op_Implicit", new[] { clrtype }); if (opImplicit != null) { usedImplicitConversion = typematch = opImplicit.ReturnType == pi[n].ParameterType; clrtype = pi[n].ParameterType; } } Runtime.XDecref(pyoptype); if (!typematch) { margs = null; break; } } else { typematch = true; clrtype = pi[n].ParameterType; } } else { clrtype = pi[n].ParameterType; } if (pi[n].IsOut || clrtype.IsByRef) { outs++; } if (!Converter.ToManaged(op, clrtype, out arg, false)) { Exceptions.Clear(); margs = null; break; } if (arrayStart == n) { // GetSlice() creates a new reference but GetItem() // returns only a borrow reference. Runtime.XDecref(op); } margs[n] = arg; } else { if (defaultArgList != null) { margs[n] = defaultArgList[n - pynargs]; } } } if (margs == null) { continue; } object target = null; if (!mi.IsStatic && inst != IntPtr.Zero) { //CLRObject co = (CLRObject)ManagedType.GetManagedObject(inst); // InvalidCastException: Unable to cast object of type // 'Python.Runtime.ClassObject' to type 'Python.Runtime.CLRObject' var co = ManagedType.GetManagedObject(inst) as CLRObject; // Sanity check: this ensures a graceful exit if someone does // something intentionally wrong like call a non-static method // on the class rather than on an instance of the class. // XXX maybe better to do this before all the other rigmarole. if (co == null) { return(null); } target = co.inst; } var binding = new Binding(mi, target, margs, outs); if (usedImplicitConversion) { // lets just keep the first binding using implicit conversion // this is to respect method order/precedence if (bindingUsingImplicitConversion == null) { // in this case we will not return the binding yet in case there is a match // which does not use implicit conversions, which will return directly bindingUsingImplicitConversion = binding; } } else { return(binding); } } } // if we generated a binding using implicit conversion return it if (bindingUsingImplicitConversion != null) { return(bindingUsingImplicitConversion); } // We weren't able to find a matching method but at least one // is a generic method and info is null. That happens when a generic // method was not called using the [] syntax. Let's introspect the // type of the arguments and use it to construct the correct method. if (isGeneric && info == null && methodinfo != null) { Type[] types = Runtime.PythonArgsToTypeArray(args, true); MethodInfo mi = MatchParameters(methodinfo, types); return(Bind(inst, args, kw, mi, null)); } return(null); }
internal Binding Bind(IntPtr inst, IntPtr args, IntPtr kw, MethodBase info, MethodInfo[] methodinfo) { // loop to find match, return invoker w/ or /wo error MethodBase[] _methods = null; int pynargs = Runtime.PyTuple_Size(args); object arg; var isGeneric = false; ArrayList defaultArgList = null; if (info != null) { _methods = new MethodBase[1]; _methods.SetValue(info, 0); } else { _methods = GetMethods(); } Type clrtype; // TODO: Clean up foreach (MethodBase mi in _methods) { if (mi.IsGenericMethod) { isGeneric = true; } ParameterInfo[] pi = mi.GetParameters(); int clrnargs = pi.Length; var match = false; int arrayStart = -1; var outs = 0; if (pynargs == clrnargs) { match = true; } else if (pynargs < clrnargs) { match = true; defaultArgList = new ArrayList(); for (int v = pynargs; v < clrnargs; v++) { if (pi[v].DefaultValue == DBNull.Value) { match = false; } else { defaultArgList.Add(pi[v].DefaultValue); } } } else if (pynargs > clrnargs && clrnargs > 0 && Attribute.IsDefined(pi[clrnargs - 1], typeof(ParamArrayAttribute))) { // This is a `foo(params object[] bar)` style method match = true; arrayStart = clrnargs - 1; } if (match) { var margs = new object[clrnargs]; for (var n = 0; n < clrnargs; n++) { IntPtr op; if (n < pynargs) { if (arrayStart == n) { // map remaining Python arguments to a tuple since // the managed function accepts it - hopefully :] op = Runtime.PyTuple_GetSlice(args, arrayStart, pynargs); } else { op = Runtime.PyTuple_GetItem(args, n); } // this logic below handles cases when multiple overloading methods // are ambiguous, hence comparison between Python and CLR types // is necessary clrtype = null; IntPtr pyoptype; if (_methods.Length > 1) { pyoptype = IntPtr.Zero; pyoptype = Runtime.PyObject_Type(op); Exceptions.Clear(); if (pyoptype != IntPtr.Zero) { clrtype = Converter.GetTypeByAlias(pyoptype); } Runtime.XDecref(pyoptype); } if (clrtype != null) { var typematch = false; if ((pi[n].ParameterType != typeof(object)) && (pi[n].ParameterType != clrtype)) { IntPtr pytype = Converter.GetPythonTypeByAlias(pi[n].ParameterType); pyoptype = Runtime.PyObject_Type(op); Exceptions.Clear(); if (pyoptype != IntPtr.Zero) { if (pytype != pyoptype) { typematch = false; } else { typematch = true; clrtype = pi[n].ParameterType; } } if (!typematch) { // this takes care of nullables var underlyingType = Nullable.GetUnderlyingType(pi[n].ParameterType); if (underlyingType == null) { underlyingType = pi[n].ParameterType; } // this takes care of enum values TypeCode argtypecode = Type.GetTypeCode(underlyingType); TypeCode paramtypecode = Type.GetTypeCode(clrtype); if (argtypecode == paramtypecode) { typematch = true; clrtype = pi[n].ParameterType; } // this takes care of implicit conversions var opImplicit = pi[n].ParameterType.GetMethod("op_Implicit", new[] { clrtype }); if (opImplicit != null) { typematch = opImplicit.ReturnType == pi[n].ParameterType; clrtype = pi[n].ParameterType; } } Runtime.XDecref(pyoptype); if (!typematch) { margs = null; break; } } else { typematch = true; clrtype = pi[n].ParameterType; } } else { clrtype = pi[n].ParameterType; } if (pi[n].IsOut || clrtype.IsByRef) { outs++; } if (!Converter.ToManaged(op, clrtype, out arg, false)) { Exceptions.Clear(); margs = null; break; } if (arrayStart == n) { // GetSlice() creates a new reference but GetItem() // returns only a borrow reference. Runtime.XDecref(op); } margs[n] = arg; } else { if (defaultArgList != null) { margs[n] = defaultArgList[n - pynargs]; } } } if (margs == null) { continue; } object target = null; if (!mi.IsStatic && inst != IntPtr.Zero) { //CLRObject co = (CLRObject)ManagedType.GetManagedObject(inst); // InvalidCastException: Unable to cast object of type // 'Python.Runtime.ClassObject' to type 'Python.Runtime.CLRObject' var co = ManagedType.GetManagedObject(inst) as CLRObject; // Sanity check: this ensures a graceful exit if someone does // something intentionally wrong like call a non-static method // on the class rather than on an instance of the class. // XXX maybe better to do this before all the other rigmarole. if (co == null) { return(null); } target = co.inst; } return(new Binding(mi, target, margs, outs)); } } // We weren't able to find a matching method but at least one // is a generic method and info is null. That happens when a generic // method was not called using the [] syntax. Let's introspect the // type of the arguments and use it to construct the correct method. if (isGeneric && info == null && methodinfo != null) { Type[] types = Runtime.PythonArgsToTypeArray(args, true); MethodInfo mi = MatchParameters(methodinfo, types); return(Bind(inst, args, kw, mi, null)); } return(null); }
internal Binding Bind(IntPtr inst, IntPtr pythonParametersPtr, IntPtr kw, MethodBase info, MethodInfo[] methodInfoArray) { // loop to find match, return invoker w/ or /wo error MethodBase[] _methods = null; // NOTE: return the size of the args pointer (the number of parameter from the python call) int pythonParameterCount = Runtime.PyTuple_Size(pythonParametersPtr); //WHY: Why is that so widely scoped ? object pythonManagedParameterPtr; var isGeneric = false; ArrayList defaultParameterList = null; if (info != null) { // NOTE: If a MethodBase object has been provided, create an array with only it. // WHY a method base is provided some times and not other ? (ex: when call a genric with a type in []) _methods = new MethodBase[1]; _methods.SetValue(info, 0); } else { // NOTE: Create an array of MethodBase from teh called method/constructor // WHY not use the methodinfo provided? _methods = GetMethods(); } //WHY is it so widely scoped Type clrConvertedParameterType; // TODO: Clean up foreach (MethodBase methodInfo in _methods) { //WHY not just do isGeneric = mi.IsGenericMethod or use it directly ? if (methodInfo.IsGenericMethod) { isGeneric = true; } //NOTE: Get the parameter from the current MethodBase //NOTE: MethodInfo Ok ParameterInfo[] clrParameterInfoArray = methodInfo.GetParameters(); //NOTE: Get the number of clr parameters int clrParameterCount = clrParameterInfoArray.Length; var paramCountMatch = false; //REFACTOR: Use var like the other local variables var clrHasParamArray = false; var clrParamsArrayStart = -1; var byRefCount = 0; if (pythonParameterCount == clrParameterCount) { paramCountMatch = true; } else if (pythonParameterCount < clrParameterCount) { paramCountMatch = true; defaultParameterList = new ArrayList(); for (int v = pythonParameterCount; v < clrParameterCount; v++) { if (clrParameterInfoArray[v].DefaultValue == DBNull.Value) { paramCountMatch = false; } else { defaultParameterList.Add(clrParameterInfoArray[v].DefaultValue); } } } else if (pythonParameterCount > clrParameterCount && clrParameterCount > 0 && Attribute.IsDefined(clrParameterInfoArray[clrParameterCount - 1], typeof(ParamArrayAttribute))) { // This is a `foo({...}, params object[] bar)` style method paramCountMatch = true; clrHasParamArray = true; clrParamsArrayStart = clrParameterCount - 1; } if (paramCountMatch) { var methodParametersPtrArray = new object[clrParameterCount]; for (var n = 0; n < clrParameterCount; n++) { IntPtr pythonParameterPtr; if (n < pythonParameterCount) { if (clrParamsArrayStart == n) { // map remaining Python arguments to a tuple since // the managed function accepts it - hopefully :] //WHY: Hmmm it returns a lot of python paramter as one. isn't there a problem later ? pythonParameterPtr = Runtime.PyTuple_GetSlice(pythonParametersPtr, clrParamsArrayStart, pythonParameterCount); } else { pythonParameterPtr = Runtime.PyTuple_GetItem(pythonParametersPtr, n); } // this logic below handles cases when multiple overloading methods // are ambiguous, hence comparison between Python and CLR types // is necessary clrConvertedParameterType = null; IntPtr pythonParameterPtrType = IntPtr.Zero; if (_methods.Length > 1) { pythonParameterPtrType = Runtime.PyObject_Type(pythonParameterPtr); Exceptions.Clear(); if (pythonParameterPtrType != IntPtr.Zero) { clrConvertedParameterType = Converter.GetTypeByAlias(pythonParameterPtrType); } Runtime.XDecref(pythonParameterPtrType); } if (clrConvertedParameterType != null) { var parameterTypeMatch = false; if ((clrParameterInfoArray[n].ParameterType != typeof(object)) && (clrParameterInfoArray[n].ParameterType != clrConvertedParameterType)) { IntPtr pythonConvertedParameterPtrType = Converter.GetPythonTypeByAlias(clrParameterInfoArray[n].ParameterType); pythonParameterPtrType = Runtime.PyObject_Type(pythonParameterPtr); Exceptions.Clear(); if (pythonParameterPtrType != IntPtr.Zero) { if (pythonConvertedParameterPtrType != pythonParameterPtrType) { parameterTypeMatch = false; } else { parameterTypeMatch = true; clrConvertedParameterType = clrParameterInfoArray[n].ParameterType; } } if (!parameterTypeMatch) { // this takes care of enum values TypeCode clrParameterTypeCode = Type.GetTypeCode(clrParameterInfoArray[n].ParameterType); TypeCode clrConvertedParameterTypeCode = Type.GetTypeCode(clrConvertedParameterType); if (clrParameterTypeCode == clrConvertedParameterTypeCode) { parameterTypeMatch = true; clrConvertedParameterType = clrParameterInfoArray[n].ParameterType; } } Runtime.XDecref(pythonParameterPtrType); if (!parameterTypeMatch) { methodParametersPtrArray = null; break; } } else { parameterTypeMatch = true; clrConvertedParameterType = clrParameterInfoArray[n].ParameterType; } } else { clrConvertedParameterType = clrParameterInfoArray[n].ParameterType; } if (clrParameterInfoArray[n].IsOut || clrConvertedParameterType.IsByRef) { byRefCount++; } if (!Converter.ToManaged(pythonParameterPtr, clrConvertedParameterType, out pythonManagedParameterPtr, false)) { Exceptions.Clear(); methodParametersPtrArray = null; break; } if (clrParamsArrayStart == n) { // GetSlice() creates a new reference but GetItem() // returns only a borrow reference. Runtime.XDecref(pythonParameterPtr); } methodParametersPtrArray[n] = pythonParameterPtr; } else { if (defaultParameterList != null) { methodParametersPtrArray[n] = defaultParameterList[n - pythonParameterCount]; } } } if (methodParametersPtrArray == null) { continue; } object target = null; if (!methodInfo.IsStatic && inst != IntPtr.Zero) { //CLRObject co = (CLRObject)ManagedType.GetManagedObject(inst); // InvalidCastException: Unable to cast object of type // 'Python.Runtime.ClassObject' to type 'Python.Runtime.CLRObject' var co = ManagedType.GetManagedObject(inst) as CLRObject; // Sanity check: this ensures a graceful exit if someone does // something intentionally wrong like call a non-static method // on the class rather than on an instance of the class. // XXX maybe better to do this before all the other rigmarole. if (co == null) { return(null); } target = co.inst; } return(new Binding(methodInfo, target, methodParametersPtrArray, byRefCount)); } } // We weren't able to find a matching method but at least one // is a generic method and info is null. That happens when a generic // method was not called using the [] syntax. Let's introspect the // type of the arguments and use it to construct the correct method. if (isGeneric && info == null && methodInfoArray != null) { Type[] types = Runtime.PythonArgsToTypeArray(pythonParametersPtr, true); MethodInfo mi = MatchParameters(methodInfoArray, types); return(Bind(inst, pythonParametersPtr, kw, mi, null)); } return(null); }
public override bool TryConvert(ConvertBinder binder, out object result) { return(Converter.ToManaged(this.obj, binder.Type, out result, false)); }
/// <summary> /// Descriptor __set__ implementation. This method sets the value of /// a property based on the given Python value. The Python value must /// be convertible to the type of the property. /// </summary> public new static int tp_descr_set(IntPtr ds, IntPtr ob, IntPtr val) { var self = (PropertyObject)GetManagedObject(ds); MethodInfo setter = self.setter; object newval; if (val == IntPtr.Zero) { Exceptions.RaiseTypeError("cannot delete property"); return(-1); } if (setter == null) { Exceptions.RaiseTypeError("property is read-only"); return(-1); } if (!Converter.ToManaged(val, self.info.PropertyType, out newval, true)) { return(-1); } bool is_static = setter.IsStatic; if (ob == IntPtr.Zero || ob == Runtime.PyNone) { if (!is_static) { Exceptions.RaiseTypeError("instance property must be set on an instance"); return(-1); } } try { if (!is_static) { var co = GetManagedObject(ob) as CLRObject; if (co == null) { Exceptions.RaiseTypeError("invalid target"); return(-1); } self.info.SetValue(co.inst, newval, null); } else { self.info.SetValue(null, newval, null); } return(0); } catch (Exception e) { if (e.InnerException != null) { e = e.InnerException; } Exceptions.SetError(e); return(-1); } }
/// <summary> /// Implements __setitem__ for array types. /// </summary> public static int mp_ass_subscript(IntPtr ob, IntPtr idx, IntPtr v) { var obj = (CLRObject)GetManagedObject(ob); var items = obj.inst as Array; Type itemType = obj.inst.GetType().GetElementType(); int rank = items.Rank; int index; object value; if (items.IsReadOnly) { Exceptions.RaiseTypeError("array is read-only"); return(-1); } if (!Converter.ToManaged(v, itemType, out value, true)) { return(-1); } if (rank == 1) { index = Runtime.Interop.PyInt_AsLong(idx); if (Exceptions.ErrorOccurred()) { Exceptions.RaiseTypeError("invalid index value"); return(-1); } if (index < 0) { index = items.Length + index; } try { items.SetValue(value, index); } catch (IndexOutOfRangeException) { Exceptions.SetError(Exceptions.IndexError, "array index out of range"); return(-1); } return(0); } if (!Runtime.PyTuple_Check(idx)) { Exceptions.RaiseTypeError("invalid index value"); return(-1); } int count = Runtime.Interop.PyTuple_Size(idx); var args = new int[count]; for (var i = 0; i < count; i++) { IntPtr op = Runtime.Interop.PyTuple_GetItem(idx, i); index = Runtime.Interop.PyInt_AsLong(op); if (Exceptions.ErrorOccurred()) { Exceptions.RaiseTypeError("invalid index value"); return(-1); } if (index < 0) { index = items.GetLength(i) + index; } args.SetValue(index, i); } try { items.SetValue(value, args); } catch (IndexOutOfRangeException) { Exceptions.SetError(Exceptions.IndexError, "array index out of range"); return(-1); } return(0); }
/// <summary> /// Descriptor __set__ implementation. This method sets the value of /// a property based on the given Python value. The Python value must /// be convertible to the type of the property. /// </summary> public new static int tp_descr_set(IntPtr ds, IntPtr ob, IntPtr val) { var self = (PropertyObject)GetManagedObject(ds); MethodInfo setter = self.setter; object newval; if (val == IntPtr.Zero) { Exceptions.RaiseTypeError("cannot delete property"); return(-1); } if (setter == null) { Exceptions.RaiseTypeError("property is read-only"); return(-1); } if (!Converter.ToManaged(val, self.info.PropertyType, out newval, true)) { return(-1); } bool is_static = setter.IsStatic; if (ob == IntPtr.Zero || ob == Runtime.PyNone) { if (!is_static) { Exceptions.RaiseTypeError("instance property must be set on an instance"); return(-1); } } try { if (!is_static) { var co = GetManagedObject(ob) as CLRObject; if (co == null) { Exceptions.RaiseTypeError("invalid target"); return(-1); } if (self.setterCache == null && !self.setterCacheFailed) { // if the setter is not public 'GetSetMethod' will not find it // but calling 'SetValue' will work, so for backwards compatibility // we will use it instead self.setterCache = BuildSetter(self.info); if (self.setterCache == null) { self.setterCacheFailed = true; } } if (self.setterCacheFailed) { self.info.SetValue(co.inst, newval, null); } else { self.setterCache(co.inst, newval); } } else { self.info.SetValue(null, newval, null); } return(0); } catch (Exception e) { if (e.InnerException != null) { e = e.InnerException; } Exceptions.SetError(e); return(-1); } }