//==================================================================== // Implements __call__ for reflected generic types. //==================================================================== public static IntPtr tp_call(IntPtr ob, IntPtr args, IntPtr kw) { Exceptions.SetError(Exceptions.TypeError, "object is not callable"); return(IntPtr.Zero); }
//==================================================================== // 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. List <IntPtr> disposeList = new List <IntPtr>(); try { IntPtr target = self.target; if ((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); } target = Runtime.PyTuple_GetItem(args, 0); Runtime.Incref(target); disposeList.Add(target); args = Runtime.PyTuple_GetSlice(args, 1, len); disposeList.Add(args); } // if the class is a IPythonDerivedClass and target is not the same as self.targetType // (eg if calling the base class method) then call the original base class method instead // of the target method. IntPtr superType = IntPtr.Zero; if (Runtime.PyObject_TYPE(target) != self.targetType) { CLRObject inst = CLRObject.GetManagedObject(target) as CLRObject; if (inst != null && (inst.inst as IPythonDerivedType) != null) { ClassBase baseType = GetManagedObject(self.targetType) as ClassBase; if (baseType != null) { string baseMethodName = "_" + baseType.type.Name + "__" + self.m.name; IntPtr baseMethod = Runtime.PyObject_GetAttrString(target, baseMethodName); if (baseMethod != null) { MethodBinding baseSelf = GetManagedObject(baseMethod) as MethodBinding; if (baseSelf != null) { self = baseSelf; } } Runtime.Decref(baseMethod); } } } return(self.m.Invoke(target, args, kw, self.info)); } finally { foreach (IntPtr ptr in disposeList) { Runtime.Decref(ptr); } } }
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 = "No method matches given arguments"; if (methodinfo != null && methodinfo.Length > 0) { value += (" for " + methodinfo[0].Name + ""); } Exceptions.SetError(Exceptions.TypeError, value); 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)); }
/// <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")); } 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(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)); }
/// <summary> /// Allows ctor selection to be limited to a single attempt at a /// match by providing the MethodBase to use instead of searching /// the entire MethodBinder.list (generic ArrayList) /// </summary> /// <param name="inst"> (possibly null) instance </param> /// <param name="args"> PyObject* to the arg tuple </param> /// <param name="kw"> PyObject* to the keyword args dict </param> /// <param name="info"> The sole ContructorInfo to use or null </param> /// <returns> The result of the constructor call with converted params </returns> /// <remarks> /// 2010-07-24 BC: I added the info parameter to the call to Bind() /// Binding binding = this.Bind(inst, args, kw, info); /// to take advantage of Bind()'s ability to use a single MethodBase (CI or MI). /// </remarks> internal object InvokeRaw(IntPtr inst, IntPtr args, IntPtr kw, MethodBase info) { object result; if (_containingType.IsValueType && !_containingType.IsPrimitive && !_containingType.IsEnum && _containingType != typeof(decimal) && Runtime.PyTuple_Size(args) == 0) { // If you are trying to construct an instance of a struct by // calling its default constructor, that ConstructorInfo // instance will not appear in reflection and the object must // instead be constructed via a call to // Activator.CreateInstance(). try { result = Activator.CreateInstance(_containingType); } catch (Exception e) { if (e.InnerException != null) { e = e.InnerException; } Exceptions.SetError(e); return(null); } return(result); } Binding binding = Bind(inst, args, kw, info); if (binding == 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); binding = Bind(inst, eargs, kw); Runtime.XDecref(eargs); if (binding == null) { var errorMessage = new StringBuilder("No constructor matches given arguments"); if (info != null && info.IsConstructor && info.DeclaringType != null) { errorMessage.Append(" for ").Append(info.DeclaringType.Name); } errorMessage.Append(": "); AppendArgumentTypes(to: errorMessage, args); Exceptions.SetError(Exceptions.TypeError, errorMessage.ToString()); return(null); } } // Fire the selected ctor and catch errors... var ci = (ConstructorInfo)binding.info; // Object construction is presumed to be non-blocking and fast // enough that we shouldn't really need to release the GIL. try { result = ci.Invoke(binding.args); } catch (Exception e) { if (e.InnerException != null) { e = e.InnerException; } Exceptions.SetError(e); return(null); } return(result); }
/// <summary> /// Convert a Python value to an instance of a primitive managed type. /// </summary> private static bool ToPrimitive(IntPtr value, Type obType, out object result, bool setError) { IntPtr overflow = Exceptions.OverflowError; TypeCode tc = Type.GetTypeCode(obType); result = null; IntPtr op; int ival; switch (tc) { case TypeCode.String: string st = Runtime.GetManagedString(value); if (st == null) { goto type_error; } result = st; return(true); case TypeCode.Int32: // Trickery to support 64-bit platforms. if (Runtime.IsPython2 && Runtime.Is32Bit) { op = Runtime.PyNumber_Int(value); // As of Python 2.3, large ints magically convert :( if (Runtime.PyLong_Check(op)) { Runtime.XDecref(op); goto overflow; } if (op == IntPtr.Zero) { if (Exceptions.ExceptionMatches(overflow)) { goto overflow; } goto type_error; } ival = (int)Runtime.PyInt_AsLong(op); Runtime.XDecref(op); result = ival; return(true); } else // Python3 always use PyLong API { op = Runtime.PyNumber_Long(value); if (op == IntPtr.Zero) { Exceptions.Clear(); if (Exceptions.ExceptionMatches(overflow)) { goto overflow; } goto type_error; } long ll = (long)Runtime.PyLong_AsLongLong(op); Runtime.XDecref(op); if (ll == -1 && Exceptions.ErrorOccurred()) { goto overflow; } if (ll > Int32.MaxValue || ll < Int32.MinValue) { goto overflow; } result = (int)ll; return(true); } case TypeCode.Boolean: result = Runtime.PyObject_IsTrue(value) != 0; return(true); case TypeCode.Byte: #if PYTHON3 if (Runtime.PyObject_TypeCheck(value, Runtime.PyBytesType)) { if (Runtime.PyBytes_Size(value) == 1) { op = Runtime.PyBytes_AS_STRING(value); result = (byte)Marshal.ReadByte(op); return(true); } goto type_error; } #elif PYTHON2 if (Runtime.PyObject_TypeCheck(value, Runtime.PyStringType)) { if (Runtime.PyString_Size(value) == 1) { op = Runtime.PyString_AsString(value); result = (byte)Marshal.ReadByte(op); return(true); } goto type_error; } #endif op = Runtime.PyNumber_Int(value); if (op == IntPtr.Zero) { if (Exceptions.ExceptionMatches(overflow)) { goto overflow; } goto type_error; } ival = (int)Runtime.PyInt_AsLong(op); Runtime.XDecref(op); if (ival > Byte.MaxValue || ival < Byte.MinValue) { goto overflow; } byte b = (byte)ival; result = b; return(true); case TypeCode.SByte: #if PYTHON3 if (Runtime.PyObject_TypeCheck(value, Runtime.PyBytesType)) { if (Runtime.PyBytes_Size(value) == 1) { op = Runtime.PyBytes_AS_STRING(value); result = (byte)Marshal.ReadByte(op); return(true); } goto type_error; } #elif PYTHON2 if (Runtime.PyObject_TypeCheck(value, Runtime.PyStringType)) { if (Runtime.PyString_Size(value) == 1) { op = Runtime.PyString_AsString(value); result = (sbyte)Marshal.ReadByte(op); return(true); } goto type_error; } #endif op = Runtime.PyNumber_Int(value); if (op == IntPtr.Zero) { if (Exceptions.ExceptionMatches(overflow)) { goto overflow; } goto type_error; } ival = (int)Runtime.PyInt_AsLong(op); Runtime.XDecref(op); if (ival > SByte.MaxValue || ival < SByte.MinValue) { goto overflow; } sbyte sb = (sbyte)ival; result = sb; return(true); case TypeCode.Char: #if PYTHON3 if (Runtime.PyObject_TypeCheck(value, Runtime.PyBytesType)) { if (Runtime.PyBytes_Size(value) == 1) { op = Runtime.PyBytes_AS_STRING(value); result = (byte)Marshal.ReadByte(op); return(true); } goto type_error; } #elif PYTHON2 if (Runtime.PyObject_TypeCheck(value, Runtime.PyStringType)) { if (Runtime.PyString_Size(value) == 1) { op = Runtime.PyString_AsString(value); result = (char)Marshal.ReadByte(op); return(true); } goto type_error; } #endif else if (Runtime.PyObject_TypeCheck(value, Runtime.PyUnicodeType)) { if (Runtime.PyUnicode_GetSize(value) == 1) { op = Runtime.PyUnicode_AsUnicode(value); Char[] buff = new Char[1]; Marshal.Copy(op, buff, 0, 1); result = buff[0]; return(true); } goto type_error; } op = Runtime.PyNumber_Int(value); if (op == IntPtr.Zero) { goto type_error; } ival = Runtime.PyInt_AsLong(op); Runtime.XDecref(op); if (ival > Char.MaxValue || ival < Char.MinValue) { goto overflow; } result = (char)ival; return(true); case TypeCode.Int16: op = Runtime.PyNumber_Int(value); if (op == IntPtr.Zero) { if (Exceptions.ExceptionMatches(overflow)) { goto overflow; } goto type_error; } ival = (int)Runtime.PyInt_AsLong(op); Runtime.XDecref(op); if (ival > Int16.MaxValue || ival < Int16.MinValue) { goto overflow; } short s = (short)ival; result = s; return(true); case TypeCode.Int64: op = Runtime.PyNumber_Long(value); if (op == IntPtr.Zero) { if (Exceptions.ExceptionMatches(overflow)) { goto overflow; } goto type_error; } long l = (long)Runtime.PyLong_AsLongLong(op); Runtime.XDecref(op); if ((l == -1) && Exceptions.ErrorOccurred()) { goto overflow; } result = l; return(true); case TypeCode.UInt16: op = Runtime.PyNumber_Int(value); if (op == IntPtr.Zero) { if (Exceptions.ExceptionMatches(overflow)) { goto overflow; } goto type_error; } ival = (int)Runtime.PyInt_AsLong(op); Runtime.XDecref(op); if (ival > UInt16.MaxValue || ival < UInt16.MinValue) { goto overflow; } ushort us = (ushort)ival; result = us; return(true); case TypeCode.UInt32: op = Runtime.PyNumber_Long(value); if (op == IntPtr.Zero) { if (Exceptions.ExceptionMatches(overflow)) { goto overflow; } goto type_error; } uint ui = (uint)Runtime.PyLong_AsUnsignedLong(op); if (Exceptions.ErrorOccurred()) { Runtime.XDecref(op); goto overflow; } IntPtr check = Runtime.PyLong_FromUnsignedLong(ui); int err = Runtime.PyObject_Compare(check, op); Runtime.XDecref(check); Runtime.XDecref(op); if (0 != err || Exceptions.ErrorOccurred()) { goto overflow; } result = ui; return(true); case TypeCode.UInt64: op = Runtime.PyNumber_Long(value); if (op == IntPtr.Zero) { if (Exceptions.ExceptionMatches(overflow)) { goto overflow; } goto type_error; } ulong ul = (ulong)Runtime.PyLong_AsUnsignedLongLong(op); Runtime.XDecref(op); if (Exceptions.ErrorOccurred()) { goto overflow; } result = ul; return(true); case TypeCode.Single: op = Runtime.PyNumber_Float(value); if (op == IntPtr.Zero) { if (Exceptions.ExceptionMatches(overflow)) { goto overflow; } goto type_error; } double dd = Runtime.PyFloat_AsDouble(op); Runtime.CheckExceptionOccurred(); Runtime.XDecref(op); if (dd > Single.MaxValue || dd < Single.MinValue) { if (!double.IsInfinity(dd)) { goto overflow; } } result = (float)dd; return(true); case TypeCode.Double: op = Runtime.PyNumber_Float(value); if (op == IntPtr.Zero) { goto type_error; } double d = Runtime.PyFloat_AsDouble(op); Runtime.CheckExceptionOccurred(); Runtime.XDecref(op); result = d; return(true); } type_error: if (setError) { string tpName = Runtime.PyObject_GetTypeName(value); Exceptions.SetError(Exceptions.TypeError, $"'{tpName}' value cannot be converted to {obType}"); } return(false); overflow: if (setError) { Exceptions.SetError(Exceptions.OverflowError, "value too large to convert"); } return(false); }
//==================================================================== // Internal helper methods for common error handling scenarios. //==================================================================== internal static IntPtr RaiseTypeError(string message) { Exceptions.SetError(Exceptions.TypeError, message); return(IntPtr.Zero); }
/// <summary> /// The actual import hook that ties Python to the managed world. /// </summary> 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. var 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; var 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") { IntPtr clr_module = GetCLRModule(fromList); if (clr_module != IntPtr.Zero) { IntPtr sys_modules = Runtime.PyImport_GetModuleDict(); if (sys_modules != IntPtr.Zero) { Runtime.PyDict_SetItemString(sys_modules, "clr", clr_module); } } return(clr_module); } if (mod_name == "CLR") { Exceptions.deprecation("The CLR module is deprecated. Please use 'clr'."); IntPtr clr_module = GetCLRModule(fromList); if (clr_module != IntPtr.Zero) { IntPtr sys_modules = Runtime.PyImport_GetModuleDict(); if (sys_modules != IntPtr.Zero) { Runtime.PyDict_SetItemString(sys_modules, "clr", clr_module); } } return(clr_module); } string realname = mod_name; string clr_prefix = null; if (mod_name.StartsWith("CLR.")) { clr_prefix = "CLR."; // prepend when adding the module to sys.modules realname = mod_name.Substring(4); string msg = $"Importing from the CLR.* namespace is deprecated. Please import '{realname}' directly."; 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. 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); } // 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)) { if (!AssemblyManager.LoadImplicit(realname)) { // 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 existing module. IntPtr modules = Runtime.PyImport_GetModuleDict(); IntPtr module = Runtime.PyDict_GetItem(modules, py_mod_name); if (module != IntPtr.Zero) { if (fromlist) { if (IsLoadAll(fromList)) { var mod = ManagedType.GetManagedObject(module) as ModuleObject; mod?.LoadNames(); } Runtime.XIncref(module); return(module); } if (clr_prefix != null) { return(GetCLRModule(fromList)); } module = Runtime.PyDict_GetItemString(modules, names[0]); Runtime.XIncref(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(); foreach (string name in names) { ManagedType mt = tail.GetAttribute(name, true); if (!(mt is ModuleObject)) { Exceptions.SetError(Exceptions.ImportError, $"No module named {name}"); 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.pyHandle); // If imported from CLR add CLR.<modulename> to sys.modules as well if (clr_prefix != null) { Runtime.PyDict_SetItemString(modules, clr_prefix + tail.moduleName, tail.pyHandle); } } { var mod = fromlist ? tail : head; if (fromlist && IsLoadAll(fromList)) { mod.LoadNames(); } Runtime.XIncref(mod.pyHandle); return(mod.pyHandle); } }
internal static bool ToManagedValue(IntPtr value, Type obType, out object result, bool setError) { if (obType == typeof(PyObject)) { Runtime.XIncref(value); // PyObject() assumes ownership result = new PyObject(value); return(true); } // Common case: if the Python value is a wrapped managed object // instance, just return the wrapped object. ManagedType mt = ManagedType.GetManagedObject(value); result = null; if (mt != null) { if (mt is CLRObject) { object tmp = ((CLRObject)mt).inst; if (obType.IsInstanceOfType(tmp)) { result = tmp; return(true); } Exceptions.SetError(Exceptions.TypeError, $"value cannot be converted to {obType}"); return(false); } if (mt is ClassBase) { result = ((ClassBase)mt).type; return(true); } // shouldn't happen return(false); } if (value == Runtime.PyNone && !obType.IsValueType) { result = null; return(true); } if (obType.IsGenericType && obType.GetGenericTypeDefinition() == typeof(Nullable <>)) { if (value == Runtime.PyNone) { result = null; return(true); } // Set type to underlying type obType = obType.GetGenericArguments()[0]; } if (obType.IsArray) { return(ToArray(value, obType, out result, setError)); } if (obType.IsEnum) { return(ToEnum(value, obType, out result, setError)); } // Conversion to 'Object' is done based on some reasonable default // conversions (Python string -> managed string, Python int -> Int32 etc.). if (obType == objectType) { if (Runtime.IsStringType(value)) { return(ToPrimitive(value, stringType, out result, setError)); } if (Runtime.PyBool_Check(value)) { return(ToPrimitive(value, boolType, out result, setError)); } if (Runtime.PyInt_Check(value)) { return(ToPrimitive(value, int32Type, out result, setError)); } if (Runtime.PyLong_Check(value)) { return(ToPrimitive(value, int64Type, out result, setError)); } if (Runtime.PyFloat_Check(value)) { return(ToPrimitive(value, doubleType, out result, setError)); } if (Runtime.PySequence_Check(value)) { return(ToArray(value, typeof(object[]), out result, setError)); } if (setError) { Exceptions.SetError(Exceptions.TypeError, "value cannot be converted to Object"); } return(false); } // Conversion to 'Type' is done using the same mappings as above for objects. if (obType == typeType) { if (value == Runtime.PyStringType) { result = stringType; return(true); } if (value == Runtime.PyBoolType) { result = boolType; return(true); } if (value == Runtime.PyIntType) { result = int32Type; return(true); } if (value == Runtime.PyLongType) { result = int64Type; return(true); } if (value == Runtime.PyFloatType) { result = doubleType; return(true); } if (value == Runtime.PyListType || value == Runtime.PyTupleType) { result = typeof(object[]); return(true); } if (setError) { Exceptions.SetError(Exceptions.TypeError, "value cannot be converted to Type"); } return(false); } return(ToPrimitive(value, obType, out result, setError)); }
/// <summary> /// Default __set__ implementation - this prevents descriptor instances /// being silently replaced in a type __dict__ by default __setattr__. /// </summary> public static int tp_descr_set(IntPtr ds, IntPtr ob, IntPtr val) { Exceptions.SetError(Exceptions.AttributeError, "attribute is read-only"); return(-1); }
/// <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 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); }
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); if (mod_name == "CLR" || mod_name == "clr") { Runtime.Incref(root.pyHandle); return(root.pyHandle); } string realname = mod_name; if (mod_name.StartsWith("CLR.")) { realname = mod_name.Substring(4); } 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(); AssemblyManager.LoadImplicit(realname); if (!AssemblyManager.IsValidNamespace(realname)) { 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. if (preload < 0) { if (Runtime.PySys_GetObject("ps1") != IntPtr.Zero) { preload = 1; } else { Exceptions.Clear(); preload = 0; } } ModuleObject head = (mod_name == realname) ? null : root; ModuleObject tail = root; for (int i = 0; i < names.Length; i++) { string name = names[i]; ManagedType mt = tail.GetAttribute(name); 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 (preload == 1) { 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 ((preload < 1) && Runtime.GetManagedString(fp) == "*") { mod.LoadNames(); } Runtime.Decref(fp); } Runtime.Incref(mod.pyHandle); return(mod.pyHandle); }
/// <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; IntPtr IterObject = Runtime.PyObject_GetIter(value); if (IterObject == IntPtr.Zero) { 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); 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(false); } IntPtr item; while ((item = Runtime.PyIter_Next(IterObject)) != IntPtr.Zero) { object obj; if (!Converter.ToManaged(item, elementType, out obj, setError)) { Runtime.XDecref(item); return(false); } list.Add(obj); Runtime.XDecref(item); } Runtime.XDecref(IterObject); Array items = Array.CreateInstance(elementType, list.Count); list.CopyTo(items, 0); result = items; return(true); }
/// <summary> /// Convert a Python value to an instance of a primitive managed type. /// </summary> private static bool ToPrimitive(IntPtr value, Type obType, out object result, bool setError) { result = null; if (obType.IsEnum) { if (setError) { Exceptions.SetError(Exceptions.TypeError, "since Python.NET 3.0 int can not be converted to Enum implicitly. Use Enum(int_value)"); } return(false); } TypeCode tc = Type.GetTypeCode(obType); IntPtr op = IntPtr.Zero; switch (tc) { case TypeCode.String: string st = Runtime.GetManagedString(value); if (st == null) { goto type_error; } result = st; return(true); case TypeCode.Int32: { // Python3 always use PyLong API nint num = Runtime.PyLong_AsSignedSize_t(value); if (num == -1 && Exceptions.ErrorOccurred()) { goto convert_error; } if (num > Int32.MaxValue || num < Int32.MinValue) { goto overflow; } result = (int)num; return(true); } case TypeCode.Boolean: result = Runtime.PyObject_IsTrue(value) != 0; return(true); case TypeCode.Byte: { if (Runtime.PyObject_TypeCheck(value, Runtime.PyBytesType)) { if (Runtime.PyBytes_Size(value) == 1) { op = Runtime.PyBytes_AS_STRING(value); result = (byte)Marshal.ReadByte(op); return(true); } goto type_error; } nint num = Runtime.PyLong_AsSignedSize_t(value); if (num == -1 && Exceptions.ErrorOccurred()) { goto convert_error; } if (num > Byte.MaxValue || num < Byte.MinValue) { goto overflow; } result = (byte)num; return(true); } case TypeCode.SByte: { if (Runtime.PyObject_TypeCheck(value, Runtime.PyBytesType)) { if (Runtime.PyBytes_Size(value) == 1) { op = Runtime.PyBytes_AS_STRING(value); result = (byte)Marshal.ReadByte(op); return(true); } goto type_error; } nint num = Runtime.PyLong_AsSignedSize_t(value); if (num == -1 && Exceptions.ErrorOccurred()) { goto convert_error; } if (num > SByte.MaxValue || num < SByte.MinValue) { goto overflow; } result = (sbyte)num; return(true); } case TypeCode.Char: { if (Runtime.PyObject_TypeCheck(value, Runtime.PyBytesType)) { if (Runtime.PyBytes_Size(value) == 1) { op = Runtime.PyBytes_AS_STRING(value); result = (byte)Marshal.ReadByte(op); return(true); } goto type_error; } else if (Runtime.PyObject_TypeCheck(value, Runtime.PyUnicodeType)) { if (Runtime.PyUnicode_GetSize(value) == 1) { op = Runtime.PyUnicode_AsUnicode(value); Char[] buff = new Char[1]; Marshal.Copy(op, buff, 0, 1); result = buff[0]; return(true); } goto type_error; } nint num = Runtime.PyLong_AsSignedSize_t(value); if (num == -1 && Exceptions.ErrorOccurred()) { goto convert_error; } if (num > Char.MaxValue || num < Char.MinValue) { goto overflow; } result = (char)num; return(true); } case TypeCode.Int16: { nint num = Runtime.PyLong_AsSignedSize_t(value); if (num == -1 && Exceptions.ErrorOccurred()) { goto convert_error; } if (num > Int16.MaxValue || num < Int16.MinValue) { goto overflow; } result = (short)num; return(true); } case TypeCode.Int64: { if (Runtime.Is32Bit) { if (!Runtime.PyLong_Check(value)) { goto type_error; } long num = Runtime.PyExplicitlyConvertToInt64(value); if (num == -1 && Exceptions.ErrorOccurred()) { goto convert_error; } result = num; return(true); } else { nint num = Runtime.PyLong_AsSignedSize_t(value); if (num == -1 && Exceptions.ErrorOccurred()) { goto convert_error; } result = (long)num; return(true); } } case TypeCode.UInt16: { nint num = Runtime.PyLong_AsSignedSize_t(value); if (num == -1 && Exceptions.ErrorOccurred()) { goto convert_error; } if (num > UInt16.MaxValue || num < UInt16.MinValue) { goto overflow; } result = (ushort)num; return(true); } case TypeCode.UInt32: { nuint num = Runtime.PyLong_AsUnsignedSize_t(value); if (num == unchecked ((nuint)(-1)) && Exceptions.ErrorOccurred()) { goto convert_error; } if (num > UInt32.MaxValue) { goto overflow; } result = (uint)num; return(true); } case TypeCode.UInt64: { ulong num = Runtime.PyLong_AsUnsignedLongLong(value); if (num == ulong.MaxValue && Exceptions.ErrorOccurred()) { goto convert_error; } result = num; return(true); } case TypeCode.Single: { double num = Runtime.PyFloat_AsDouble(value); if (num == -1.0 && Exceptions.ErrorOccurred()) { goto convert_error; } if (num > Single.MaxValue || num < Single.MinValue) { if (!double.IsInfinity(num)) { goto overflow; } } result = (float)num; return(true); } case TypeCode.Double: { double num = Runtime.PyFloat_AsDouble(value); if (num == -1.0 && Exceptions.ErrorOccurred()) { goto convert_error; } result = num; return(true); } default: goto type_error; } convert_error: if (op != value) { Runtime.XDecref(op); } if (!setError) { Exceptions.Clear(); } return(false); type_error: if (setError) { string tpName = Runtime.PyObject_GetTypeName(value); Exceptions.SetError(Exceptions.TypeError, $"'{tpName}' value cannot be converted to {obType}"); } return(false); overflow: // C# level overflow error if (op != value) { Runtime.XDecref(op); } if (setError) { Exceptions.SetError(Exceptions.OverflowError, "value too large to convert"); } return(false); }
internal static bool ToManagedValue(IntPtr value, Type obType, out object result, bool setError) { if (obType == typeof(PyObject)) { Runtime.XIncref(value); // PyObject() assumes ownership result = new PyObject(value); return(true); } // Common case: if the Python value is a wrapped managed object // instance, just return the wrapped object. ManagedType mt = ManagedType.GetManagedObject(value); result = null; if (mt != null) { if (mt is CLRObject co) { object tmp = co.inst; if (obType.IsInstanceOfType(tmp)) { result = tmp; return(true); } if (setError) { string typeString = tmp is null ? "null" : tmp.GetType().ToString(); Exceptions.SetError(Exceptions.TypeError, $"{typeString} value cannot be converted to {obType}"); } return(false); } if (mt is ClassBase cb) { if (!cb.type.Valid) { Exceptions.SetError(Exceptions.TypeError, cb.type.DeletedMessage); return(false); } result = cb.type.Value; return(true); } // shouldn't happen return(false); } if (value == Runtime.PyNone && !obType.IsValueType) { result = null; return(true); } if (obType.IsGenericType && obType.GetGenericTypeDefinition() == typeof(Nullable <>)) { if (value == Runtime.PyNone) { result = null; return(true); } // Set type to underlying type obType = obType.GetGenericArguments()[0]; } if (obType.ContainsGenericParameters) { if (setError) { Exceptions.SetError(Exceptions.TypeError, $"Cannot create an instance of the open generic type {obType}"); } return(false); } if (obType.IsArray) { return(ToArray(value, obType, out result, setError)); } // Conversion to 'Object' is done based on some reasonable default // conversions (Python string -> managed string, Python int -> Int32 etc.). if (obType == objectType) { if (Runtime.IsStringType(value)) { return(ToPrimitive(value, stringType, out result, setError)); } if (Runtime.PyBool_Check(value)) { return(ToPrimitive(value, boolType, out result, setError)); } if (Runtime.PyInt_Check(value)) { return(ToPrimitive(value, int32Type, out result, setError)); } if (Runtime.PyLong_Check(value)) { return(ToPrimitive(value, int64Type, out result, setError)); } if (Runtime.PyFloat_Check(value)) { return(ToPrimitive(value, doubleType, out result, setError)); } // give custom codecs a chance to take over conversion of sequences IntPtr pyType = Runtime.PyObject_TYPE(value); if (PyObjectConversions.TryDecode(value, pyType, obType, out result)) { return(true); } if (Runtime.PySequence_Check(value)) { return(ToArray(value, typeof(object[]), out result, setError)); } Runtime.XIncref(value); // PyObject() assumes ownership result = new PyObject(value); return(true); } // Conversion to 'Type' is done using the same mappings as above for objects. if (obType == typeType) { if (value == Runtime.PyStringType) { result = stringType; return(true); } if (value == Runtime.PyBoolType) { result = boolType; return(true); } if (value == Runtime.PyIntType) { result = int32Type; return(true); } if (value == Runtime.PyLongType) { result = int64Type; return(true); } if (value == Runtime.PyFloatType) { result = doubleType; return(true); } if (value == Runtime.PyListType || value == Runtime.PyTupleType) { result = typeof(object[]); return(true); } if (setError) { Exceptions.SetError(Exceptions.TypeError, "value cannot be converted to Type"); } return(false); } TypeCode typeCode = Type.GetTypeCode(obType); if (typeCode == TypeCode.Object || obType.IsEnum) { IntPtr pyType = Runtime.PyObject_TYPE(value); if (PyObjectConversions.TryDecode(value, pyType, obType, out result)) { return(true); } } return(ToPrimitive(value, obType, out result, setError)); }