internal static IntPtr ToPython(Object value, Type type) { IntPtr result = IntPtr.Zero; // Null always converts to None in Python. if (value == null) { result = Runtime.PyNone; Runtime.Incref(result); return(result); } // it the type is a python subclass of a managed type then return the // underying python object rather than construct a new wrapper object. IPythonDerivedType pyderived = value as IPythonDerivedType; if (null != pyderived) { return(ClassDerivedObject.ToPython(pyderived)); } // hmm - from Python, we almost never care what the declared // type is. we'd rather have the object bound to the actual // implementing class. type = value.GetType(); TypeCode tc = Type.GetTypeCode(type); switch (tc) { case TypeCode.Object: result = CLRObject.GetInstHandle(value, type); // XXX - hack to make sure we convert new-style class based // managed exception instances to wrappers ;( if (Runtime.wrap_exceptions) { Exception e = value as Exception; if (e != null) { return(Exceptions.GetExceptionInstanceWrapper(result)); } } return(result); case TypeCode.String: return(Runtime.PyUnicode_FromString((string)value)); case TypeCode.Int32: return(Runtime.PyInt_FromInt32((int)value)); case TypeCode.Boolean: if ((bool)value) { Runtime.Incref(Runtime.PyTrue); return(Runtime.PyTrue); } Runtime.Incref(Runtime.PyFalse); return(Runtime.PyFalse); case TypeCode.Byte: return(Runtime.PyInt_FromInt32((int)((byte)value))); case TypeCode.Char: return(Runtime.PyUnicode_FromOrdinal((int)((char)value))); case TypeCode.Int16: return(Runtime.PyInt_FromInt32((int)((short)value))); case TypeCode.Int64: return(Runtime.PyLong_FromLongLong((long)value)); case TypeCode.Single: // return Runtime.PyFloat_FromDouble((double)((float)value)); string ss = ((float)value).ToString(nfi); IntPtr ps = Runtime.PyString_FromString(ss); IntPtr op = Runtime.PyFloat_FromString(ps, IntPtr.Zero); Runtime.Decref(ps); return(op); case TypeCode.Double: return(Runtime.PyFloat_FromDouble((double)value)); case TypeCode.SByte: return(Runtime.PyInt_FromInt32((int)((sbyte)value))); case TypeCode.UInt16: return(Runtime.PyInt_FromInt32((int)((ushort)value))); case TypeCode.UInt32: return(Runtime.PyLong_FromUnsignedLong((uint)value)); case TypeCode.UInt64: return(Runtime.PyLong_FromUnsignedLongLong((ulong)value)); default: if (value is IEnumerable) { using (var resultlist = new PyList()) { foreach (object o in (IEnumerable)value) { using (var p = new PyObject(ToPython(o, o.GetType()))) resultlist.Append(p); } Runtime.Incref(resultlist.Handle); return(resultlist.Handle); } } result = CLRObject.GetInstHandle(value, type); return(result); } }
internal static bool ToManagedValue(IntPtr value, Type obType, out Object result, bool setError) { // Common case: if the Python value is a wrapped managed object // instance, just return the wrapped object. ManagedType mt = ManagedType.GetManagedObject(value); result = null; // XXX - hack to support objects wrapped in old-style classes // (such as exception objects). if (Runtime.wrap_exceptions) { if (mt == null) { if (Runtime.PyObject_IsInstance( value, Exceptions.Exception ) > 0) { IntPtr p = Runtime.PyObject_GetAttrString(value, "_inner"); if (p != IntPtr.Zero) { // This is safe because we know that the __dict__ of // value holds a reference to _inner. value = p; Runtime.Decref(p); mt = ManagedType.GetManagedObject(value); } } IntPtr c = Exceptions.UnwrapExceptionClass(value); if ((c != IntPtr.Zero) && (c != value)) { value = c; Runtime.Decref(c); mt = ManagedType.GetManagedObject(value); } } } if (mt != null) { if (mt is CLRObject) { object tmp = ((CLRObject)mt).inst; if (obType.IsInstanceOfType(tmp)) { result = tmp; return(true); } string err = "value cannot be converted to {0}"; err = String.Format(err, obType); Exceptions.SetError(Exceptions.TypeError, err); return(false); } if (mt is ClassBase) { result = ((ClassBase)mt).type; return(true); } // shouldnt happen return(false); } if (value == Runtime.PyNone && !obType.IsValueType) { result = null; return(true); } 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)); } else if (Runtime.PyBool_Check(value)) { return(ToPrimitive(value, boolType, out result, setError)); } else if (Runtime.PyInt_Check(value)) { return(ToPrimitive(value, int32Type, out result, setError)); } else if (Runtime.PyLong_Check(value)) { return(ToPrimitive(value, int64Type, out result, setError)); } else if (Runtime.PyFloat_Check(value)) { return(ToPrimitive(value, doubleType, out result, setError)); } else 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); } else if (value == Runtime.PyBoolType) { result = boolType; return(true); } else if (value == Runtime.PyIntType) { result = int32Type; return(true); } else if (value == Runtime.PyLongType) { result = int64Type; return(true); } else if (value == Runtime.PyFloatType) { result = doubleType; return(true); } else 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)); }
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> /// 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> /// Initialize Method /// </summary> /// <remarks> /// Initialize the Python runtime. It is safe to call this method /// more than once, though initialization will only happen on the /// first call. It is *not* necessary to hold the Python global /// interpreter lock (GIL) to call this method. /// </remarks> public static void Initialize(IEnumerable <string> args, bool setSysArgv = true) { if (!initialized) { // Creating the delegateManager MUST happen before Runtime.Initialize // is called. If it happens afterwards, DelegateManager's CodeGenerator // throws an exception in its ctor. This exception is eaten somehow // during an initial "import clr", and the world ends shortly thereafter. // This is probably masking some bad mojo happening somewhere in Runtime.Initialize(). delegateManager = new DelegateManager(); Runtime.Initialize(); initialized = true; IntPtr gs = AcquireLock(); Exceptions.Clear(); if (setSysArgv) { Py.SetArgv(args); } // register the atexit callback (this doesn't use Py_AtExit as the C atexit // callbacks are called after python is fully finalized but the python ones // are called while the python engine is still running). string code = "import atexit, clr\n" + "atexit.register(clr._AtExit)\n"; PythonEngine.Exec(code); // Load the clr.py resource into the clr module IntPtr clr = Python.Runtime.ImportHook.GetCLRModule(); IntPtr clr_dict = Runtime.PyModule_GetDict(clr); var locals = new PyDict(); try { IntPtr module = Runtime.PyImport_AddModule("clr._extras"); IntPtr module_globals = Runtime.PyModule_GetDict(module); IntPtr builtins = Runtime.PyEval_GetBuiltins(); Runtime.PyDict_SetItemString(module_globals, "__builtins__", builtins); Assembly assembly = Assembly.GetExecutingAssembly(); using (Stream stream = assembly.GetManifestResourceStream("clr.py")) using (var reader = new StreamReader(stream)) { // add the contents of clr.py to the module string clr_py = reader.ReadToEnd(); Exec(clr_py, module_globals, locals.Handle); } // add the imported module to the clr module, and copy the API functions // and decorators into the main clr module. Runtime.PyDict_SetItemString(clr_dict, "_extras", module); foreach (PyObject key in locals.Keys()) { if (!key.ToString().StartsWith("_") || key.ToString().Equals("__version__")) { PyObject value = locals[key]; Runtime.PyDict_SetItem(clr_dict, key.Handle, value.Handle); value.Dispose(); } key.Dispose(); } } finally { locals.Dispose(); ReleaseLock(gs); } } }
/// <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.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); } var count = Runtime.PyTuple_Size(idx); var args = new int[count]; for (var i = 0; i < count; i++) { IntPtr op = Runtime.PyTuple_GetItem(idx, i); index = Runtime.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); }
//==================================================================== // Internal helper methods for common error handling scenarios. //==================================================================== internal static IntPtr RaiseTypeError(string message) { Exceptions.SetError(Exceptions.TypeError, message); return(IntPtr.Zero); }
static Type TryComputeClrArgumentType(Type parameterType, IntPtr argument, bool needsResolution) { // 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 (needsResolution) { // HACK: each overload should be weighted in some way instead pyoptype = Runtime.PyObject_Type(argument); Exceptions.Clear(); if (pyoptype != IntPtr.Zero) { clrtype = Converter.GetTypeByAlias(pyoptype); } Runtime.XDecref(pyoptype); } if (clrtype != null) { var typematch = false; if ((parameterType != typeof(object)) && (parameterType != clrtype)) { IntPtr pytype = Converter.GetPythonTypeByAlias(parameterType); pyoptype = Runtime.PyObject_Type(argument); Exceptions.Clear(); if (pyoptype != IntPtr.Zero) { if (pytype != pyoptype) { typematch = false; } else { typematch = true; clrtype = parameterType; } } if (!typematch) { // this takes care of enum values TypeCode argtypecode = Type.GetTypeCode(parameterType); TypeCode paramtypecode = Type.GetTypeCode(clrtype); if (argtypecode == paramtypecode) { typematch = true; clrtype = parameterType; } } Runtime.XDecref(pyoptype); if (!typematch) { return(null); } } else { typematch = true; clrtype = parameterType; } } else { clrtype = parameterType; } return(clrtype); }
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); } var underlyingType = Nullable.GetUnderlyingType(obType); if (underlyingType != null) { return(ToManagedValue(value, underlyingType, out result, setError)); } var opImplicit = obType.GetMethod("op_Implicit", new[] { obType }); if (opImplicit != null) { if (ToManagedValue(value, opImplicit.ReturnType, out result, setError)) { opImplicit = obType.GetMethod("op_Implicit", new[] { result.GetType() }); if (opImplicit != null) { result = opImplicit.Invoke(null, new[] { result }); } return(opImplicit != null); } } return(ToPrimitive(value, obType, out result, setError)); }
/// <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.Object: if (obType == typeof(TimeSpan)) { op = Runtime.PyObject_Str(value); TimeSpan ts; var arr = Runtime.GetManagedString(op).Split(','); string sts = arr.Length == 1 ? arr[0] : arr[1]; if (!TimeSpan.TryParse(sts, out ts)) { goto type_error; } Runtime.XDecref(op); int days = 0; if (arr.Length > 1) { if (!int.TryParse(arr[0].Split(' ')[0].Trim(), out days)) { goto type_error; } } result = ts.Add(TimeSpan.FromDays(days)); return(true); } break; 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); case TypeCode.Decimal: op = Runtime.PyObject_Str(value); decimal m; string sm = Runtime.GetManagedString(op); if (!Decimal.TryParse(sm, NumberStyles.Number, nfi, out m)) { goto type_error; } Runtime.XDecref(op); result = m; return(true); case TypeCode.DateTime: op = Runtime.PyObject_Str(value); DateTime dt; string sdt = Runtime.GetManagedString(op); if (!DateTime.TryParse(sdt, out dt)) { goto type_error; } Runtime.XDecref(op); result = dt; 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 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; ArrayList defaultArgList = null; if (info != null) { _methods = (MethodBase[])Array.CreateInstance( typeof(MethodBase), 1 ); _methods.SetValue(info, 0); } else { _methods = GetMethods(); } Type clrtype; 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) { match = true; defaultArgList = new ArrayList(); for (int v = pynargs; v < clrnargs; v++) { if (pi[v].DefaultValue == DBNull.Value) { match = false; } else { defaultArgList.Add((object)pi[v].DefaultValue); } } } else if ((pynargs > clrnargs) && (clrnargs > 0) && Attribute.IsDefined(pi[clrnargs - 1], typeof(ParamArrayAttribute))) { // This is 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 (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.Decref(pyoptype); } if (clrtype != null) { bool typematch = false; if (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 enum values TypeCode argtypecode = Type.GetTypeCode(pi[n].ParameterType); TypeCode paramtypecode = Type.GetTypeCode(clrtype); if (argtypecode == paramtypecode) { typematch = true; clrtype = pi[n].ParameterType; } } Runtime.Decref(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.Decref(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' 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); }
/// <summary> /// Standard comparison implementation for instances of reflected types. /// </summary> public static IntPtr tp_richcompare(IntPtr ob, IntPtr other, int op) { CLRObject co1; CLRObject co2; switch (op) { case Runtime.Py_EQ: case Runtime.Py_NE: IntPtr pytrue = Runtime.PyTrue; IntPtr pyfalse = Runtime.PyFalse; // swap true and false for NE if (op != Runtime.Py_EQ) { pytrue = Runtime.PyFalse; pyfalse = Runtime.PyTrue; } if (ob == other) { Runtime.XIncref(pytrue); return(pytrue); } co1 = GetManagedObject(ob) as CLRObject; co2 = GetManagedObject(other) as CLRObject; if (null == co2) { Runtime.XIncref(pyfalse); return(pyfalse); } object o1 = co1.inst; object o2 = co2.inst; if (Equals(o1, o2)) { Runtime.XIncref(pytrue); return(pytrue); } Runtime.XIncref(pyfalse); return(pyfalse); case Runtime.Py_LT: case Runtime.Py_LE: case Runtime.Py_GT: case Runtime.Py_GE: co1 = GetManagedObject(ob) as CLRObject; co2 = GetManagedObject(other) as CLRObject; if (co1 == null || co2 == null) { return(Exceptions.RaiseTypeError("Cannot get managed object")); } var co1Comp = co1.inst as IComparable; if (co1Comp == null) { Type co1Type = co1.GetType(); return(Exceptions.RaiseTypeError($"Cannot convert object of type {co1Type} to IComparable")); } try { int cmp = co1Comp.CompareTo(co2.inst); IntPtr pyCmp; if (cmp < 0) { if (op == Runtime.Py_LT || op == Runtime.Py_LE) { pyCmp = Runtime.PyTrue; } else { pyCmp = Runtime.PyFalse; } } else if (cmp == 0) { if (op == Runtime.Py_LE || op == Runtime.Py_GE) { pyCmp = Runtime.PyTrue; } else { pyCmp = Runtime.PyFalse; } } else { if (op == Runtime.Py_GE || op == Runtime.Py_GT) { pyCmp = Runtime.PyTrue; } else { pyCmp = Runtime.PyFalse; } } Runtime.XIncref(pyCmp); return(pyCmp); } catch (ArgumentException e) { return(Exceptions.RaiseTypeError(e.Message)); } default: Runtime.XIncref(Runtime.PyNotImplemented); return(Runtime.PyNotImplemented); } }
/// <summary> /// MethodBinding __call__ implementation. /// </summary> public static IntPtr tp_call(IntPtr ob, IntPtr args, IntPtr kw) { var 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) { var len = Runtime.PyTuple_Size(args); //FIXME: Never used 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. var disposeList = new List <IntPtr>(); try { IntPtr target = self.target; if (target == IntPtr.Zero && !self.m.IsStatic()) { var 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.XIncref(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) { var inst = GetManagedObject(target) as CLRObject; if (inst?.inst is IPythonDerivedType) { var 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 != IntPtr.Zero) { var baseSelf = GetManagedObject(baseMethod) as MethodBinding; if (baseSelf != null) { self = baseSelf; } Runtime.XDecref(baseMethod); } else { Runtime.PyErr_Clear(); } } } } return(self.m.Invoke(target, args, kw, self.info)); } finally { foreach (IntPtr ptr in disposeList) { Runtime.XDecref(ptr); } } }
//==================================================================== // Convert a Python value to an instance of a primitive managed type. //==================================================================== 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: #if !(PYTHON32 || PYTHON33 || PYTHON34 || PYTHON35) // Trickery to support 64-bit platforms. if (IntPtr.Size == 4) { op = Runtime.PyNumber_Int(value); // As of Python 2.3, large ints magically convert :( if (Runtime.PyLong_Check(op)) { Runtime.Decref(op); goto overflow; } if (op == IntPtr.Zero) { if (Exceptions.ExceptionMatches(overflow)) { goto overflow; } goto type_error; } ival = (int)Runtime.PyInt_AsLong(op); Runtime.Decref(op); result = ival; return(true); } else { #else // When using Python3 always use the PyLong API { #endif 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.Decref(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 (PYTHON32 || PYTHON33 || PYTHON34 || PYTHON35) 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.PyStringType)) { if (Runtime.PyString_Size(value) == 1) { op = Runtime.PyString_AS_STRING(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.Decref(op); if (ival > Byte.MaxValue || ival < Byte.MinValue) { goto overflow; } byte b = (byte)ival; result = b; return(true); case TypeCode.SByte: #if (PYTHON32 || PYTHON33 || PYTHON34 || PYTHON35) 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.PyStringType)) { if (Runtime.PyString_Size(value) == 1) { op = Runtime.PyString_AS_STRING(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.Decref(op); if (ival > SByte.MaxValue || ival < SByte.MinValue) { goto overflow; } sbyte sb = (sbyte)ival; result = sb; return(true); case TypeCode.Char: #if (PYTHON32 || PYTHON33 || PYTHON34 || PYTHON35) 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.PyStringType)) { if (Runtime.PyString_Size(value) == 1) { op = Runtime.PyString_AS_STRING(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_AS_UNICODE(value); #if (!UCS4) // 2011-01-02: Marshal as character array because the cast // result = (char)Marshal.ReadInt16(op); throws an OverflowException // on negative numbers with Check Overflow option set on the project Char[] buff = new Char[1]; Marshal.Copy(op, buff, 0, 1); result = buff[0]; #else // XXX this is probably NOT correct? result = (char)Marshal.ReadInt32(op); #endif return(true); } goto type_error; } op = Runtime.PyNumber_Int(value); if (op == IntPtr.Zero) { goto type_error; } ival = Runtime.PyInt_AsLong(op); Runtime.Decref(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.Decref(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.Decref(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.Decref(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.Decref(op); goto overflow; } IntPtr check = Runtime.PyLong_FromUnsignedLong(ui); int err = Runtime.PyObject_Compare(check, op); Runtime.Decref(check); Runtime.Decref(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.Decref(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.Decref(op); if (dd > Single.MaxValue || dd < Single.MinValue) { 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.Decref(op); if (d > Double.MaxValue || d < Double.MinValue) { goto overflow; } result = d; return(true); } type_error: if (setError) { string format = "'{0}' value cannot be converted to {1}"; string tpName = Runtime.PyObject_GetTypeName(value); string error = String.Format(format, tpName, obType); Exceptions.SetError(Exceptions.TypeError, error); } return(false); overflow: if (setError) { string error = "value too large to convert"; Exceptions.SetError(Exceptions.OverflowError, error); } return(false); }
/// <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. int num_args = Runtime.Interop.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.Interop.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.Interop.PyTuple_GetItem(args, 3); if (fromList != IntPtr.Zero && Runtime.Interop.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.Interop.PyImport_GetModuleDict(); if (sys_modules != IntPtr.Zero) { Runtime.Interop.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.Interop.PyImport_GetModuleDict(); if (sys_modules != IntPtr.Zero) { Runtime.Interop.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.Interop.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); } 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.Interop.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.Interop.PyImport_GetModuleDict(); IntPtr module = Runtime.Interop.PyDict_GetItem(modules, py_mod_name); if (module != IntPtr.Zero) { if (fromlist) { Runtime.XIncref(module); return(module); } if (clr_prefix != null) { return(GetCLRModule(fromList)); } module = Runtime.Interop.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.Interop.PyDict_SetItemString(modules, tail.moduleName, tail.pyHandle); // If imported from CLR add CLR.<modulename> to sys.modules as well if (clr_prefix != null) { Runtime.Interop.PyDict_SetItemString(modules, clr_prefix + tail.moduleName, tail.pyHandle); } } ModuleObject mod = fromlist ? tail : head; if (fromlist && Runtime.Interop.PySequence_Size(fromList) == 1) { IntPtr fp = Runtime.Interop.PySequence_GetItem(fromList, 0); if (!CLRModule.preload && Runtime.GetManagedString(fp) == "*") { mod.LoadNames(); } Runtime.XDecref(fp); } Runtime.XIncref(mod.pyHandle); return(mod.pyHandle); }
/// <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 = this.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 = this.Bind(inst, eargs, kw); Runtime.XDecref(eargs); if (binding == null) { Exceptions.SetError(Exceptions.TypeError, "no constructor matches given arguments" ); return(null); } } // Fire the selected ctor and catch errors... ConstructorInfo 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> /// 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); } }
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> /// 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); if (!self.info.Valid) { Exceptions.RaiseTypeError(self.info.DeletedMessage); return(-1); } var info = self.info.Value; MethodInfo setter = self.setter.UnsafeValue; 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, 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); } var type = co.inst.GetType(); self.GetMemberSetter(type)(self.IsValueType(type) ? co.inst.WrapIfValueType() : co.inst, newval); } else { self.GetMemberSetter(info.DeclaringType)(info.DeclaringType, newval); } return(0); } catch (Exception e) { if (e.InnerException != null) { e = e.InnerException; } Exceptions.SetError(e); return(-1); } }
/// <summary> /// Metatype __new__ implementation. This is called to create a new /// class / type when a reflected class is subclassed. /// </summary> public static IntPtr tp_new(IntPtr tp, IntPtr args, IntPtr kw) { var 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. var 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__")); } // If __assembly__ or __namespace__ are in the class dictionary then create // a managed sub type. // This creates a new managed type that can be used from .net to call back // into python. if (IntPtr.Zero != dict) { Runtime.XIncref(dict); using (var clsDict = new PyDict(dict)) { if (clsDict.HasKey("__assembly__") || clsDict.HasKey("__namespace__")) { return(TypeManager.CreateSubType(name, base_type, dict)); } } } // otherwise just create a basic type without reflecting back into the managed side. IntPtr func = Marshal.ReadIntPtr(Runtime.PyTypeType, TypeOffset.tp_new); IntPtr type = NativeCall.Call_3(func, tp, args, kw); if (type == IntPtr.Zero) { return(IntPtr.Zero); } int flags = TypeFlags.Default; flags |= TypeFlags.Managed; flags |= TypeFlags.HeapType; flags |= TypeFlags.BaseType; flags |= TypeFlags.Subclass; flags |= TypeFlags.HaveGC; Util.WriteCLong(type, TypeOffset.tp_flags, flags); TypeManager.CopySlot(base_type, type, TypeOffset.tp_dealloc); // Hmm - the standard subtype_traverse, clear look at ob_size to // do things, so to allow gc to work correctly we need to move // our hidden handle out of ob_size. Then, in theory we can // comment this out and still not crash. TypeManager.CopySlot(base_type, type, TypeOffset.tp_traverse); TypeManager.CopySlot(base_type, type, TypeOffset.tp_clear); // for now, move up hidden handle... IntPtr gc = Marshal.ReadIntPtr(base_type, TypeOffset.magic()); Marshal.WriteIntPtr(type, TypeOffset.magic(), gc); return(type); }
/// <summary> /// Descriptor __get__ implementation. This method returns the /// value of the property on the given object. The returned value /// is converted to an appropriately typed Python object. /// </summary> public static IntPtr tp_descr_get(IntPtr ds, IntPtr ob, IntPtr tp) { var self = (PropertyObject)GetManagedObject(ds); if (!self.info.Valid) { return(Exceptions.RaiseTypeError(self.info.DeletedMessage)); } var info = self.info.Value; MethodInfo getter = self.getter.UnsafeValue; object result; if (getter == null) { return(Exceptions.RaiseTypeError("property cannot be read")); } if (ob == IntPtr.Zero || ob == Runtime.PyNone) { if (!getter.IsStatic) { Exceptions.SetError(Exceptions.TypeError, "instance property must be accessed through a class instance"); return(IntPtr.Zero); } try { result = self.GetMemberGetter(info.DeclaringType)(info.DeclaringType); return(Converter.ToPython(result, info.PropertyType)); } catch (Exception e) { return(Exceptions.RaiseTypeError(e.Message)); } } var co = GetManagedObject(ob) as CLRObject; if (co == null) { return(Exceptions.RaiseTypeError("invalid target")); } try { var type = co.inst.GetType(); result = self.GetMemberGetter(type)(self.IsValueType(type) ? co.inst.WrapIfValueType() : co.inst); return(Converter.ToPython(result, info.PropertyType)); } catch (Exception e) { if (e.InnerException != null) { e = e.InnerException; } Exceptions.SetError(e); return(IntPtr.Zero); } }
/// <summary> /// Implements __getitem__ for array types. /// </summary> public static IntPtr mp_subscript(IntPtr ob, IntPtr idx) { var obj = (CLRObject)GetManagedObject(ob); var arrObj = (ArrayObject)GetManagedObjectType(ob); var items = obj.inst as Array; Type itemType = arrObj.type.GetElementType(); int rank = items.Rank; int index; object value; // Note that CLR 1.0 only supports int indexes - methods to // support long indices were introduced in 1.1. We could // support long indices automatically, but given that long // indices are not backward compatible and a relative edge // case, we won't bother for now. // Single-dimensional arrays are the most common case and are // cheaper to deal with than multi-dimensional, so check first. if (rank == 1) { index = Runtime.PyInt_AsLong(idx); if (Exceptions.ErrorOccurred()) { return(Exceptions.RaiseTypeError("invalid index value")); } if (index < 0) { index = items.Length + index; } try { value = items.GetValue(index); } catch (IndexOutOfRangeException) { Exceptions.SetError(Exceptions.IndexError, "array index out of range"); return(IntPtr.Zero); } return(Converter.ToPython(value, itemType)); } // Multi-dimensional arrays can be indexed a la: list[1, 2, 3]. if (!Runtime.PyTuple_Check(idx)) { Exceptions.SetError(Exceptions.TypeError, "invalid index value"); return(IntPtr.Zero); } var count = Runtime.PyTuple_Size(idx); var args = new int[count]; for (var i = 0; i < count; i++) { IntPtr op = Runtime.PyTuple_GetItem(idx, i); index = Runtime.PyInt_AsLong(op); if (Exceptions.ErrorOccurred()) { return(Exceptions.RaiseTypeError("invalid index value")); } if (index < 0) { index = items.GetLength(i) + index; } args.SetValue(index, i); } try { value = items.GetValue(args); } catch (IndexOutOfRangeException) { Exceptions.SetError(Exceptions.IndexError, "array index out of range"); return(IntPtr.Zero); } return(Converter.ToPython(value, itemType)); }
/// <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); }