private PyDict_SetItemString ( IntPtr pointer, string key, IntPtr value ) : int | ||
pointer | IntPtr | |
key | string | |
value | IntPtr | |
return | int |
private static void SetVariable(IntPtr?globals, string key, IntPtr value) { CpyRuntime.PyDict_SetItemString( pointer: globals.Value, key: key, value: value ); }
public override ValueType Execute(ValueType arg) { const string code = @" from Python.EmbeddingTest.Domain import MyClass def test_obj_call(): obj = MyClass() obj.Method() obj.StaticMethod() obj.Property = 1 obj.Field = 10 test_obj_call() "; const string name = "test_domain_reload_mod"; using (Py.GIL()) { // Create a new module IntPtr module = PyRuntime.PyModule_New(name); Assert.That(module != IntPtr.Zero); IntPtr globals = PyRuntime.PyObject_GetAttrString(module, "__dict__"); Assert.That(globals != IntPtr.Zero); try { // import builtins // module.__dict__[__builtins__] = builtins int res = PyRuntime.PyDict_SetItemString(globals, "__builtins__", PyRuntime.PyEval_GetBuiltins()); PythonException.ThrowIfIsNotZero(res); // Execute the code in the module's scope PythonEngine.Exec(code, globals); // import sys // modules = sys.modules IntPtr modules = PyRuntime.PyImport_GetModuleDict(); // modules[name] = module res = PyRuntime.PyDict_SetItemString(modules, name, module); PythonException.ThrowIfIsNotZero(res); } catch { PyRuntime.XDecref(module); throw; } finally { PyRuntime.XDecref(globals); } return(module); } }
internal static IntPtr CreateMetaType(Type impl) { // The managed metatype is functionally little different than the // standard Python metatype (PyType_Type). It overrides certain of // the standard type slots, and has to subclass PyType_Type for // certain functions in the C runtime to work correctly with it. IntPtr type = AllocateTypeObject("CLR Metatype"); IntPtr py_type = Runtime.PyTypeType; Marshal.WriteIntPtr(type, TypeOffset.tp_base, py_type); Runtime.XIncref(py_type); // Copy gc and other type slots from the base Python metatype. CopySlot(py_type, type, TypeOffset.tp_basicsize); CopySlot(py_type, type, TypeOffset.tp_itemsize); CopySlot(py_type, type, TypeOffset.tp_dictoffset); CopySlot(py_type, type, TypeOffset.tp_weaklistoffset); CopySlot(py_type, type, TypeOffset.tp_traverse); CopySlot(py_type, type, TypeOffset.tp_clear); CopySlot(py_type, type, TypeOffset.tp_is_gc); // Override type slots with those of the managed implementation. InitializeSlots(type, impl); int flags = TypeFlags.Default; flags |= TypeFlags.Managed; flags |= TypeFlags.HeapType; flags |= TypeFlags.HaveGC; Util.WriteCLong(type, TypeOffset.tp_flags, flags); // We need space for 3 PyMethodDef structs, each of them // 4 int-ptrs in size. IntPtr mdef = Runtime.PyMem_Malloc(3 * 4 * IntPtr.Size); IntPtr mdefStart = mdef; mdef = WriteMethodDef( mdef, "__instancecheck__", Interop.GetThunk(typeof(MetaType).GetMethod("__instancecheck__"), "BinaryFunc") ); mdef = WriteMethodDef( mdef, "__subclasscheck__", Interop.GetThunk(typeof(MetaType).GetMethod("__subclasscheck__"), "BinaryFunc") ); // FIXME: mdef is not used mdef = WriteMethodDefSentinel(mdef); Marshal.WriteIntPtr(type, TypeOffset.tp_methods, mdefStart); Runtime.PyType_Ready(type); IntPtr dict = Marshal.ReadIntPtr(type, TypeOffset.tp_dict); IntPtr mod = Runtime.PyString_FromString("CLR"); Runtime.PyDict_SetItemString(dict, "__module__", mod); //DebugUtil.DumpType(type); return(type); }
internal static IntPtr CreateType(ManagedType impl, Type clrType) { // Cleanup the type name to get rid of funny nested type names. string name = "CLR." + clrType.FullName; int i = name.LastIndexOf('+'); if (i > -1) { name = name.Substring(i + 1); } i = name.LastIndexOf('.'); if (i > -1) { name = name.Substring(i + 1); } IntPtr base_ = IntPtr.Zero; int ob_size = ObjectOffset.Size(Runtime.PyTypeType); int tp_dictoffset = ObjectOffset.DictOffset(Runtime.PyTypeType); // XXX Hack, use a different base class for System.Exception // Python 2.5+ allows new style class exceptions but they *must* // subclass BaseException (or better Exception). if (typeof(Exception).IsAssignableFrom(clrType)) { ob_size = ObjectOffset.Size(Exceptions.Exception); tp_dictoffset = ObjectOffset.DictOffset(Exceptions.Exception); } if (clrType == typeof(Exception)) { base_ = Exceptions.Exception; } else if (clrType.BaseType != null) { ClassBase bc = ClassManager.GetClass(clrType.BaseType); base_ = bc.pyHandle; } IntPtr type = AllocateTypeObject(name); Marshal.WriteIntPtr(type, TypeOffset.ob_type, Runtime.PyCLRMetaType); Runtime.XIncref(Runtime.PyCLRMetaType); Marshal.WriteIntPtr(type, TypeOffset.tp_basicsize, (IntPtr)ob_size); Marshal.WriteIntPtr(type, TypeOffset.tp_itemsize, IntPtr.Zero); Marshal.WriteIntPtr(type, TypeOffset.tp_dictoffset, (IntPtr)tp_dictoffset); InitializeSlots(type, impl.GetType()); if (base_ != IntPtr.Zero) { Marshal.WriteIntPtr(type, TypeOffset.tp_base, base_); Runtime.XIncref(base_); } int flags = TypeFlags.Default; flags |= TypeFlags.Managed; flags |= TypeFlags.HeapType; flags |= TypeFlags.BaseType; flags |= TypeFlags.HaveGC; Util.WriteCLong(type, TypeOffset.tp_flags, flags); // Leverage followup initialization from the Python runtime. Note // that the type of the new type must PyType_Type at the time we // call this, else PyType_Ready will skip some slot initialization. Runtime.PyType_Ready(type); IntPtr dict = Marshal.ReadIntPtr(type, TypeOffset.tp_dict); string mn = clrType.Namespace ?? ""; IntPtr mod = Runtime.PyString_FromString(mn); Runtime.PyDict_SetItemString(dict, "__module__", mod); // Hide the gchandle of the implementation in a magic type slot. GCHandle gc = GCHandle.Alloc(impl); Marshal.WriteIntPtr(type, TypeOffset.magic(), (IntPtr)gc); // Set the handle attributes on the implementing instance. impl.tpHandle = Runtime.PyCLRMetaType; impl.gcHandle = gc; impl.pyHandle = type; //DebugUtil.DumpType(type); return(type); }
/// <remarks> /// the lines /// // XXX - hack to raise a compatible old-style exception ;( /// if (Runtime.wrap_exceptions) { /// CallOneOfTheseMethods(); /// /// </remarks> internal static void SetupExceptionHack() { ns_exc = ClassManager.GetClass(typeof(Exception)).pyHandle; cache = new Hashtable(); string code = "import exceptions\n" + "class Exception(exceptions.Exception):\n" + " _class = None\n" + " _inner = None\n" + " \n" + " #@property\n" + " def message(self):\n" + " return self.Message\n" + " message = property(message)\n" + " \n" + " def __init__(self, *args, **kw):\n" + " inst = self.__class__._class(*args, **kw)\n" + " self.__dict__['_inner'] = inst\n" + " exceptions.Exception.__init__(self, *args, **kw)\n" + "\n" + " def __getattr__(self, name, _marker=[]):\n" + " inner = self.__dict__['_inner']\n" + " v = getattr(inner, name, _marker)\n" + " if v is not _marker:\n" + " return v\n" + " v = self.__dict__.get(name, _marker)\n" + " if v is not _marker:\n" + " return v\n" + " raise AttributeError(name)\n" + "\n" + " def __setattr__(self, name, value):\n" + " inner = self.__dict__['_inner']\n" + " setattr(inner, name, value)\n" + "\n" + " def __str__(self):\n" + " inner = self.__dict__.get('_inner')\n" + " msg = getattr(inner, 'Message', '')\n" + " st = getattr(inner, 'StackTrace', '')\n" + " st = st and '\\n' + st or ''\n" + " return msg + st\n" + " \n" + " def __repr__(self):\n" + " inner = self.__dict__.get('_inner')\n" + " msg = getattr(inner, 'Message', '')\n" + " name = self.__class__.__name__\n" + " return '%s(\\'%s\\',)' % (name, msg) \n" + "\n"; IntPtr dict = Runtime.PyDict_New(); IntPtr builtins = Runtime.PyEval_GetBuiltins(); Runtime.PyDict_SetItemString(dict, "__builtins__", builtins); IntPtr namestr = Runtime.PyString_FromString("System"); Runtime.PyDict_SetItemString(dict, "__name__", namestr); Runtime.Decref(namestr); Runtime.PyDict_SetItemString(dict, "__file__", Runtime.PyNone); Runtime.PyDict_SetItemString(dict, "__doc__", Runtime.PyNone); IntPtr flag = Runtime.Py_file_input; IntPtr result = Runtime.PyRun_String(code, flag, dict, dict); Exceptions.ErrorCheck(result); Runtime.Decref(result); os_exc = Runtime.PyDict_GetItemString(dict, "Exception"); Runtime.PyObject_SetAttrString(os_exc, "_class", ns_exc); Runtime.PyErr_Clear(); }
/// <summary> /// Stores an attribute in the instance dict for future lookups. /// </summary> private void StoreAttribute(string name, ManagedType ob) { Runtime.PyDict_SetItemString(dict, name, ob.pyHandle); cache[name] = ob; }
/// <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> /// 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() { 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; Exceptions.Clear(); // 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"; PyObject r = PythonEngine.RunString(code); if (r != null) { r.Dispose(); } // Load the clr.py resource into the clr module IntPtr clr = Python.Runtime.ImportHook.GetCLRModule(); IntPtr clr_dict = Runtime.PyModule_GetDict(clr); PyDict 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); var assembly = Assembly.GetExecutingAssembly(); using (Stream stream = assembly.GetManifestResourceStream("clr.py")) using (StreamReader reader = new StreamReader(stream)) { // add the contents of clr.py to the module string clr_py = reader.ReadToEnd(); PyObject result = RunString(clr_py, module_globals, locals.Handle); if (null == result) { throw new PythonException(); } result.Dispose(); } // 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("_")) { PyObject value = locals[key]; Runtime.PyDict_SetItem(clr_dict, key.Handle, value.Handle); value.Dispose(); } key.Dispose(); } } finally { locals.Dispose(); } } }
/// <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(); } } }
private static void InitClassBase(Type type, ClassBase impl) { // First, we introspect the managed type and build some class // information, including generating the member descriptors // that we'll be putting in the Python class __dict__. ClassInfo info = GetClassInfo(type); impl.indexer = info.indexer; // Now we allocate the Python type object to reflect the given // managed type, filling the Python type slots with thunks that // point to the managed methods providing the implementation. IntPtr tp = TypeManager.GetTypeHandle(impl, type); impl.tpHandle = tp; // Finally, initialize the class __dict__ and return the object. IntPtr dict = Marshal.ReadIntPtr(tp, TypeOffset.tp_dict); IDictionaryEnumerator iter = info.members.GetEnumerator(); while (iter.MoveNext()) { ManagedType item = (ManagedType)iter.Value; string name = (string)iter.Key; Runtime.PyDict_SetItemString(dict, name, item.pyHandle); } // If class has constructors, generate an __doc__ attribute. IntPtr doc = IntPtr.Zero; Type marker = typeof(DocStringAttribute); Attribute[] attrs = (Attribute[])type.GetCustomAttributes(marker, false); if (attrs.Length == 0) { doc = IntPtr.Zero; } else { DocStringAttribute attr = (DocStringAttribute)attrs[0]; string docStr = attr.DocString; doc = Runtime.PyString_FromString(docStr); Runtime.PyDict_SetItemString(dict, "__doc__", doc); Runtime.Decref(doc); } ClassObject co = impl as ClassObject; // If this is a ClassObject AND it has constructors, generate a __doc__ attribute. // required that the ClassObject.ctors be changed to internal if (co != null) { if (co.ctors.Length > 0) { // Implement Overloads on the class object if (!CLRModule._SuppressOverloads) { ConstructorBinding ctors = new ConstructorBinding(type, tp, co.binder); // ExtensionType types are untracked, so don't Incref() them. // XXX deprecate __overloads__ soon... Runtime.PyDict_SetItemString(dict, "__overloads__", ctors.pyHandle); Runtime.PyDict_SetItemString(dict, "Overloads", ctors.pyHandle); } // don't generate the docstring if one was already set from a DocStringAttribute. if (!CLRModule._SuppressDocs && doc == IntPtr.Zero) { doc = co.GetDocString(); Runtime.PyDict_SetItemString(dict, "__doc__", doc); Runtime.Decref(doc); } } } }
/// <summary> /// The actual import hook that ties Python to the managed world. /// </summary> public static IntPtr __import__(IntPtr self, IntPtr args, IntPtr kw) { // Replacement for the builtin __import__. The original import // hook is saved as this.py_import. This version handles CLR // import and defers to the normal builtin for everything else. var num_args = Runtime.PyTuple_Size(args); if (num_args < 1) { return(Exceptions.RaiseTypeError("__import__() takes at least 1 argument (0 given)")); } // borrowed reference IntPtr py_mod_name = Runtime.PyTuple_GetItem(args, 0); if (py_mod_name == IntPtr.Zero || !Runtime.IsStringType(py_mod_name)) { return(Exceptions.RaiseTypeError("string expected")); } // Check whether the import is of the form 'from x import y'. // This determines whether we return the head or tail module. IntPtr fromList = IntPtr.Zero; var fromlist = false; if (num_args >= 4) { fromList = Runtime.PyTuple_GetItem(args, 3); if (fromList != IntPtr.Zero && Runtime.PyObject_IsTrue(fromList) == 1) { fromlist = true; } } string mod_name = Runtime.GetManagedString(py_mod_name); // Check these BEFORE the built-in import runs; may as well // do the Incref()ed return here, since we've already found // the module. if (mod_name == "clr") { IntPtr clr_module = GetCLRModule(fromList); if (clr_module != IntPtr.Zero) { IntPtr sys_modules = Runtime.PyImport_GetModuleDict(); if (sys_modules != IntPtr.Zero) { Runtime.PyDict_SetItemString(sys_modules, "clr", clr_module); } } return(clr_module); } string realname = mod_name; string clr_prefix = null; // 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); } // Save the exception var originalException = new PythonException(); // Otherwise, just clear the it. Exceptions.Clear(); string[] names = realname.Split('.'); // See if sys.modules for this interpreter already has the // requested module. If so, just return the existing module. 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)) { originalException.Restore(); return(IntPtr.Zero); } if (head == null) { head = (ModuleObject)mt; } tail = (ModuleObject)mt; if (CLRModule.preload) { tail.LoadNames(); } // Add the module to sys.modules Runtime.PyDict_SetItemString(modules, tail.moduleName, tail.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); } }
private static void InitClassBase(Type type, ClassBase impl) { // First, we introspect the managed type and build some class // information, including generating the member descriptors // that we'll be putting in the Python class __dict__. ClassInfo info = GetClassInfo(type); impl.indexer = info.indexer; impl.richcompare = new Dictionary <int, MethodObject>(); // Now we allocate the Python type object to reflect the given // managed type, filling the Python type slots with thunks that // point to the managed methods providing the implementation. IntPtr tp = TypeManager.GetTypeHandle(impl, type); // Finally, initialize the class __dict__ and return the object. var dict = new BorrowedReference(Marshal.ReadIntPtr(tp, TypeOffset.tp_dict)); if (impl.dotNetMembers == null) { impl.dotNetMembers = new List <string>(); } IDictionaryEnumerator iter = info.members.GetEnumerator(); while (iter.MoveNext()) { var item = (ManagedType)iter.Value; var name = (string)iter.Key; impl.dotNetMembers.Add(name); Runtime.PyDict_SetItemString(dict, name, item.ObjectReference); // Decref the item now that it's been used. item.DecrRefCount(); if (ClassBase.CilToPyOpMap.TryGetValue(name, out var pyOp)) { impl.richcompare.Add(pyOp, (MethodObject)item); } } // If class has constructors, generate an __doc__ attribute. NewReference doc = default; Type marker = typeof(DocStringAttribute); var attrs = (Attribute[])type.GetCustomAttributes(marker, false); if (attrs.Length != 0) { var attr = (DocStringAttribute)attrs[0]; string docStr = attr.DocString; doc = NewReference.DangerousFromPointer(Runtime.PyString_FromString(docStr)); Runtime.PyDict_SetItem(dict, PyIdentifier.__doc__, doc); } var co = impl as ClassObject; // If this is a ClassObject AND it has constructors, generate a __doc__ attribute. // required that the ClassObject.ctors be changed to internal if (co != null) { if (co.NumCtors > 0) { // Implement Overloads on the class object if (!CLRModule._SuppressOverloads) { var ctors = new ConstructorBinding(type, tp, co.binder); // ExtensionType types are untracked, so don't Incref() them. // TODO: deprecate __overloads__ soon... Runtime.PyDict_SetItem(dict, PyIdentifier.__overloads__, ctors.ObjectReference); Runtime.PyDict_SetItem(dict, PyIdentifier.Overloads, ctors.ObjectReference); ctors.DecrRefCount(); } // don't generate the docstring if one was already set from a DocStringAttribute. if (!CLRModule._SuppressDocs && doc.IsNull()) { doc = co.GetDocString(); Runtime.PyDict_SetItem(dict, PyIdentifier.__doc__, doc); } } } doc.Dispose(); // The type has been modified after PyType_Ready has been called // Refresh the type Runtime.PyType_Modified(tp); }
//==================================================================== // Create a new ClassBase-derived instance that implements a reflected // managed type. The new object will be associated with a generated // Python type object. //==================================================================== private static ClassBase CreateClass(Type type) { // First, we introspect the managed type and build some class // information, including generating the member descriptors // that we'll be putting in the Python class __dict__. ClassInfo info = GetClassInfo(type); // Next, select the appropriate managed implementation class. // Different kinds of types, such as array types or interface // types, want to vary certain implementation details to make // sure that the type semantics are consistent in Python. ClassBase impl; // Check to see if the given type extends System.Exception. This // lets us check once (vs. on every lookup) in case we need to // wrap Exception-derived types in old-style classes if (type.ContainsGenericParameters) { impl = new GenericType(type); } else if (type.IsSubclassOf(dtype)) { impl = new DelegateObject(type); } else if (type.IsArray) { impl = new ArrayObject(type); } else if (type.IsInterface) { impl = new InterfaceObject(type); } else if (type == typeof(Exception) || type.IsSubclassOf(typeof(Exception))) { impl = new ExceptionClassObject(type); } else { impl = new ClassObject(type); } impl.indexer = info.indexer; // Now we allocate the Python type object to reflect the given // managed type, filling the Python type slots with thunks that // point to the managed methods providing the implementation. IntPtr tp = TypeManager.GetTypeHandle(impl, type); impl.tpHandle = tp; // Finally, initialize the class __dict__ and return the object. IntPtr dict = Marshal.ReadIntPtr(tp, TypeOffset.tp_dict); IDictionaryEnumerator iter = info.members.GetEnumerator(); while (iter.MoveNext()) { ManagedType item = (ManagedType)iter.Value; string name = (string)iter.Key; Runtime.PyDict_SetItemString(dict, name, item.pyHandle); } // If class has constructors, generate an __doc__ attribute. IntPtr doc; Type marker = typeof(DocStringAttribute); Attribute[] attrs = (Attribute[])type.GetCustomAttributes(marker, false); if (attrs.Length == 0) { doc = IntPtr.Zero; } else { DocStringAttribute attr = (DocStringAttribute)attrs[0]; string docStr = attr.DocString; doc = Runtime.PyString_FromString(docStr); Runtime.PyDict_SetItemString(dict, "__doc__", doc); Runtime.Decref(doc); } ClassObject co = impl as ClassObject; // If this is a ClassObject AND it has constructors, generate a __doc__ attribute. // required that the ClassObject.ctors be changed to internal if (co != null) { if (co.ctors.Length > 0) { // Implement Overloads on the class object ConstructorBinding ctors = new ConstructorBinding(type, tp, co.binder); // ExtensionType types are untracked, so don't Incref() them. // XXX deprecate __overloads__ soon... Runtime.PyDict_SetItemString(dict, "__overloads__", ctors.pyHandle); Runtime.PyDict_SetItemString(dict, "Overloads", ctors.pyHandle); if (doc == IntPtr.Zero) { doc = co.GetDocString(); Runtime.PyDict_SetItemString(dict, "__doc__", doc); Runtime.Decref(doc); } } } return(impl); }
//=================================================================== // The actual import hook that ties Python to the managed world. //=================================================================== public static IntPtr __import__(IntPtr self, IntPtr args, IntPtr kw) { // Replacement for the builtin __import__. The original import // hook is saved as this.py_import. This version handles CLR // import and defers to the normal builtin for everything else. int num_args = Runtime.PyTuple_Size(args); if (num_args < 1) { return(Exceptions.RaiseTypeError( "__import__() takes at least 1 argument (0 given)" )); } // borrowed reference IntPtr py_mod_name = Runtime.PyTuple_GetItem(args, 0); if ((py_mod_name == IntPtr.Zero) || (!Runtime.IsStringType(py_mod_name))) { return(Exceptions.RaiseTypeError("string expected")); } // Check whether the import is of the form 'from x import y'. // This determines whether we return the head or tail module. IntPtr fromList = IntPtr.Zero; bool fromlist = false; if (num_args >= 4) { fromList = Runtime.PyTuple_GetItem(args, 3); if ((fromList != IntPtr.Zero) && (Runtime.PyObject_IsTrue(fromList) == 1)) { fromlist = true; } } string mod_name = Runtime.GetManagedString(py_mod_name); // Check these BEFORE the built-in import runs; may as well // do the Incref()ed return here, since we've already found // the module. if (mod_name == "clr") { root.InitializePreload(); Runtime.Incref(root.pyHandle); return(root.pyHandle); } if (mod_name == "CLR") { Exceptions.deprecation("The CLR module is deprecated. " + "Please use 'clr'."); root.InitializePreload(); Runtime.Incref(root.pyHandle); return(root.pyHandle); } string realname = mod_name; if (mod_name.StartsWith("CLR.")) { realname = mod_name.Substring(4); string msg = String.Format("Importing from the CLR.* namespace " + "is deprecated. Please import '{0}' directly.", realname); Exceptions.deprecation(msg); } else { // 2010-08-15: Always seemed smart to let python try first... // This shaves off a few tenths of a second on test_module.py // and works around a quirk where 'sys' is found by the // LoadImplicit() deprecation logic. // Turns out that the AssemblyManager.ResolveHandler() checks to see if any // Assembly's FullName.ToLower().StartsWith(name.ToLower()), which makes very // little sense to me. IntPtr res = Runtime.PyObject_Call(py_import, args, kw); if (res != IntPtr.Zero) { // There was no error. return(res); } // There was an error if (!Exceptions.ExceptionMatches(Exceptions.ImportError)) { // and it was NOT an ImportError; bail out here. return(IntPtr.Zero); } // Otherwise, just clear the it. Exceptions.Clear(); } string[] names = realname.Split('.'); // Now we need to decide if the name refers to a CLR module, // and may have to do an implicit load (for b/w compatibility) // using the AssemblyManager. The assembly manager tries // really hard not to use Python objects or APIs, because // parts of it can run recursively and on strange threads. // // It does need an opportunity from time to time to check to // see if sys.path has changed, in a context that is safe. Here // we know we have the GIL, so we'll let it update if needed. AssemblyManager.UpdatePath(); if (!AssemblyManager.IsValidNamespace(realname)) { if (!AssemblyManager.LoadImplicit(realname)) { // May be called when a module being imported imports a module. // In particular, I've seen decimal import copy import org.python.core return(Runtime.PyObject_Call(py_import, args, kw)); } } // See if sys.modules for this interpreter already has the // requested module. If so, just return the exising module. IntPtr modules = Runtime.PyImport_GetModuleDict(); IntPtr module = Runtime.PyDict_GetItem(modules, py_mod_name); if (module != IntPtr.Zero) { if (fromlist) { Runtime.Incref(module); return(module); } module = Runtime.PyDict_GetItemString(modules, names[0]); Runtime.Incref(module); return(module); } Exceptions.Clear(); // Traverse the qualified module name to get the named module // and place references in sys.modules as we go. Note that if // we are running in interactive mode we pre-load the names in // each module, which is often useful for introspection. If we // are not interactive, we stick to just-in-time creation of // objects at lookup time, which is much more efficient. // NEW: The clr got a new module variable preload. You can // enable preloading in a non-interactive python processing by // setting clr.preload = True ModuleObject head = (mod_name == realname) ? null : root; ModuleObject tail = root; root.InitializePreload(); for (int i = 0; i < names.Length; i++) { string name = names[i]; ManagedType mt = tail.GetAttribute(name, true); if (!(mt is ModuleObject)) { string error = String.Format("No module named {0}", name); Exceptions.SetError(Exceptions.ImportError, error); return(IntPtr.Zero); } if (head == null) { head = (ModuleObject)mt; } tail = (ModuleObject)mt; if (CLRModule.preload) { tail.LoadNames(); } Runtime.PyDict_SetItemString(modules, tail.moduleName, tail.pyHandle ); } ModuleObject mod = fromlist ? tail : head; if (fromlist && Runtime.PySequence_Size(fromList) == 1) { IntPtr fp = Runtime.PySequence_GetItem(fromList, 0); if ((!CLRModule.preload) && Runtime.GetManagedString(fp) == "*") { mod.LoadNames(); } Runtime.Decref(fp); } Runtime.Incref(mod.pyHandle); return(mod.pyHandle); }
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); }