public PythonException() : base() { IntPtr gs = PythonEngine.AcquireLock(); Runtime.PyErr_Fetch(ref _pyType, ref _pyValue, ref _pyTB); Runtime.Incref(_pyType); Runtime.Incref(_pyValue); Runtime.Incref(_pyTB); if ((_pyType != IntPtr.Zero) && (_pyValue != IntPtr.Zero)) { string type; string message; Runtime.Incref(_pyType); using (PyObject pyType = new PyObject(_pyType)) using (PyObject pyTypeName = pyType.GetAttr("__name__")) { type = pyTypeName.ToString(); } Runtime.Incref(_pyValue); using (PyObject pyValue = new PyObject(_pyValue)) { message = pyValue.ToString(); } _message = type + " : " + message; } if (_pyTB != IntPtr.Zero) { PyObject tb_module = PythonEngine.ImportModule("traceback"); Runtime.Incref(_pyTB); using (PyObject pyTB = new PyObject(_pyTB)) { _tb = tb_module.InvokeMethod("format_tb", pyTB).ToString(); } } PythonEngine.ReleaseLock(gs); }
/// <summary> /// PyDict Constructor /// </summary> /// /// <remarks> /// Copy constructor - obtain a PyDict from a generic PyObject. An /// ArgumentException will be thrown if the given object is not a /// Python dictionary object. /// </remarks> public PyDict(PyObject o) : base() { if (!IsDictType(o)) { throw new ArgumentException("object is not a dict"); } Runtime.Incref(o.obj); obj = o.obj; }
/// <summary> /// PyLong Constructor /// </summary> /// /// <remarks> /// Copy constructor - obtain a PyLong from a generic PyObject. An /// ArgumentException will be thrown if the given object is not a /// Python long object. /// </remarks> public PyLong(PyObject o) : base() { if (!IsLongType(o)) { throw new ArgumentException("object is not a long"); } Runtime.Incref(o.obj); obj = o.obj; }
/// <summary> /// PyTuple Constructor /// </summary> /// /// <remarks> /// Copy constructor - obtain a PyTuple from a generic PyObject. An /// ArgumentException will be thrown if the given object is not a /// Python tuple object. /// </remarks> public PyTuple(PyObject o) : base() { if (!IsTupleType(o)) { throw new ArgumentException("object is not a tuple"); } Runtime.Incref(o.obj); obj = o.obj; }
/// <summary> /// Contains Method /// </summary> /// /// <remarks> /// Return true if the sequence contains the given item. This method /// throws a PythonException if an error occurs during the check. /// </remarks> public bool Contains(PyObject item) { int r = Runtime.PySequence_Contains(obj, item.obj); if (r < 0) { throw new PythonException(); } return (r != 0); }
/// <summary> /// SetSlice Method /// </summary> /// /// <remarks> /// Sets the slice of the sequence with the given indices. /// </remarks> public void SetSlice(int i1, int i2, PyObject v) { int r = Runtime.PySequence_SetSlice(obj, i1, i2, v.obj); if (r < 0) { throw new PythonException(); } }
/// <summary> /// Concat Method /// </summary> /// /// <remarks> /// Return the concatenation of the sequence object with the passed in /// sequence object. /// </remarks> public PyObject Concat(PyObject other) { IntPtr op = Runtime.PySequence_Concat(obj, other.obj); if (op == IntPtr.Zero) { throw new PythonException(); } return new PyObject(op); }
/// <summary> /// PyInt Constructor /// </summary> /// /// <remarks> /// Copy constructor - obtain a PyInt from a generic PyObject. An /// ArgumentException will be thrown if the given object is not a /// Python int object. /// </remarks> public PyInt(PyObject o) : base() { if (!IsIntType(o)) { throw new ArgumentException("object is not an int"); } Runtime.XIncref(o.obj); obj = o.obj; }
/// <summary> /// PyString Constructor /// </summary> /// /// <remarks> /// Copy constructor - obtain a PyAnsiString from a generic PyObject. /// An ArgumentException will be thrown if the given object is not /// a Python string object. /// </remarks> public PyAnsiString(PyObject o) : base() { if (!IsStringType(o)) { throw new ArgumentException("object is not a string"); } Runtime.XIncref(o.obj); obj = o.obj; }
/// <summary> /// PyTuple Constructor /// </summary> /// /// <remarks> /// Creates a new PyTuple from an array of PyObject instances. /// </remarks> public PyTuple(PyObject[] items) : base() { int count = items.Length; obj = Runtime.PyTuple_New(count); for (int i = 0; i < count; i++) { IntPtr ptr = items[i].obj; Runtime.Incref(ptr); int r = Runtime.PyTuple_SetItem(obj, i, ptr); if (r < 0) { throw new PythonException(); } } }
//=================================================================== // Return the clr python module (new reference) //=================================================================== public static IntPtr GetCLRModule(IntPtr? fromList = null) { root.InitializePreload(); #if (PYTHON32 || PYTHON33 || PYTHON34 || PYTHON35) // update the module dictionary with the contents of the root dictionary root.LoadNames(); IntPtr py_mod_dict = Runtime.PyModule_GetDict(py_clr_module); IntPtr clr_dict = Runtime._PyObject_GetDictPtr(root.pyHandle); // PyObject** clr_dict = (IntPtr)Marshal.PtrToStructure(clr_dict, typeof(IntPtr)); Runtime.PyDict_Update(py_mod_dict, clr_dict); // find any items from the fromlist and get them from the root if they're not // aleady in the module dictionary if (fromList != null && fromList != IntPtr.Zero) { if (Runtime.PyTuple_Check(fromList.GetValueOrDefault())) { Runtime.XIncref(py_mod_dict); using(PyDict mod_dict = new PyDict(py_mod_dict)) { Runtime.XIncref(fromList.GetValueOrDefault()); using (PyTuple from = new PyTuple(fromList.GetValueOrDefault())) { foreach (PyObject item in from) { if (mod_dict.HasKey(item)) continue; string s = item.AsManagedObject(typeof(string)) as string; if (null == s) continue; ManagedType attr = root.GetAttribute(s, true); if (null == attr) continue; Runtime.XIncref(attr.pyHandle); using (PyObject obj = new PyObject(attr.pyHandle)) { mod_dict.SetItem(s, obj); } } } } } } Runtime.XIncref(py_clr_module); return py_clr_module; #else Runtime.XIncref(root.pyHandle); return root.pyHandle; #endif }
// This method calls back into the CPython runtime - tests // call this from Python to check that we don't hang on // nested transitions from managed to Python code and back. public static string CallEchoString(string arg) { IntPtr gs = PythonEngine.AcquireLock(); if (module == null) { module = PythonEngine.ModuleFromString("tt", testmod); } PyObject func = module.GetAttr("echostring"); PyString parg = new PyString(arg); PyObject temp = func.Invoke(parg); string result = (string)temp.AsManagedObject(typeof(String)); func.Dispose(); parg.Dispose(); temp.Dispose(); PythonEngine.ReleaseLock(gs); return result; }
private void LoadScripts(string directory) { log.Info("Loading Python scripts..."); string[] files = Directory.GetFiles(directory, "*.py"); var sb = new StringBuilder(); foreach (string file in files) { try { string script = System.IO.File.ReadAllText(file); sb.Append(script); } catch (Exception e) { log.Error("Failed to load script file \"" + file + "\"", e); } } IntPtr ptr = PythonEngine.AcquireLock(); module = PythonEngine.ModuleFromString("bot", sb.ToString()); PythonEngine.ReleaseLock(ptr); }
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); } }
public static T T <T>(PyObject obj) { return(obj.As <T>()); }
/// <summary> /// Return the clr python module (new reference) /// </summary> public static IntPtr GetCLRModule(IntPtr?fromList = null) { root.InitializePreload(); if (Runtime.IsPython2) { Runtime.XIncref(py_clr_module); return(py_clr_module); } // Python 3 // update the module dictionary with the contents of the root dictionary root.LoadNames(); IntPtr py_mod_dict = Runtime.PyModule_GetDict(py_clr_module); IntPtr clr_dict = Runtime._PyObject_GetDictPtr(root.pyHandle); // PyObject** clr_dict = (IntPtr)Marshal.PtrToStructure(clr_dict, typeof(IntPtr)); Runtime.PyDict_Update(py_mod_dict, clr_dict); // find any items from the from list and get them from the root if they're not // already in the module dictionary if (fromList != null && fromList != IntPtr.Zero) { if (Runtime.PyTuple_Check(fromList.GetValueOrDefault())) { Runtime.XIncref(py_mod_dict); using (var mod_dict = new PyDict(py_mod_dict)) { Runtime.XIncref(fromList.GetValueOrDefault()); using (var from = new PyTuple(fromList.GetValueOrDefault())) { foreach (PyObject item in from) { if (mod_dict.HasKey(item)) { continue; } var s = item.AsManagedObject(typeof(string)) as string; if (s == null) { continue; } ManagedType attr = root.GetAttribute(s, true); if (attr == null) { continue; } Runtime.XIncref(attr.pyHandle); using (var obj = new PyObject(attr.pyHandle)) { mod_dict.SetItem(s, obj); } } } } } } Runtime.XIncref(py_clr_module); return(py_clr_module); }
/// <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" || mod_name == "CLR") { 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)) { var loadExceptions = new List <Exception>(); if (!AssemblyManager.LoadImplicit(realname, assemblyLoadErrorHandler: loadExceptions.Add)) { // May be called when a module being imported imports a module. // In particular, I've seen decimal import copy import org.python.core IntPtr importResult = Runtime.PyObject_Call(py_import, args, kw); // TODO: use ModuleNotFoundError in Python 3.6+ if (importResult == IntPtr.Zero && loadExceptions.Count > 0 && Exceptions.ExceptionMatches(Exceptions.ImportError)) { loadExceptions.Add(new PythonException()); var importError = new PyObject(new BorrowedReference(Exceptions.ImportError)); importError.SetAttr("__cause__", new AggregateException(loadExceptions).ToPython()); Runtime.PyErr_SetObject(new BorrowedReference(Exceptions.ImportError), importError.Reference); } return(importResult); } } // 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); } }
/// <summary> /// IsTupleType Method /// </summary> /// <remarks> /// Returns true if the given object is a Python tuple. /// </remarks> public static bool IsTupleType(PyObject value) { return(Runtime.PyTuple_Check(value.obj)); }
/// <summary> /// SetItem Method /// </summary> /// /// <remarks> /// For objects that support the Python sequence or mapping protocols, /// set the item at the given string index to the given value. This /// method raises a PythonException if the set operation fails. /// </remarks> public virtual void SetItem(string key, PyObject value) { SetItem(new PyString(key), value); }
/// <summary> /// Eval Method /// </summary> /// <remarks> /// Evaluate a Python expression and returns the result. /// It's a subset of Python eval function. /// </remarks> public static PyObject Eval(string code, IntPtr?globals = null, IntPtr?locals = null) { PyObject result = RunString(code, globals, locals, RunFlagType.Eval); return(result); }
/// <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. /// initSigs can be set to 1 to do default python signal configuration. This will override the way signals are handled by the application. /// </remarks> public static void Initialize(IEnumerable <string> args, bool setSysArgv = true, bool initSigs = false) { 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(initSigs); initialized = true; Exceptions.Clear(); // Make sure we clean up properly on app domain unload. AppDomain.CurrentDomain.DomainUnload += OnDomainUnload; // Remember to shut down the runtime. AddShutdownHandler(Runtime.Shutdown); // The global scope gets used implicitly quite early on, remember // to clear it out when we shut down. AddShutdownHandler(PyScopeManager.Global.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(); } } }
/// <summary> /// PyObject Indexer /// </summary> /// <remarks> /// Provides a shorthand for the object versions of the GetItem and /// SetItem methods. /// </remarks> public virtual PyObject this[PyObject key] { get { return(GetItem(key)); } set { SetItem(key, value); } }
/// <summary> /// HasAttr Method /// </summary> /// <remarks> /// Returns true if the object has an attribute with the given name, /// where name is a PyObject wrapping a string or unicode object. /// </remarks> public bool HasAttr(PyObject name) { return(Runtime.Interop.PyObject_HasAttr(obj, name.obj) != 0); }
/// <summary> /// TypeCheck Method /// </summary> /// <remarks> /// Returns true if the object o is of type typeOrClass or a subtype /// of typeOrClass. /// </remarks> public bool TypeCheck(PyObject typeOrClass) { return(Runtime.PyObject_TypeCheck(obj, typeOrClass.obj)); }
/// <summary> /// IsNumberType Method /// </summary> /// /// <remarks> /// Returns true if the given object is a Python numeric type. /// </remarks> public static bool IsNumberType(PyObject value) { return(Runtime.PyNumber_Check(value.obj)); }
protected Dispatcher(IntPtr target, Type dtype) { this.target = new PyObject(new BorrowedReference(target)); this.dtype = dtype; }
/// <summary> /// SetAttr Method /// </summary> /// /// <remarks> /// Set an attribute of the object with the given name and value, /// where the name is a Python string or unicode object. This method /// throws a PythonException if the attribute set fails. /// </remarks> public void SetAttr(PyObject name, PyObject value) { int r = Runtime.PyObject_SetAttr(obj, name.obj, value.obj); if (r < 0) { throw new PythonException(); } }
internal static IntPtr ToPython(object value, Type type) { if (value is PyObject) { IntPtr handle = ((PyObject)value).Handle; Runtime.XIncref(handle); return(handle); } IntPtr result = IntPtr.Zero; // Null always converts to None in Python. if (value == null) { result = Runtime.PyNone; Runtime.XIncref(result); return(result); } if (Type.GetTypeCode(type) == TypeCode.Object && value.GetType() != typeof(object)) { var encoded = PyObjectConversions.TryEncode(value, type); if (encoded != null) { result = encoded.Handle; Runtime.XIncref(result); return(result); } } if (value is IList && !(value is INotifyPropertyChanged) && value.GetType().IsGenericType) { using (var resultlist = new PyList()) { foreach (object o in (IEnumerable)value) { using (var p = new PyObject(ToPython(o, o?.GetType()))) { resultlist.Append(p); } } Runtime.XIncref(resultlist.Handle); return(resultlist.Handle); } } if (type.IsInterface) { var ifaceObj = (InterfaceObject)ClassManager.GetClass(type); return(ifaceObj.WrapObject(value)); } // We need to special case interface array handling to ensure we // produce the correct type. Value may be an array of some concrete // type (FooImpl[]), but we want access to go via the interface type // (IFoo[]). if (type.IsArray && type.GetElementType().IsInterface) { return(CLRObject.GetInstHandle(value, type)); } // it the type is a python subclass of a managed type then return the // underlying python object rather than construct a new wrapper object. var pyderived = value as IPythonDerivedType; if (null != pyderived) { if (!IsTransparentProxy(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: return(CLRObject.GetInstHandle(value, type)); 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.XIncref(Runtime.PyTrue); return(Runtime.PyTrue); } Runtime.XIncref(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); NewReference op = Runtime.PyFloat_FromString(new BorrowedReference(ps));; Runtime.XDecref(ps); return(op.DangerousMoveToPointerOrNull()); 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.XIncref(resultlist.Handle); return(resultlist.Handle); } } result = CLRObject.GetInstHandle(value, type); return(result); } }
public override bool TryBinaryOperation(BinaryOperationBinder binder, Object arg, out Object result) { IntPtr res; if (!(arg is PyObject)) arg = arg.ToPython(); switch (binder.Operation) { case ExpressionType.Add: res = Runtime.PyNumber_Add(this.obj, ((PyObject)arg).obj); break; case ExpressionType.AddAssign: res = Runtime.PyNumber_InPlaceAdd(this.obj, ((PyObject)arg).obj); break; case ExpressionType.Subtract: res = Runtime.PyNumber_Subtract(this.obj, ((PyObject)arg).obj); break; case ExpressionType.SubtractAssign: res = Runtime.PyNumber_InPlaceSubtract(this.obj, ((PyObject)arg).obj); break; case ExpressionType.Multiply: res = Runtime.PyNumber_Multiply(this.obj, ((PyObject)arg).obj); break; case ExpressionType.MultiplyAssign: res = Runtime.PyNumber_InPlaceMultiply(this.obj, ((PyObject)arg).obj); break; case ExpressionType.Divide: res = Runtime.PyNumber_Divide(this.obj, ((PyObject)arg).obj); break; case ExpressionType.DivideAssign: res = Runtime.PyNumber_InPlaceDivide(this.obj, ((PyObject)arg).obj); break; case ExpressionType.And: res = Runtime.PyNumber_And(this.obj, ((PyObject)arg).obj); break; case ExpressionType.AndAssign: res = Runtime.PyNumber_InPlaceAnd(this.obj, ((PyObject)arg).obj); break; case ExpressionType.ExclusiveOr: res = Runtime.PyNumber_Xor(this.obj, ((PyObject)arg).obj); break; case ExpressionType.ExclusiveOrAssign: res = Runtime.PyNumber_InPlaceXor(this.obj, ((PyObject)arg).obj); break; case ExpressionType.GreaterThan: result = Runtime.PyObject_Compare(this.obj, ((PyObject)arg).obj) > 0; return true; case ExpressionType.GreaterThanOrEqual: result = Runtime.PyObject_Compare(this.obj, ((PyObject)arg).obj) >= 0; return true; case ExpressionType.LeftShift: res = Runtime.PyNumber_Lshift(this.obj, ((PyObject)arg).obj); break; case ExpressionType.LeftShiftAssign: res = Runtime.PyNumber_InPlaceLshift(this.obj, ((PyObject)arg).obj); break; case ExpressionType.LessThan: result = Runtime.PyObject_Compare(this.obj, ((PyObject)arg).obj) < 0; return true; case ExpressionType.LessThanOrEqual: result = Runtime.PyObject_Compare(this.obj, ((PyObject)arg).obj) <= 0; return true; case ExpressionType.Modulo: res = Runtime.PyNumber_Remainder(this.obj, ((PyObject)arg).obj); break; case ExpressionType.ModuloAssign: res = Runtime.PyNumber_InPlaceRemainder(this.obj, ((PyObject)arg).obj); break; case ExpressionType.NotEqual: result = Runtime.PyObject_Compare(this.obj, ((PyObject)arg).obj) != 0; return true; case ExpressionType.Or: res = Runtime.PyNumber_Or(this.obj, ((PyObject)arg).obj); break; case ExpressionType.OrAssign: res = Runtime.PyNumber_InPlaceOr(this.obj, ((PyObject)arg).obj); break; case ExpressionType.Power: res = Runtime.PyNumber_Power(this.obj, ((PyObject)arg).obj); break; case ExpressionType.RightShift: res = Runtime.PyNumber_Rshift(this.obj, ((PyObject)arg).obj); break; case ExpressionType.RightShiftAssign: res = Runtime.PyNumber_InPlaceRshift(this.obj, ((PyObject)arg).obj); break; default: result = null; return false; } result = new PyObject(res); return true; }
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)); } 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)); } // 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) { IntPtr pyType = Runtime.PyObject_TYPE(value); if (PyObjectConversions.TryDecode(value, pyType, obType, out result)) { return(true); } } return(ToPrimitive(value, obType, out result, setError)); }
/// <summary> /// IsFloatType Method /// </summary> /// <remarks> /// Returns true if the given object is a Python float. /// </remarks> public static bool IsFloatType(PyObject value) { return(Runtime.PyFloat_Check(value.obj)); }
internal static IntPtr ToPython(object value, Type type) { if (value is PyObject) { IntPtr handle = ((PyObject)value).Handle; Runtime.XIncref(handle); return(handle); } IntPtr result = IntPtr.Zero; // Null always converts to None in Python. if (value == null) { result = Runtime.PyNone; Runtime.XIncref(result); return(result); } if (value is IList && value.GetType().IsGenericType) { using (var resultlist = new PyList()) { foreach (object o in (IEnumerable)value) { using (var p = new PyObject(ToPython(o, o?.GetType()))) { resultlist.Append(p); } } Runtime.XIncref(resultlist.Handle); return(resultlist.Handle); } } // it the type is a python subclass of a managed type then return the // underlying python object rather than construct a new wrapper object. var pyderived = value as IPythonDerivedType; if (null != pyderived) { #if NETSTANDARD return(ClassDerivedObject.ToPython(pyderived)); #else // if object is remote don't do this if (!System.Runtime.Remoting.RemotingServices.IsTransparentProxy(pyderived)) { return(ClassDerivedObject.ToPython(pyderived)); } #endif } // 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: return(CLRObject.GetInstHandle(value, type)); 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.XIncref(Runtime.PyTrue); return(Runtime.PyTrue); } Runtime.XIncref(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.XDecref(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.XIncref(resultlist.Handle); return(resultlist.Handle); } } result = CLRObject.GetInstHandle(value, type); return(result); } }
/// <summary> /// PyObject Indexer /// </summary> /// /// <remarks> /// Provides a shorthand for the object versions of the GetItem and /// SetItem methods. /// </remarks> public virtual PyObject this[PyObject key] { get { return GetItem(key); } set { SetItem(key, value); } }
/// <summary> /// DelItem Method /// </summary> /// /// <remarks> /// For objects that support the Python sequence or mapping protocols, /// delete the item at the given object index. This method raises a /// PythonException if the delete operation fails. /// </remarks> public virtual void DelItem(PyObject key) { int r = Runtime.PyObject_DelItem(obj, key.obj); if (r < 0) { throw new PythonException(); } }
/// <summary> /// HasKey Method /// </summary> /// <remarks> /// Returns true if the object key appears in the dictionary. /// </remarks> public bool HasKey(PyObject key) { return(Runtime.PyMapping_HasKey(obj, key.obj) != 0); }
/// <summary> /// GetAttr Method /// </summary> /// /// <remarks> /// Returns the named attribute of the Python object, or the given /// default object if the attribute access fails. The name argument /// is a PyObject wrapping a Python string or unicode object. /// </remarks> public PyObject GetAttr(PyObject name, PyObject _default) { IntPtr op = Runtime.PyObject_GetAttr(obj, name.obj); if (op == IntPtr.Zero) { Runtime.PyErr_Clear(); return _default; } return new PyObject(op); }
public override bool TryBinaryOperation(BinaryOperationBinder binder, Object arg, out Object result) { IntPtr res; if (!(arg is PyObject)) { arg = arg.ToPython(); } switch (binder.Operation) { case ExpressionType.Add: res = Runtime.PyNumber_Add(this.obj, ((PyObject)arg).obj); break; case ExpressionType.AddAssign: res = Runtime.PyNumber_InPlaceAdd(this.obj, ((PyObject)arg).obj); break; case ExpressionType.Subtract: res = Runtime.PyNumber_Subtract(this.obj, ((PyObject)arg).obj); break; case ExpressionType.SubtractAssign: res = Runtime.PyNumber_InPlaceSubtract(this.obj, ((PyObject)arg).obj); break; case ExpressionType.Multiply: res = Runtime.PyNumber_Multiply(this.obj, ((PyObject)arg).obj); break; case ExpressionType.MultiplyAssign: res = Runtime.PyNumber_InPlaceMultiply(this.obj, ((PyObject)arg).obj); break; case ExpressionType.Divide: res = Runtime.PyNumber_Divide(this.obj, ((PyObject)arg).obj); break; case ExpressionType.DivideAssign: res = Runtime.PyNumber_InPlaceDivide(this.obj, ((PyObject)arg).obj); break; case ExpressionType.And: res = Runtime.PyNumber_And(this.obj, ((PyObject)arg).obj); break; case ExpressionType.AndAssign: res = Runtime.PyNumber_InPlaceAnd(this.obj, ((PyObject)arg).obj); break; case ExpressionType.ExclusiveOr: res = Runtime.PyNumber_Xor(this.obj, ((PyObject)arg).obj); break; case ExpressionType.ExclusiveOrAssign: res = Runtime.PyNumber_InPlaceXor(this.obj, ((PyObject)arg).obj); break; case ExpressionType.GreaterThan: result = Runtime.PyObject_Compare(this.obj, ((PyObject)arg).obj) > 0; return(true); case ExpressionType.GreaterThanOrEqual: result = Runtime.PyObject_Compare(this.obj, ((PyObject)arg).obj) >= 0; return(true); case ExpressionType.LeftShift: res = Runtime.PyNumber_Lshift(this.obj, ((PyObject)arg).obj); break; case ExpressionType.LeftShiftAssign: res = Runtime.PyNumber_InPlaceLshift(this.obj, ((PyObject)arg).obj); break; case ExpressionType.LessThan: result = Runtime.PyObject_Compare(this.obj, ((PyObject)arg).obj) < 0; return(true); case ExpressionType.LessThanOrEqual: result = Runtime.PyObject_Compare(this.obj, ((PyObject)arg).obj) <= 0; return(true); case ExpressionType.Modulo: res = Runtime.PyNumber_Remainder(this.obj, ((PyObject)arg).obj); break; case ExpressionType.ModuloAssign: res = Runtime.PyNumber_InPlaceRemainder(this.obj, ((PyObject)arg).obj); break; case ExpressionType.NotEqual: result = Runtime.PyObject_Compare(this.obj, ((PyObject)arg).obj) != 0; return(true); case ExpressionType.Or: res = Runtime.PyNumber_Or(this.obj, ((PyObject)arg).obj); break; case ExpressionType.OrAssign: res = Runtime.PyNumber_InPlaceOr(this.obj, ((PyObject)arg).obj); break; case ExpressionType.Power: res = Runtime.PyNumber_Power(this.obj, ((PyObject)arg).obj); break; case ExpressionType.RightShift: res = Runtime.PyNumber_Rshift(this.obj, ((PyObject)arg).obj); break; case ExpressionType.RightShiftAssign: res = Runtime.PyNumber_InPlaceRshift(this.obj, ((PyObject)arg).obj); break; default: result = null; return(false); } result = new PyObject(res); return(true); }
/// <summary> /// HasAttr Method /// </summary> /// /// <remarks> /// Returns true if the object has an attribute with the given name, /// where name is a PyObject wrapping a string or unicode object. /// </remarks> public bool HasAttr(PyObject name) { return (Runtime.PyObject_HasAttr(obj, name.obj) != 0); }
/// <summary> /// PyFloat Constructor /// </summary> /// <remarks> /// Copy constructor - obtain a PyFloat from a generic PyObject. An /// ArgumentException will be thrown if the given object is not a /// Python float object. /// </remarks> public PyFloat(PyObject o) : base(FromObject(o)) { }
/// <summary> /// InvokeMethod Method /// </summary> /// /// <remarks> /// Invoke the named method of the object with the given arguments /// and keyword arguments. Keyword args are passed as a PyDict object. /// A PythonException is raised if the invokation is unsuccessful. /// </remarks> public PyObject InvokeMethod(string name, PyObject[] args, PyDict kw) { PyObject method = GetAttr(name); PyObject result = method.Invoke(args, kw); method.Dispose(); return result; }
public static void Initialize() { _opType = GetOperatorType(); }
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> /// TypeCheck Method /// </summary> /// /// <remarks> /// Returns true if the object o is of type typeOrClass or a subtype /// of typeOrClass. /// </remarks> public bool TypeCheck(PyObject typeOrClass) { return Runtime.PyObject_TypeCheck(obj, typeOrClass.obj); }
/// <summary> /// Creates a new managed type derived from a base type with any virtual /// methods overridden to call out to python if the associated python /// object has overridden the method. /// </summary> internal static Type CreateDerivedType(string name, Type baseType, IntPtr py_dict, string namespaceStr, string assemblyName, string moduleName = "Python.Runtime.Dynamic.dll") { if (null != namespaceStr) { name = namespaceStr + "." + name; } if (null == assemblyName) { assemblyName = Assembly.GetExecutingAssembly().FullName; } ModuleBuilder moduleBuilder = GetModuleBuilder(assemblyName, moduleName); Type baseClass = baseType; var interfaces = new List <Type> { typeof(IPythonDerivedType) }; // if the base type is an interface then use System.Object as the base class // and add the base type to the list of interfaces this new class will implement. if (baseType.IsInterface) { interfaces.Add(baseType); baseClass = typeof(object); } TypeBuilder typeBuilder = moduleBuilder.DefineType(name, TypeAttributes.Public | TypeAttributes.Class, baseClass, interfaces.ToArray()); // add a field for storing the python object pointer // FIXME: fb not used FieldBuilder fb = typeBuilder.DefineField("__pyobj__", typeof(CLRObject), FieldAttributes.Public); // override any constructors ConstructorInfo[] constructors = baseClass.GetConstructors(); foreach (ConstructorInfo ctor in constructors) { AddConstructor(ctor, baseType, typeBuilder); } // Override any properties explicitly overridden in python var pyProperties = new HashSet <string>(); if (py_dict != IntPtr.Zero && Runtime.PyDict_Check(py_dict)) { Runtime.XIncref(py_dict); using (var dict = new PyDict(py_dict)) using (PyObject keys = dict.Keys()) { foreach (PyObject pyKey in keys) { using (PyObject value = dict[pyKey]) { if (value.HasAttr("_clr_property_type_")) { string propertyName = pyKey.ToString(); pyProperties.Add(propertyName); // Add the property to the type AddPythonProperty(propertyName, value, typeBuilder); } } } } } // override any virtual methods not already overridden by the properties above MethodInfo[] methods = baseType.GetMethods(); var virtualMethods = new HashSet <string>(); foreach (MethodInfo method in methods) { if (!method.Attributes.HasFlag(MethodAttributes.Virtual) | method.Attributes.HasFlag(MethodAttributes.Final)) { continue; } // skip if this property has already been overridden if ((method.Name.StartsWith("get_") || method.Name.StartsWith("set_")) && pyProperties.Contains(method.Name.Substring(4))) { continue; } // keep track of the virtual methods redirected to the python instance virtualMethods.Add(method.Name); // override the virtual method to call out to the python method, if there is one. AddVirtualMethod(method, baseType, typeBuilder); } // Add any additional methods and properties explicitly exposed from Python. if (py_dict != IntPtr.Zero && Runtime.PyDict_Check(py_dict)) { Runtime.XIncref(py_dict); using (var dict = new PyDict(py_dict)) using (PyObject keys = dict.Keys()) { foreach (PyObject pyKey in keys) { using (PyObject value = dict[pyKey]) { if (value.HasAttr("_clr_return_type_") && value.HasAttr("_clr_arg_types_")) { string methodName = pyKey.ToString(); // if this method has already been redirected to the python method skip it if (virtualMethods.Contains(methodName)) { continue; } // Add the method to the type AddPythonMethod(methodName, value, typeBuilder); } } } } } // add the destructor so the python object created in the constructor gets destroyed MethodBuilder methodBuilder = typeBuilder.DefineMethod("Finalize", MethodAttributes.Family | MethodAttributes.Virtual | MethodAttributes.HideBySig, CallingConventions.Standard, typeof(void), Type.EmptyTypes); ILGenerator il = methodBuilder.GetILGenerator(); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Call, typeof(PythonDerivedType).GetMethod("Finalize")); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Call, baseClass.GetMethod("Finalize", BindingFlags.NonPublic | BindingFlags.Instance)); il.Emit(OpCodes.Ret); Type type = typeBuilder.CreateType(); // scan the assembly so the newly added class can be imported Assembly assembly = Assembly.GetAssembly(type); AssemblyManager.ScanAssembly(assembly); // FIXME: assemblyBuilder not used AssemblyBuilder assemblyBuilder = assemblyBuilders[assemblyName]; return(type); }
/// <summary> /// DelAttr Method /// </summary> /// /// <remarks> /// Delete the named attribute of the Python object, where name is a /// PyObject wrapping a Python string or unicode object. This method /// throws a PythonException if the attribute set fails. /// </remarks> public void DelAttr(PyObject name) { int r = Runtime.PyObject_SetAttr(obj, name.obj, IntPtr.Zero); if (r < 0) { throw new PythonException(); } }
/// <summary> /// Python method may have the following function attributes set to control how they're exposed: /// - _clr_return_type_ - method return type (required) /// - _clr_arg_types_ - list of method argument types (required) /// - _clr_method_name_ - method name, if different from the python method name (optional) /// </summary> /// <param name="methodName">Method name to add to the type</param> /// <param name="func">Python callable object</param> /// <param name="typeBuilder">TypeBuilder for the new type the method/property is to be added to</param> private static void AddPythonMethod(string methodName, PyObject func, TypeBuilder typeBuilder) { if (func.HasAttr("_clr_method_name_")) { using (PyObject pyMethodName = func.GetAttr("_clr_method_name_")) { methodName = pyMethodName.ToString(); } } using (PyObject pyReturnType = func.GetAttr("_clr_return_type_")) using (PyObject pyArgTypes = func.GetAttr("_clr_arg_types_")) { var returnType = pyReturnType.AsManagedObject(typeof(Type)) as Type; if (returnType == null) { returnType = typeof(void); } if (!pyArgTypes.IsIterable()) { throw new ArgumentException("_clr_arg_types_ must be a list or tuple of CLR types"); } var argTypes = new List <Type>(); foreach (PyObject pyArgType in pyArgTypes) { var argType = pyArgType.AsManagedObject(typeof(Type)) as Type; if (argType == null) { throw new ArgumentException("_clr_arg_types_ must be a list or tuple of CLR types"); } argTypes.Add(argType); } // add the method to call back into python MethodAttributes methodAttribs = MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.ReuseSlot | MethodAttributes.HideBySig; MethodBuilder methodBuilder = typeBuilder.DefineMethod(methodName, methodAttribs, returnType, argTypes.ToArray()); ILGenerator il = methodBuilder.GetILGenerator(); il.DeclareLocal(typeof(object[])); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldstr, methodName); il.Emit(OpCodes.Ldnull); // don't fall back to the base type's method il.Emit(OpCodes.Ldc_I4, argTypes.Count); il.Emit(OpCodes.Newarr, typeof(object)); il.Emit(OpCodes.Stloc_0); for (var i = 0; i < argTypes.Count; ++i) { il.Emit(OpCodes.Ldloc_0); il.Emit(OpCodes.Ldc_I4, i); il.Emit(OpCodes.Ldarg, i + 1); if (argTypes[i].IsValueType) { il.Emit(OpCodes.Box, argTypes[i]); } il.Emit(OpCodes.Stelem, typeof(object)); } il.Emit(OpCodes.Ldloc_0); if (returnType == typeof(void)) { il.Emit(OpCodes.Call, typeof(PythonDerivedType).GetMethod("InvokeMethodVoid")); } else { il.Emit(OpCodes.Call, typeof(PythonDerivedType).GetMethod("InvokeMethod").MakeGenericMethod(returnType)); } il.Emit(OpCodes.Ret); } }
/// <summary> /// GetAttr Method /// </summary> /// /// <remarks> /// Returns the named attribute of the Python object or raises a /// PythonException if the attribute access fails. The name argument /// is a PyObject wrapping a Python string or unicode object. /// </remarks> public PyObject GetAttr(PyObject name) { IntPtr op = Runtime.PyObject_GetAttr(obj, name.obj); if (op == IntPtr.Zero) { throw new PythonException(); } return new PyObject(op); }
/// <summary> /// Python properties may have the following function attributes set to control how they're exposed: /// - _clr_property_type_ - property type (required) /// </summary> /// <param name="propertyName">Property name to add to the type</param> /// <param name="func">Python property object</param> /// <param name="typeBuilder">TypeBuilder for the new type the method/property is to be added to</param> private static void AddPythonProperty(string propertyName, PyObject func, TypeBuilder typeBuilder) { // add the method to call back into python MethodAttributes methodAttribs = MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.ReuseSlot | MethodAttributes.HideBySig | MethodAttributes.SpecialName; using (PyObject pyPropertyType = func.GetAttr("_clr_property_type_")) { var propertyType = pyPropertyType.AsManagedObject(typeof(Type)) as Type; if (propertyType == null) { throw new ArgumentException("_clr_property_type must be a CLR type"); } PropertyBuilder propertyBuilder = typeBuilder.DefineProperty(propertyName, PropertyAttributes.None, propertyType, null); if (func.HasAttr("fget")) { using (PyObject pyfget = func.GetAttr("fget")) { if (pyfget.IsTrue()) { MethodBuilder methodBuilder = typeBuilder.DefineMethod("get_" + propertyName, methodAttribs, propertyType, null); ILGenerator il = methodBuilder.GetILGenerator(); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldstr, propertyName); il.Emit(OpCodes.Call, typeof(PythonDerivedType).GetMethod("InvokeGetProperty").MakeGenericMethod(propertyType)); il.Emit(OpCodes.Ret); propertyBuilder.SetGetMethod(methodBuilder); } } } if (func.HasAttr("fset")) { using (PyObject pyset = func.GetAttr("fset")) { if (pyset.IsTrue()) { MethodBuilder methodBuilder = typeBuilder.DefineMethod("set_" + propertyName, methodAttribs, null, new[] { propertyType }); ILGenerator il = methodBuilder.GetILGenerator(); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldstr, propertyName); il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Call, typeof(PythonDerivedType).GetMethod("InvokeSetProperty").MakeGenericMethod(propertyType)); il.Emit(OpCodes.Ret); propertyBuilder.SetSetMethod(methodBuilder); } } } } }
/// <summary> /// GetItem Method /// </summary> /// /// <remarks> /// For objects that support the Python sequence or mapping protocols, /// return the item at the given object index. This method raises a /// PythonException if the indexing operation fails. /// </remarks> public virtual PyObject GetItem(PyObject key) { IntPtr op = Runtime.PyObject_GetItem(obj, key.obj); if (op == IntPtr.Zero) { throw new PythonException(); } return new PyObject(op); }
public static void InvokeMethodVoid(IPythonDerivedType obj, string methodName, string origMethodName, object[] args) { FieldInfo fi = obj.GetType().GetField("__pyobj__"); var self = (CLRObject)fi.GetValue(obj); if (null != self) { var disposeList = new List <PyObject>(); IntPtr gs = Runtime.PyGILState_Ensure(); try { Runtime.XIncref(self.pyHandle); var pyself = new PyObject(self.pyHandle); disposeList.Add(pyself); Runtime.XIncref(Runtime.PyNone); var pynone = new PyObject(Runtime.PyNone); disposeList.Add(pynone); PyObject method = pyself.GetAttr(methodName, pynone); disposeList.Add(method); if (method.Handle != Runtime.PyNone) { // if the method hasn't been overridden then it will be a managed object ManagedType managedMethod = ManagedType.GetManagedObject(method.Handle); if (null == managedMethod) { var pyargs = new PyObject[args.Length]; for (var i = 0; i < args.Length; ++i) { pyargs[i] = new PyObject(Converter.ToPythonImplicit(args[i])); disposeList.Add(pyargs[i]); } PyObject py_result = method.Invoke(pyargs); disposeList.Add(py_result); return; } } } finally { foreach (PyObject x in disposeList) { x?.Dispose(); } Runtime.PyGILState_Release(gs); } } if (origMethodName == null) { throw new NotImplementedException($"Python object does not have a '{methodName}' method"); } obj.GetType().InvokeMember(origMethodName, BindingFlags.InvokeMethod, null, obj, args); }
/// <summary> /// Invoke Method /// </summary> /// /// <remarks> /// Invoke the callable object with the given positional and keyword /// arguments. A PythonException is raised if the invokation fails. /// </remarks> public PyObject Invoke(PyObject[] args, PyDict kw) { PyTuple t = new PyTuple(args); IntPtr r = Runtime.PyObject_Call(obj, t.obj, kw != null ? kw.obj : IntPtr.Zero); t.Dispose(); if (r == IntPtr.Zero) { throw new PythonException(); } return new PyObject(r); }
public static void InvokeCtor(IPythonDerivedType obj, string origCtorName, object[] args) { // call the base constructor obj.GetType().InvokeMember(origCtorName, BindingFlags.InvokeMethod, null, obj, args); var disposeList = new List <PyObject>(); CLRObject self = null; IntPtr gs = Runtime.PyGILState_Ensure(); try { // create the python object IntPtr type = TypeManager.GetTypeHandle(obj.GetType()); self = new CLRObject(obj, type); // set __pyobj__ to self and deref the python object which will allow this // object to be collected. FieldInfo fi = obj.GetType().GetField("__pyobj__"); fi.SetValue(obj, self); Runtime.XIncref(self.pyHandle); var pyself = new PyObject(self.pyHandle); disposeList.Add(pyself); Runtime.XIncref(Runtime.PyNone); var pynone = new PyObject(Runtime.PyNone); disposeList.Add(pynone); // call __init__ PyObject init = pyself.GetAttr("__init__", pynone); disposeList.Add(init); if (init.Handle != Runtime.PyNone) { // if __init__ hasn't been overridden then it will be a managed object ManagedType managedMethod = ManagedType.GetManagedObject(init.Handle); if (null == managedMethod) { var pyargs = new PyObject[args.Length]; for (var i = 0; i < args.Length; ++i) { pyargs[i] = new PyObject(Converter.ToPython(args[i], args[i]?.GetType())); disposeList.Add(pyargs[i]); } disposeList.Add(init.Invoke(pyargs)); } } } finally { foreach (PyObject x in disposeList) { x?.Dispose(); } // Decrement the python object's reference count. // This doesn't actually destroy the object, it just sets the reference to this object // to be a weak reference and it will be destroyed when the C# object is destroyed. if (null != self) { Runtime.XDecref(self.pyHandle); } Runtime.PyGILState_Release(gs); } }
/// <summary> /// IsSubclass Method /// </summary> /// /// <remarks> /// Return true if the object is identical to or derived from the /// given Python type or class. This method always succeeds. /// </remarks> public bool IsSubclass(PyObject typeOrClass) { int r = Runtime.PyObject_IsSubclass(obj, typeOrClass.obj); if (r < 0) { Runtime.PyErr_Clear(); return false; } return (r != 0); }
/// <summary> /// IsLongType Method /// </summary> /// <remarks> /// Returns true if the given object is a Python long. /// </remarks> public static bool IsLongType(PyObject value) { return(Runtime.PyLong_Check(value.obj)); }
/// <summary> /// SetItem Method /// </summary> /// /// <remarks> /// For objects that support the Python sequence or mapping protocols, /// set the item at the given object index to the given value. This /// method raises a PythonException if the set operation fails. /// </remarks> public virtual void SetItem(PyObject key, PyObject value) { int r = Runtime.PyObject_SetItem(obj, key.obj, value.obj); if (r < 0) { throw new PythonException(); } }
/// <summary> /// PyLong Constructor /// </summary> /// <remarks> /// Copy constructor - obtain a PyLong from a generic PyObject. An /// ArgumentException will be thrown if the given object is not a /// Python long object. /// </remarks> public PyLong(PyObject o) : base(FromObject(o)) { }
/// <summary> /// SetItem Method /// </summary> /// /// <remarks> /// For objects that support the Python sequence or mapping protocols, /// set the item at the given numeric index to the given value. This /// method raises a PythonException if the set operation fails. /// </remarks> public virtual void SetItem(int index, PyObject value) { SetItem(new PyInt(index), value); }
internal static IntPtr CreateSubType(IntPtr py_name, IntPtr py_base_type, IntPtr py_dict) { // Utility to create a subtype of a managed type with the ability for the // a python subtype able to override the managed implementation string name = Runtime.GetManagedString(py_name); // the derived class can have class attributes __assembly__ and __module__ which // control the name of the assembly and module the new type is created in. object assembly = null; object namespaceStr = null; var disposeList = new List <PyObject>(); try { var assemblyKey = new PyObject(Converter.ToPython("__assembly__", typeof(string))); disposeList.Add(assemblyKey); if (0 != Runtime.PyMapping_HasKey(py_dict, assemblyKey.Handle)) { var pyAssembly = new PyObject(Runtime.PyDict_GetItem(py_dict, assemblyKey.Handle)); Runtime.XIncref(pyAssembly.Handle); disposeList.Add(pyAssembly); if (!Converter.ToManagedValue(pyAssembly.Handle, typeof(string), out assembly, false)) { throw new InvalidCastException("Couldn't convert __assembly__ value to string"); } } var namespaceKey = new PyObject(Converter.ToPythonImplicit("__namespace__")); disposeList.Add(namespaceKey); if (0 != Runtime.PyMapping_HasKey(py_dict, namespaceKey.Handle)) { var pyNamespace = new PyObject(Runtime.PyDict_GetItem(py_dict, namespaceKey.Handle)); Runtime.XIncref(pyNamespace.Handle); disposeList.Add(pyNamespace); if (!Converter.ToManagedValue(pyNamespace.Handle, typeof(string), out namespaceStr, false)) { throw new InvalidCastException("Couldn't convert __namespace__ value to string"); } } } finally { foreach (PyObject o in disposeList) { o.Dispose(); } } // create the new managed type subclassing the base managed type var baseClass = ManagedType.GetManagedObject(py_base_type) as ClassBase; if (null == baseClass) { return(Exceptions.RaiseTypeError("invalid base class, expected CLR class type")); } try { Type subType = ClassDerivedObject.CreateDerivedType(name, baseClass.type, py_dict, (string)namespaceStr, (string)assembly); // create the new ManagedType and python type ClassBase subClass = ClassManager.GetClass(subType); IntPtr py_type = GetTypeHandle(subClass, subType); // by default the class dict will have all the C# methods in it, but as this is a // derived class we want the python overrides in there instead if they exist. IntPtr cls_dict = Marshal.ReadIntPtr(py_type, TypeOffset.tp_dict); Runtime.PyDict_Update(cls_dict, py_dict); return(py_type); } catch (Exception e) { return(Exceptions.RaiseTypeError(e.Message)); } }
public override bool TryUnaryOperation(UnaryOperationBinder binder, out Object result) { int r; IntPtr res; switch (binder.Operation) { case ExpressionType.Negate: res = Runtime.PyNumber_Negative(this.obj); break; case ExpressionType.UnaryPlus: res = Runtime.PyNumber_Positive(this.obj); break; case ExpressionType.OnesComplement: res = Runtime.PyNumber_Invert(this.obj); break; case ExpressionType.Not: r = Runtime.PyObject_Not(this.obj); result = r == 1; return r != -1; case ExpressionType.IsFalse: r = Runtime.PyObject_IsTrue(this.obj); result = r == 0; return r != -1; case ExpressionType.IsTrue: r = Runtime.PyObject_IsTrue(this.obj); result = r == 1; return r != -1; case ExpressionType.Decrement: case ExpressionType.Increment: default: result = null; return false; } result = new PyObject(res); return true; }
/// <summary>Wraps an existing type object.</summary> public PyType(PyObject o) : base(FromObject(o)) { }