/// <summary> /// DelegateObject __new__ implementation. The result of this is a new /// PyObject whose type is DelegateObject and whose ob_data is a handle /// to an actual delegate instance. The method wrapped by the actual /// delegate instance belongs to an object generated to relay the call /// to the Python callable passed in. /// </summary> public static IntPtr tp_new(IntPtr tp, IntPtr args, IntPtr kw) { var self = (DelegateObject)GetManagedObject(tp); if (!self.type.Valid) { return(Exceptions.RaiseTypeError(self.type.DeletedMessage)); } Type type = self.type.Value; if (Runtime.PyTuple_Size(args) != 1) { return(Exceptions.RaiseTypeError("class takes exactly one argument")); } IntPtr method = Runtime.PyTuple_GetItem(args, 0); if (Runtime.PyCallable_Check(method) != 1) { return(Exceptions.RaiseTypeError("argument must be callable")); } Delegate d = PythonEngine.DelegateManager.GetDelegate(type, method); return(CLRObject.GetInstHandle(d, self.pyHandle)); }
internal bool NeedsDefaultArgs(IntPtr args) { var methods = SetterBinder.GetMethods(); if (methods.Count == 0) { return(false); } int pynargs = Runtime.PyTuple_Size(args); var pi = methods[0].ParameterInfo; // need to subtract one for the value int clrnargs = pi.Length - 1; if (pynargs == clrnargs || pynargs > clrnargs) { return(false); } for (int v = pynargs; v < clrnargs; v++) { if (pi[v].DefaultValue == DBNull.Value) { return(false); } } return(true); }
/// <summary> /// This will return default arguments a new instance of a tuple. The size /// of the tuple will indicate the number of default arguments. /// </summary> /// <param name="args">This is pointing to the tuple args passed in</param> /// <returns>a new instance of the tuple containing the default args</returns> internal IntPtr GetDefaultArgs(IntPtr args) { // if we don't need default args return empty tuple if (!NeedsDefaultArgs(args)) { return(Runtime.PyTuple_New(0)); } var pynargs = Runtime.PyTuple_Size(args); // Get the default arg tuple MethodBase[] methods = SetterBinder.GetMethods(); MethodBase mi = methods[0]; ParameterInfo[] pi = mi.GetParameters(); int clrnargs = pi.Length - 1; IntPtr defaultArgs = Runtime.PyTuple_New(clrnargs - pynargs); for (var i = 0; i < clrnargs - pynargs; i++) { if (pi[i + pynargs].DefaultValue == DBNull.Value) { continue; } IntPtr arg = Converter.ToPython(pi[i + pynargs].DefaultValue, pi[i + pynargs].ParameterType); Runtime.PyTuple_SetItem(defaultArgs, i, arg); } return(defaultArgs); }
//==================================================================== // Implements __setitem__ for reflected classes and value types. //==================================================================== public static int mp_ass_subscript(IntPtr ob, IntPtr idx, IntPtr v) { //ManagedType self = GetManagedObject(ob); IntPtr tp = Runtime.PyObject_TYPE(ob); ClassBase cls = (ClassBase)GetManagedObject(tp); if (cls.indexer == null || !cls.indexer.CanSet) { Exceptions.SetError(Exceptions.TypeError, "object doesn't support item assignment" ); return(-1); } // Arg may be a tuple in the case of an indexer with multiple // parameters. If so, use it directly, else make a new tuple // with the index arg (method binders expect arg tuples). IntPtr args = idx; bool free = false; if (!Runtime.PyTuple_Check(idx)) { args = Runtime.PyTuple_New(1); Runtime.Incref(idx); Runtime.PyTuple_SetItem(args, 0, idx); free = true; } int i = Runtime.PyTuple_Size(args); IntPtr real = Runtime.PyTuple_New(i + 1); for (int n = 0; n < i; n++) { IntPtr item = Runtime.PyTuple_GetItem(args, n); Runtime.Incref(item); Runtime.PyTuple_SetItem(real, n, item); } Runtime.Incref(v); Runtime.PyTuple_SetItem(real, i, v); try { cls.indexer.SetItem(ob, real); } finally { Runtime.Decref(real); if (free) { Runtime.Decref(args); } } if (Exceptions.ErrorOccurred()) { return(-1); } return(0); }
public static IntPtr tp_call(IntPtr ob, IntPtr args, IntPtr kw) { MethodBinding self = (MethodBinding)GetManagedObject(ob); // This supports calling a method 'unbound', passing the instance // as the first argument. Note that this is not supported if any // of the overloads are static since we can't know if the intent // was to call the static method or the unbound instance method. if ((self.target == IntPtr.Zero) && (!self.m.IsStatic())) { if (Runtime.PyTuple_Size(args) < 1) { Exceptions.SetError(Exceptions.TypeError, "not enough arguments" ); return(IntPtr.Zero); } int len = Runtime.PyTuple_Size(args); IntPtr uargs = Runtime.PyTuple_GetSlice(args, 1, len); IntPtr inst = Runtime.PyTuple_GetItem(args, 0); Runtime.Incref(inst); IntPtr r = self.m.Invoke(inst, uargs, kw, self.info); Runtime.Decref(inst); Runtime.Decref(uargs); return(r); } return(self.m.Invoke(self.target, args, kw, self.info)); }
/// <summary> /// DelegateObject __new__ implementation. The result of this is a new /// PyObject whose type is DelegateObject and whose ob_data is a handle /// to an actual delegate instance. The method wrapped by the actual /// delegate instance belongs to an object generated to relay the call /// to the Python callable passed in. /// </summary> public static NewReference tp_new(BorrowedReference tp, BorrowedReference args, BorrowedReference kw) { var self = (DelegateObject)GetManagedObject(tp) !; if (!self.type.Valid) { return(Exceptions.RaiseTypeError(self.type.DeletedMessage)); } Type type = self.type.Value; if (Runtime.PyTuple_Size(args) != 1) { return(Exceptions.RaiseTypeError("class takes exactly one argument")); } BorrowedReference method = Runtime.PyTuple_GetItem(args, 0); if (Runtime.PyCallable_Check(method) != 1) { return(Exceptions.RaiseTypeError("argument must be callable")); } Delegate d = PythonEngine.DelegateManager.GetDelegate(type, new PyObject(method)); return(CLRObject.GetReference(d, ClassManager.GetClass(type))); }
/// <summary> /// This will return default arguments a new instance of a tuple. The size /// of the tuple will indicate the number of default arguments. /// </summary> /// <param name="args">This is pointing to the tuple args passed in</param> /// <returns>a new instance of the tuple containing the default args</returns> internal NewReference GetDefaultArgs(BorrowedReference args) { // if we don't need default args return empty tuple if (!NeedsDefaultArgs(args)) { return(Runtime.PyTuple_New(0)); } var pynargs = Runtime.PyTuple_Size(args); // Get the default arg tuple var methods = SetterBinder.GetMethods(); MethodBase mi = methods[0].MethodBase; ParameterInfo[] pi = mi.GetParameters(); int clrnargs = pi.Length - 1; var defaultArgs = Runtime.PyTuple_New(clrnargs - pynargs); for (var i = 0; i < clrnargs - pynargs; i++) { if (pi[i + pynargs].DefaultValue == DBNull.Value) { continue; } using var arg = Converter.ToPython(pi[i + pynargs].DefaultValue, pi[i + pynargs].ParameterType); Runtime.PyTuple_SetItem(defaultArgs.Borrow(), i, arg.Steal()); } return(defaultArgs); }
/// <summary> /// Implements __new__ for reflected classes and value types. /// </summary> static NewReference tp_new_impl(BorrowedReference tp, BorrowedReference args, BorrowedReference kw) { // 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 (GetManagedObject(tp) is not ClassObject self) { return(Exceptions.RaiseTypeError("invalid object")); } if (!self.type.Valid) { return(Exceptions.RaiseTypeError(self.type.DeletedMessage)); } Type type = self.type.Value; // 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(default);
internal bool NeedsDefaultArgs(IntPtr args) { var pynargs = Runtime.PyTuple_Size(args); MethodBase[] methods = SetterBinder.GetMethods(); if (methods.Length == 0) { return(false); } MethodBase mi = methods[0]; ParameterInfo[] pi = mi.GetParameters(); // need to subtract one for the value int clrnargs = pi.Length - 1; if (pynargs == clrnargs || pynargs > clrnargs) { return(false); } for (var v = pynargs; v < clrnargs; v++) { if (pi[v].DefaultValue == DBNull.Value) { return(false); } } return(true); }
//==================================================================== // Metatype __new__ implementation. This is called to create a new // class / type when a reflected class is subclassed. //==================================================================== public static IntPtr tp_new(IntPtr tp, IntPtr args, IntPtr kw) { int len = Runtime.PyTuple_Size(args); if (len < 3) { return(Exceptions.RaiseTypeError("invalid argument list")); } IntPtr name = Runtime.PyTuple_GetItem(args, 0); IntPtr bases = Runtime.PyTuple_GetItem(args, 1); IntPtr dict = Runtime.PyTuple_GetItem(args, 2); // We do not support multiple inheritance, so the bases argument // should be a 1-item tuple containing the type we are subtyping. // That type must itself have a managed implementation. We check // that by making sure its metatype is the CLR metatype. if (Runtime.PyTuple_Size(bases) != 1) { return(Exceptions.RaiseTypeError( "cannot use multiple inheritance with managed classes" )); } IntPtr base_type = Runtime.PyTuple_GetItem(bases, 0); IntPtr mt = Runtime.PyObject_TYPE(base_type); if (!((mt == PyCLRMetaType) || (mt == Runtime.PyTypeType))) { return(Exceptions.RaiseTypeError("invalid metatype")); } // Ensure that the reflected type is appropriate for subclassing, // disallowing subclassing of delegates, enums and array types. ClassBase cb = GetManagedObject(base_type) as ClassBase; if (cb != null) { if (!cb.CanSubclass()) { return(Exceptions.RaiseTypeError( "delegates, enums and array types cannot be subclassed" )); } } IntPtr slots = Runtime.PyDict_GetItemString(dict, "__slots__"); if (slots != IntPtr.Zero) { return(Exceptions.RaiseTypeError( "subclasses of managed classes do not support __slots__" )); } return(TypeManager.CreateSubType(name, base_type, dict)); }
/// <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()); }
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);
//==================================================================== // MethodBinding __call__ implementation. //==================================================================== public static IntPtr tp_call(IntPtr ob, IntPtr args, IntPtr kw) { MethodBinding self = (MethodBinding)GetManagedObject(ob); // This works around a situation where the wrong generic method is picked, // for example this method in the tests: string Overloaded<T>(int arg1, int arg2, string arg3) if (self.info != null) { if (self.info.IsGenericMethod) { int len = Runtime.PyTuple_Size(args); Type[] sigTp = Runtime.PythonArgsToTypeArray(args, true); if (sigTp != null) { Type[] genericTp = self.info.GetGenericArguments(); MethodInfo betterMatch = MethodBinder.MatchSignatureAndParameters(self.m.info, genericTp, sigTp); if (betterMatch != null) { self.info = betterMatch; } } } } // This supports calling a method 'unbound', passing the instance // as the first argument. Note that this is not supported if any // of the overloads are static since we can't know if the intent // was to call the static method or the unbound instance method. if ((self.target == IntPtr.Zero) && (!self.m.IsStatic())) { int len = Runtime.PyTuple_Size(args); if (len < 1) { Exceptions.SetError(Exceptions.TypeError, "not enough arguments"); return(IntPtr.Zero); } IntPtr uargs = Runtime.PyTuple_GetSlice(args, 1, len); IntPtr inst = Runtime.PyTuple_GetItem(args, 0); Runtime.Incref(inst); IntPtr r = self.m.Invoke(inst, uargs, kw, self.info); Runtime.Decref(inst); Runtime.Decref(uargs); return(r); } return(self.m.Invoke(self.target, args, kw, self.info)); }
public static IntPtr tp_new(IntPtr tp, IntPtr args, IntPtr kw) { var self = GetManagedObject(tp) as ArrayObject; if (Runtime.PyTuple_Size(args) != 1) { return(Exceptions.RaiseTypeError("array expects 1 argument")); } IntPtr op = Runtime.PyTuple_GetItem(args, 0); object result; if (!Converter.ToManaged(op, self.type, out result, true)) { return(IntPtr.Zero); } return(CLRObject.GetInstHandle(result, tp)); }
/// <summary> /// Implements __new__ for reflected interface types. /// </summary> public static IntPtr tp_new(IntPtr tp, IntPtr args, IntPtr kw) { var self = (InterfaceObject)GetManagedObject(tp); if (!self.type.Valid) { return(Exceptions.RaiseTypeError(self.type.DeletedMessage)); } var nargs = Runtime.PyTuple_Size(args); Type type = self.type.Value; object obj; if (nargs == 1) { IntPtr inst = Runtime.PyTuple_GetItem(args, 0); var co = GetManagedObject(inst) as CLRObject; if (co == null || !type.IsInstanceOfType(co.inst)) { Exceptions.SetError(Exceptions.TypeError, $"object does not implement {type.Name}"); return(IntPtr.Zero); } obj = co.inst; } else if (nargs == 0 && self.ctor != null) { obj = self.ctor.Invoke(null); if (obj == null || !type.IsInstanceOfType(obj)) { Exceptions.SetError(Exceptions.TypeError, "CoClass default constructor failed"); return(IntPtr.Zero); } } else { Exceptions.SetError(Exceptions.TypeError, "interface takes exactly one argument"); return(IntPtr.Zero); } return(self.WrapObject(obj)); }
//==================================================================== // Implements __new__ for reflected interface types. //==================================================================== public static IntPtr tp_new(IntPtr tp, IntPtr args, IntPtr kw) { InterfaceObject self = (InterfaceObject)GetManagedObject(tp); int nargs = Runtime.PyTuple_Size(args); Type type = self.type; Object obj; if (nargs == 1) { IntPtr inst = Runtime.PyTuple_GetItem(args, 0); CLRObject co = GetManagedObject(inst) as CLRObject; if ((co == null) || (!type.IsInstanceOfType(co.inst))) { string msg = "object does not implement " + type.Name; Exceptions.SetError(Exceptions.TypeError, msg); return(IntPtr.Zero); } obj = co.inst; } else if ((nargs == 0) && (self.ctor != null)) { obj = self.ctor.Invoke(null); if (obj == null || !type.IsInstanceOfType(obj)) { Exceptions.SetError(Exceptions.TypeError, "CoClass default constructor failed" ); return(IntPtr.Zero); } } else { Exceptions.SetError(Exceptions.TypeError, "interface takes exactly one argument" ); return(IntPtr.Zero); } return(CLRObject.GetInstHandle(obj, self.pyHandle)); }
public static IntPtr tp_new(IntPtr tp, IntPtr args, IntPtr kw) { DelegateObject self = (DelegateObject)GetManagedObject(tp); if (Runtime.PyTuple_Size(args) != 1) { string message = "class takes exactly one argument"; return(Exceptions.RaiseTypeError(message)); } IntPtr method = Runtime.PyTuple_GetItem(args, 0); if (Runtime.PyCallable_Check(method) != 1) { return(Exceptions.RaiseTypeError("argument must be callable")); } Delegate d = DelegateManager.GetDelegate(self.type, method); return(CLRObject.GetInstHandle(d, self.pyHandle)); }
/// <summary> /// Implements __new__ for reflected interface types. /// </summary> public static NewReference tp_new(BorrowedReference tp, BorrowedReference args, BorrowedReference kw) { var self = (InterfaceObject)GetManagedObject(tp) !; if (!self.type.Valid) { return(Exceptions.RaiseTypeError(self.type.DeletedMessage)); } var nargs = Runtime.PyTuple_Size(args); Type type = self.type.Value; object obj; if (nargs == 1) { BorrowedReference inst = Runtime.PyTuple_GetItem(args, 0); var co = GetManagedObject(inst) as CLRObject; if (co == null || !type.IsInstanceOfType(co.inst)) { Exceptions.SetError(Exceptions.TypeError, $"object does not implement {type.Name}"); return(default);
internal static IntPtr GenerateExceptionClass(IntPtr real) { if (real == ns_exc) { return(os_exc); } IntPtr nbases = Runtime.PyObject_GetAttrString(real, "__bases__"); if (Runtime.PyTuple_Size(nbases) != 1) { throw new SystemException("Invalid __bases__"); } IntPtr nsbase = Runtime.PyTuple_GetItem(nbases, 0); Runtime.Decref(nbases); IntPtr osbase = GetExceptionClassWrapper(nsbase); IntPtr baselist = Runtime.PyTuple_New(1); Runtime.Incref(osbase); Runtime.PyTuple_SetItem(baselist, 0, osbase); IntPtr name = Runtime.PyObject_GetAttrString(real, "__name__"); IntPtr dict = Runtime.PyDict_New(); IntPtr mod = Runtime.PyObject_GetAttrString(real, "__module__"); Runtime.PyDict_SetItemString(dict, "__module__", mod); Runtime.Decref(mod); IntPtr subc = Runtime.PyClass_New(baselist, dict, name); Runtime.Decref(baselist); Runtime.Decref(dict); Runtime.Decref(name); Runtime.PyObject_SetAttrString(subc, "_class", real); return(subc); }
/// <summary> /// Implements __new__ for reflected generic types. /// </summary> public static NewReference tp_new(BorrowedReference tp, BorrowedReference args, BorrowedReference kw) { var self = (GenericType)GetManagedObject(tp) !; if (!self.type.Valid) { return(Exceptions.RaiseTypeError(self.type.DeletedMessage)); } var type = self.type.Value; if (type.IsInterface && !type.IsConstructedGenericType) { var nargs = Runtime.PyTuple_Size(args); if (nargs == 1) { var instance = Runtime.PyTuple_GetItem(args, 0); return(AsGenericInterface(instance, type)); } } Exceptions.SetError(Exceptions.TypeError, "cannot instantiate an open generic type"); return(default);
protected static void AppendArgumentTypes(StringBuilder to, IntPtr args) { long argCount = Runtime.PyTuple_Size(args); to.Append("("); for (long argIndex = 0; argIndex < argCount; argIndex++) { var arg = Runtime.PyTuple_GetItem(args, argIndex); if (arg != IntPtr.Zero) { var type = Runtime.PyObject_Type(arg); if (type != IntPtr.Zero) { try { var description = Runtime.PyObject_Str(type); if (description != IntPtr.Zero) { to.Append(Runtime.GetManagedString(description)); Runtime.XDecref(description); } } finally { Runtime.XDecref(type); } } } if (argIndex + 1 < argCount) { to.Append(", "); } } to.Append(')'); }
/// <summary> /// The actual import hook that ties Python to the managed world. /// </summary> public static IntPtr __import__(IntPtr self, IntPtr argsRaw, IntPtr kw) { var args = new BorrowedReference(argsRaw); // Replacement for the builtin __import__. The original import // hook is saved as this.py_import. This version handles CLR // import and defers to the normal builtin for everything else. var num_args = Runtime.PyTuple_Size(args); if (num_args < 1) { return(Exceptions.RaiseTypeError("__import__() takes at least 1 argument (0 given)")); } BorrowedReference py_mod_name = Runtime.PyTuple_GetItem(args, 0); if (py_mod_name.IsNull || !Runtime.IsStringType(py_mod_name)) { return(Exceptions.RaiseTypeError("string expected")); } // Check whether the import is of the form 'from x import y'. // This determines whether we return the head or tail module. BorrowedReference fromList = default; var fromlist = false; if (num_args >= 4) { fromList = Runtime.PyTuple_GetItem(args, 3); if (fromList != null && Runtime.PyObject_IsTrue(fromList) == 1) { fromlist = true; } } string mod_name = Runtime.GetManagedString(py_mod_name); // Check these BEFORE the built-in import runs; may as well // do the Incref()ed return here, since we've already found // the module. if (mod_name == "clr") { NewReference clr_module = GetCLRModule(fromList); if (!clr_module.IsNull()) { BorrowedReference sys_modules = Runtime.PyImport_GetModuleDict(); if (!sys_modules.IsNull) { Runtime.PyDict_SetItemString(sys_modules, "clr", clr_module); } } return(clr_module.DangerousMoveToPointerOrNull()); } string realname = mod_name; // 2010-08-15: Always seemed smart to let python try first... // This shaves off a few tenths of a second on test_module.py // and works around a quirk where 'sys' is found by the // LoadImplicit() deprecation logic. // Turns out that the AssemblyManager.ResolveHandler() checks to see if any // Assembly's FullName.ToLower().StartsWith(name.ToLower()), which makes very // little sense to me. IntPtr res = Runtime.PyObject_Call(py_import, args.DangerousGetAddress(), kw); if (res != IntPtr.Zero) { // There was no error. if (fromlist && IsLoadAll(fromList)) { var mod = ManagedType.GetManagedObject(res) as ModuleObject; mod?.LoadNames(); } return(res); } // There was an error if (!Exceptions.ExceptionMatches(Exceptions.ImportError)) { // and it was NOT an ImportError; bail out here. return(IntPtr.Zero); } if (mod_name == string.Empty) { // Most likely a missing relative import. // For example site-packages\bs4\builder\__init__.py uses it to check if a package exists: // from . import _html5lib // We don't support them anyway return(IntPtr.Zero); } // Save the exception var originalException = new PythonException(); // Otherwise, just clear the it. Exceptions.Clear(); string[] names = realname.Split('.'); // See if sys.modules for this interpreter already has the // requested module. If so, just return the existing module. BorrowedReference modules = Runtime.PyImport_GetModuleDict(); BorrowedReference module = Runtime.PyDict_GetItem(modules, py_mod_name); if (module != null) { if (fromlist) { if (IsLoadAll(fromList)) { var mod = ManagedType.GetManagedObject(module) as ModuleObject; mod?.LoadNames(); } return(new NewReference(module).DangerousMoveToPointer()); } module = Runtime.PyDict_GetItemString(modules, names[0]); return(new NewReference(module, canBeNull: true).DangerousMoveToPointer()); } Exceptions.Clear(); // Traverse the qualified module name to get the named module // and place references in sys.modules as we go. Note that if // we are running in interactive mode we pre-load the names in // each module, which is often useful for introspection. If we // are not interactive, we stick to just-in-time creation of // objects at lookup time, which is much more efficient. // NEW: The clr got a new module variable preload. You can // enable preloading in a non-interactive python processing by // setting clr.preload = True ModuleObject head = mod_name == realname ? null : root; ModuleObject tail = root; root.InitializePreload(); foreach (string name in names) { ManagedType mt = tail.GetAttribute(name, true); if (!(mt is ModuleObject)) { originalException.Restore(); return(IntPtr.Zero); } if (head == null) { head = (ModuleObject)mt; } tail = (ModuleObject)mt; if (CLRModule.preload) { tail.LoadNames(); } // Add the module to sys.modules Runtime.PyDict_SetItemString(modules, tail.moduleName, tail.ObjectReference); } { var mod = fromlist ? tail : head; if (fromlist && IsLoadAll(fromList)) { mod.LoadNames(); } Runtime.XIncref(mod.pyHandle); return(mod.pyHandle); } }
//=================================================================== // The actual import hook that ties Python to the managed world. //=================================================================== public static IntPtr __import__(IntPtr self, IntPtr args, IntPtr kw) { // Replacement for the builtin __import__. The original import // hook is saved as this.py_import. This version handles CLR // import and defers to the normal builtin for everything else. int num_args = Runtime.PyTuple_Size(args); if (num_args < 1) { return(Exceptions.RaiseTypeError( "__import__() takes at least 1 argument (0 given)" )); } // borrowed reference IntPtr py_mod_name = Runtime.PyTuple_GetItem(args, 0); if ((py_mod_name == IntPtr.Zero) || (!Runtime.IsStringType(py_mod_name))) { return(Exceptions.RaiseTypeError("string expected")); } // Check whether the import is of the form 'from x import y'. // This determines whether we return the head or tail module. IntPtr fromList = IntPtr.Zero; bool fromlist = false; if (num_args >= 4) { fromList = Runtime.PyTuple_GetItem(args, 3); if ((fromList != IntPtr.Zero) && (Runtime.PyObject_IsTrue(fromList) == 1)) { fromlist = true; } } string mod_name = Runtime.GetManagedString(py_mod_name); // Check these BEFORE the built-in import runs; may as well // do the Incref()ed return here, since we've already found // the module. if (mod_name == "clr") { root.InitializePreload(); Runtime.Incref(root.pyHandle); return(root.pyHandle); } if (mod_name == "CLR") { Exceptions.deprecation("The CLR module is deprecated. " + "Please use 'clr'."); root.InitializePreload(); Runtime.Incref(root.pyHandle); return(root.pyHandle); } string realname = mod_name; if (mod_name.StartsWith("CLR.")) { realname = mod_name.Substring(4); string msg = String.Format("Importing from the CLR.* namespace " + "is deprecated. Please import '{0}' directly.", realname); Exceptions.deprecation(msg); } else { // 2010-08-15: Always seemed smart to let python try first... // This shaves off a few tenths of a second on test_module.py // and works around a quirk where 'sys' is found by the // LoadImplicit() deprecation logic. // Turns out that the AssemblyManager.ResolveHandler() checks to see if any // Assembly's FullName.ToLower().StartsWith(name.ToLower()), which makes very // little sense to me. IntPtr res = Runtime.PyObject_Call(py_import, args, kw); if (res != IntPtr.Zero) { // There was no error. return(res); } // There was an error if (!Exceptions.ExceptionMatches(Exceptions.ImportError)) { // and it was NOT an ImportError; bail out here. return(IntPtr.Zero); } // Otherwise, just clear the it. Exceptions.Clear(); } string[] names = realname.Split('.'); // Now we need to decide if the name refers to a CLR module, // and may have to do an implicit load (for b/w compatibility) // using the AssemblyManager. The assembly manager tries // really hard not to use Python objects or APIs, because // parts of it can run recursively and on strange threads. // // It does need an opportunity from time to time to check to // see if sys.path has changed, in a context that is safe. Here // we know we have the GIL, so we'll let it update if needed. AssemblyManager.UpdatePath(); if (!AssemblyManager.IsValidNamespace(realname)) { bool fromFile = false; if (AssemblyManager.LoadImplicit(realname, out fromFile)) { if (true == fromFile) { string deprWarning = String.Format("\nThe module was found, but not in a referenced namespace.\n" + "Implicit loading is deprecated. Please use clr.AddReference(\"{0}\").", realname); Exceptions.deprecation(deprWarning); } } else { // May be called when a module being imported imports a module. // In particular, I've seen decimal import copy import org.python.core return(Runtime.PyObject_Call(py_import, args, kw)); } } // See if sys.modules for this interpreter already has the // requested module. If so, just return the exising module. IntPtr modules = Runtime.PyImport_GetModuleDict(); IntPtr module = Runtime.PyDict_GetItem(modules, py_mod_name); if (module != IntPtr.Zero) { if (fromlist) { Runtime.Incref(module); return(module); } module = Runtime.PyDict_GetItemString(modules, names[0]); Runtime.Incref(module); return(module); } Exceptions.Clear(); // Traverse the qualified module name to get the named module // and place references in sys.modules as we go. Note that if // we are running in interactive mode we pre-load the names in // each module, which is often useful for introspection. If we // are not interactive, we stick to just-in-time creation of // objects at lookup time, which is much more efficient. // NEW: The clr got a new module variable preload. You can // enable preloading in a non-interactive python processing by // setting clr.preload = True ModuleObject head = (mod_name == realname) ? null : root; ModuleObject tail = root; root.InitializePreload(); for (int i = 0; i < names.Length; i++) { string name = names[i]; ManagedType mt = tail.GetAttribute(name, true); if (!(mt is ModuleObject)) { string error = String.Format("No module named {0}", name); Exceptions.SetError(Exceptions.ImportError, error); return(IntPtr.Zero); } if (head == null) { head = (ModuleObject)mt; } tail = (ModuleObject)mt; if (CLRModule.preload) { tail.LoadNames(); } Runtime.PyDict_SetItemString(modules, tail.moduleName, tail.pyHandle ); } ModuleObject mod = fromlist ? tail : head; if (fromlist && Runtime.PySequence_Size(fromList) == 1) { IntPtr fp = Runtime.PySequence_GetItem(fromList, 0); if ((!CLRModule.preload) && Runtime.GetManagedString(fp) == "*") { mod.LoadNames(); } Runtime.Decref(fp); } Runtime.Incref(mod.pyHandle); return(mod.pyHandle); }
/// <summary> /// Implements __setitem__ for reflected classes and value types. /// </summary> public static int mp_ass_subscript(IntPtr ob, IntPtr idx, IntPtr v) { IntPtr tp = Runtime.PyObject_TYPE(ob); var cls = (ClassBase)GetManagedObject(tp); if (cls.indexer == null || !cls.indexer.CanSet) { Exceptions.SetError(Exceptions.TypeError, "object doesn't support item assignment"); return(-1); } // Arg may be a tuple in the case of an indexer with multiple // parameters. If so, use it directly, else make a new tuple // with the index arg (method binders expect arg tuples). IntPtr args = idx; var free = false; if (!Runtime.PyTuple_Check(idx)) { args = Runtime.PyTuple_New(1); Runtime.XIncref(idx); Runtime.PyTuple_SetItem(args, 0, idx); free = true; } // Get the args passed in. var i = Runtime.PyTuple_Size(args); IntPtr defaultArgs = cls.indexer.GetDefaultArgs(args); var numOfDefaultArgs = Runtime.PyTuple_Size(defaultArgs); var temp = i + numOfDefaultArgs; IntPtr real = Runtime.PyTuple_New(temp + 1); for (var n = 0; n < i; n++) { IntPtr item = Runtime.PyTuple_GetItem(args, n); Runtime.XIncref(item); Runtime.PyTuple_SetItem(real, n, item); } // Add Default Args if needed for (var n = 0; n < numOfDefaultArgs; n++) { IntPtr item = Runtime.PyTuple_GetItem(defaultArgs, n); Runtime.XIncref(item); Runtime.PyTuple_SetItem(real, n + i, item); } // no longer need defaultArgs Runtime.XDecref(defaultArgs); i = temp; // Add value to argument list Runtime.XIncref(v); Runtime.PyTuple_SetItem(real, i, v); try { cls.indexer.SetItem(ob, real); } finally { Runtime.XDecref(real); if (free) { Runtime.XDecref(args); } } if (Exceptions.ErrorOccurred()) { return(-1); } return(0); }
internal List <Binding> Bind(IntPtr inst, IntPtr args, IntPtr kw, Type type, MethodBase info, MethodInfo[] methodinfo) { #region COM Binding List <Binding> bindings = new List <Binding>(); #endregion // loop to find match, return invoker w/ or /wo error MethodBase[] _methods = null; var pynargs = (int)Runtime.PyTuple_Size(args); var isGeneric = false; if (info != null) { _methods = new MethodBase[1]; _methods.SetValue(info, 0); } else { _methods = GetMethods(); } // TODO: Clean up foreach (MethodBase mi in _methods) { #region COM Binding try { // Enforcable return types if (type != null) { if (!(type.IsSubclassOf(((MethodInfo)mi).ReturnType) || type.Equals(((MethodInfo)mi).ReturnType))) { continue; } } } catch (InvalidCastException ex) { } #endregion if (mi.IsGenericMethod) { isGeneric = true; } ParameterInfo[] pi = mi.GetParameters(); ArrayList defaultArgList; bool paramsArray; if (!MatchesArgumentCount(pynargs, pi, out paramsArray, out defaultArgList)) { continue; } var outs = 0; var margs = TryConvertArguments(pi, paramsArray, args, pynargs, defaultArgList, needsResolution: _methods.Length > 1, outs: out outs); 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(new List <Binding>()); } target = co.inst; } #region COM Binding bindings.Add(new Binding(mi, target, margs, outs)); //return new Binding(mi, target, margs, outs); #endregion } #region COM Binding if (bindings.Count > 0) { /*Binding item = bindings.Where<Binding>(x => x.info.Name.EndsWith("_Item")).FirstOrDefault<Binding>(); * if (item != null) * return item; * * Binding def = bindings.Where<Binding>(x => x.info.Name.EndsWith("_Default")).FirstOrDefault<Binding>(); * if (def != null) * return def; * * return bindings.First<Binding>();*/ return(bindings.OrderBy(x => x.info.Name).ToList <Binding>()); } #endregion // 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, type, mi, null)); } return(new List <Binding>()); }
/// <summary> /// Bind the given Python instance and arguments to a particular method /// overload in <see cref="list"/> and return a structure that contains the converted Python /// instance, converted arguments and the correct method to call. /// If unsuccessful, may set a Python error. /// </summary> /// <param name="inst">The Python target of the method invocation.</param> /// <param name="args">The Python arguments.</param> /// <param name="kw">The Python keyword arguments.</param> /// <param name="info">If not null, only bind to that method.</param> /// <param name="methodinfo">If not null, additionally attempt to bind to the generic methods in this array by inferring generic type parameters.</param> /// <returns>A Binding if successful. Otherwise null.</returns> internal Binding Bind(IntPtr inst, IntPtr args, IntPtr kw, MethodBase info, MethodInfo[] methodinfo) { // loop to find match, return invoker w/ or w/o error MethodBase[] _methods = null; var kwargDict = new Dictionary <string, IntPtr>(); if (kw != IntPtr.Zero) { var pynkwargs = (int)Runtime.PyDict_Size(kw); IntPtr keylist = Runtime.PyDict_Keys(kw); IntPtr valueList = Runtime.PyDict_Values(kw); for (int i = 0; i < pynkwargs; ++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); } var pynargs = (int)Runtime.PyTuple_Size(args); var isGeneric = false; if (info != null) { _methods = new MethodBase[1]; _methods.SetValue(info, 0); } else { _methods = GetMethods(); } var argMatchedMethods = new List <MatchedMethod>(_methods.Length); var mismatchedMethods = new List <MismatchedMethod>(); // TODO: Clean up foreach (MethodBase mi in _methods) { if (mi.IsGenericMethod) { isGeneric = true; } ParameterInfo[] pi = mi.GetParameters(); ArrayList defaultArgList; bool paramsArray; int kwargsMatched; int defaultsNeeded; 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 && pynargs == 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. } if (!MatchesArgumentCount(pynargs, pi, kwargDict, out paramsArray, out defaultArgList, out kwargsMatched, out defaultsNeeded) && !isOperator) { continue; } // 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(); } int outs; var margs = TryConvertArguments(pi, paramsArray, args, pynargs, kwargDict, defaultArgList, outs: out outs); if (margs == null) { var mismatchCause = PythonException.FetchCurrent(); mismatchedMethods.Add(new MismatchedMethod(mismatchCause, mi)); continue; } if (isOperator) { if (inst != IntPtr.Zero) { if (ManagedType.GetManagedObject(inst) is CLRObject co) { bool isUnary = pynargs == 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; } } } var matchedMethod = new MatchedMethod(kwargsMatched, defaultsNeeded, margs, outs, mi); argMatchedMethods.Add(matchedMethod); } if (argMatchedMethods.Count > 0) { var bestKwargMatchCount = argMatchedMethods.Max(x => x.KwargsMatched); var fewestDefaultsRequired = argMatchedMethods.Where(x => x.KwargsMatched == bestKwargMatchCount).Min(x => x.DefaultsNeeded); int bestCount = 0; int bestMatchIndex = -1; for (int index = 0; index < argMatchedMethods.Count; index++) { var testMatch = argMatchedMethods[index]; if (testMatch.DefaultsNeeded == fewestDefaultsRequired && testMatch.KwargsMatched == bestKwargMatchCount) { bestCount++; if (bestMatchIndex == -1) { bestMatchIndex = index; } } } if (bestCount > 1 && fewestDefaultsRequired > 0) { // Best effort for determining method to match on gives multiple possible // matches and we need at least one default argument - bail from this point StringBuilder stringBuilder = new StringBuilder("Not enough arguments provided to disambiguate the method. Found:"); foreach (var matchedMethod in argMatchedMethods) { stringBuilder.AppendLine(); stringBuilder.Append(matchedMethod.Method.ToString()); } Exceptions.SetError(Exceptions.TypeError, stringBuilder.ToString()); return(null); } // If we're here either: // (a) There is only one best match // (b) There are multiple best matches but none of them require // default arguments // in the case of (a) we're done by default. For (b) regardless of which // method we choose, all arguments are specified _and_ can be converted // from python to C# so picking any will suffice MatchedMethod bestMatch = argMatchedMethods[bestMatchIndex]; var margs = bestMatch.ManagedArgs; var outs = bestMatch.Outs; var mi = bestMatch.Method; 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) { Exceptions.SetError(Exceptions.TypeError, "Invoked a non-static method with an invalid instance"); return(null); } target = co.inst; } return(new Binding(mi, target, margs, outs)); } else if (isGeneric && info == null && methodinfo != null) { // 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. Type[] types = Runtime.PythonArgsToTypeArray(args, true); MethodInfo mi = MatchParameters(methodinfo, types); if (mi != null) { return(Bind(inst, args, kw, mi, null)); } } if (mismatchedMethods.Count > 0) { var aggregateException = GetAggregateException(mismatchedMethods); Exceptions.SetError(aggregateException); } 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; var kwargDict = new Dictionary <string, IntPtr>(); if (kw != IntPtr.Zero) { var pynkwargs = (int)Runtime.PyDict_Size(kw); IntPtr keylist = Runtime.PyDict_Keys(kw); IntPtr valueList = Runtime.PyDict_Values(kw); for (int i = 0; i < pynkwargs; ++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); } var pynargs = (int)Runtime.PyTuple_Size(args); var isGeneric = false; if (info != null) { _methods = new MethodBase[1]; _methods.SetValue(info, 0); } else { _methods = GetMethods(); } // TODO: Clean up foreach (MethodBase mi in _methods) { if (mi.IsGenericMethod) { isGeneric = true; } ParameterInfo[] pi = mi.GetParameters(); ArrayList defaultArgList; bool paramsArray; if (!MatchesArgumentCount(pynargs, pi, kwargDict, out paramsArray, out defaultArgList)) { continue; } var outs = 0; var margs = TryConvertArguments(pi, paramsArray, args, pynargs, kwargDict, defaultArgList, needsResolution: _methods.Length > 1, outs: out outs); 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 virtual IntPtr Invoke(IntPtr inst, IntPtr args, IntPtr kw, MethodBase info, MethodInfo[] methodinfo) { Binding binding = Bind(inst, args, kw, info, methodinfo); object result; IntPtr ts = IntPtr.Zero; if (binding == null) { var value = new StringBuilder("No method matches given arguments"); if (methodinfo != null && methodinfo.Length > 0) { value.Append($" for {methodinfo[0].Name}"); } long argCount = Runtime.PyTuple_Size(args); value.Append(": ("); for (long argIndex = 0; argIndex < argCount; argIndex++) { var arg = Runtime.PyTuple_GetItem(args, argIndex); if (arg != IntPtr.Zero) { var type = Runtime.PyObject_Type(arg); if (type != IntPtr.Zero) { try { var description = Runtime.PyObject_Unicode(type); if (description != IntPtr.Zero) { value.Append(Runtime.GetManagedString(description)); Runtime.XDecref(description); } } finally { Runtime.XDecref(type); } } } if (argIndex + 1 < argCount) { value.Append(", "); } } value.Append(')'); Exceptions.SetError(Exceptions.TypeError, value.ToString()); return(IntPtr.Zero); } if (allow_threads) { ts = PythonEngine.BeginAllowThreads(); } try { result = binding.info.Invoke(binding.inst, BindingFlags.Default, null, binding.args, null); } catch (Exception e) { if (e.InnerException != null) { e = e.InnerException; } if (allow_threads) { PythonEngine.EndAllowThreads(ts); } Exceptions.SetError(e); return(IntPtr.Zero); } if (allow_threads) { PythonEngine.EndAllowThreads(ts); } // If there are out parameters, we return a tuple containing // the result followed by the out parameters. If there is only // one out parameter and the return type of the method is void, // we return the out parameter as the result to Python (for // code compatibility with ironpython). var mi = (MethodInfo)binding.info; if (binding.outs == 1 && mi.ReturnType == typeof(void)) { } if (binding.outs > 0) { ParameterInfo[] pi = mi.GetParameters(); int c = pi.Length; var n = 0; IntPtr t = Runtime.PyTuple_New(binding.outs + 1); IntPtr v = Converter.ToPython(result, mi.ReturnType); Runtime.PyTuple_SetItem(t, n, v); n++; for (var i = 0; i < c; i++) { Type pt = pi[i].ParameterType; if (pi[i].IsOut || pt.IsByRef) { v = Converter.ToPython(binding.args[i], pt); Runtime.PyTuple_SetItem(t, n, v); n++; } } if (binding.outs == 1 && mi.ReturnType == typeof(void)) { v = Runtime.PyTuple_GetItem(t, 1); Runtime.XIncref(v); Runtime.XDecref(t); return(v); } return(t); } return(Converter.ToPython(result, mi.ReturnType)); }