| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent bb490bf commit 31ea876
6 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -202,6 +202,14 @@ internal static IntPtr ToPython(object value, Type type) | |||
| 202 | 202 | return ClassDerivedObject.ToPython(pyderived); | |
| 203 | 203 | } | |
| 204 | 204 | ||
| 205 | + // ModuleObjects are created in a way that their wrapping them as | ||
| 206 | + // a CLRObject fails, the ClassObject has no tpHandle. Return the | ||
| 207 | + // pyHandle as is, do not convert. | ||
| 208 | + if (value is ModuleObject modobj) | ||
| 209 | + { | ||
| 210 | + return modobj.pyHandle; | ||
| 211 | + } | ||
| 212 | + | ||
| 205 | 213 | // hmm - from Python, we almost never care what the declared | |
| 206 | 214 | // type is. we'd rather have the object bound to the actual | |
| 207 | 215 | // implementing class. | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1,4 +1,5 @@ | |||
| 1 | 1 | using System; | |
| 2 | + using System.Collections.Generic; | ||
| 2 | 3 | using System.Runtime.InteropServices; | |
| 3 | 4 | ||
| 4 | 5 | namespace Python.Runtime | |
@@ -18,9 +19,6 @@ import sys | |||
| 18 | 19 | ||
| 19 | 20 | class DotNetLoader(importlib.abc.Loader): | |
| 20 | 21 | ||
| 21 | - def __init__(self): | ||
| 22 | - super().__init__() | ||
| 23 | - | ||
| 24 | 22 | @classmethod | |
| 25 | 23 | def exec_module(klass, mod): | |
| 26 | 24 | # This method needs to exist. | |
@@ -32,13 +30,13 @@ import clr | |||
| 32 | 30 | return clr._load_clr_module(spec) | |
| 33 | 31 | ||
| 34 | 32 | class DotNetFinder(importlib.abc.MetaPathFinder): | |
| 35 | - | ||
| 36 | - def __init__(self): | ||
| 37 | - super().__init__() | ||
| 38 | - | ||
| 33 | + | ||
| 39 | 34 | @classmethod | |
| 40 | 35 | def find_spec(klass, fullname, paths=None, target=None): | |
| 41 | - import clr | ||
| 36 | + # Don't import, we might call ourselves recursively! | ||
| 37 | + if 'clr' not in sys.modules: | ||
| 38 | + return None | ||
| 39 | + clr = sys.modules['clr'] | ||
| 42 | 40 | if clr._available_namespaces and fullname in clr._available_namespaces: | |
| 43 | 41 | return importlib.machinery.ModuleSpec(fullname, DotNetLoader(), is_package=True) | |
| 44 | 42 | return None | |
@@ -64,13 +62,10 @@ internal static unsafe void Initialize() | |||
| 64 | 62 | BorrowedReference dict = Runtime.PyImport_GetModuleDict(); | |
| 65 | 63 | Runtime.PyDict_SetItemString(dict, "CLR", ClrModuleReference); | |
| 66 | 64 | Runtime.PyDict_SetItemString(dict, "clr", ClrModuleReference); | |
| 67 | - | ||
| 68 | - // Add/create the MetaPathLoader | ||
| 69 | 65 | SetupNamespaceTracking(); | |
| 70 | 66 | SetupImportHook(); | |
| 71 | 67 | } | |
| 72 | 68 | ||
| 73 | - | ||
| 74 | 69 | /// <summary> | |
| 75 | 70 | /// Cleanup resources upon shutdown of the Python runtime. | |
| 76 | 71 | /// </summary> | |
@@ -81,11 +76,10 @@ internal static void Shutdown() | |||
| 81 | 76 | return; | |
| 82 | 77 | } | |
| 83 | 78 | ||
| 84 | - bool shouldFreeDef = Runtime.Refcount(py_clr_module) == 1; | ||
| 79 | + TeardownNameSpaceTracking(); | ||
| 85 | 80 | Runtime.XDecref(py_clr_module); | |
| 86 | 81 | py_clr_module = IntPtr.Zero; | |
| 87 | 82 | ||
| 88 | - TeardownNameSpaceTracking(); | ||
| 89 | 83 | Runtime.XDecref(root.pyHandle); | |
| 90 | 84 | root = null; | |
| 91 | 85 | CLRModule.Reset(); | |
@@ -107,62 +101,42 @@ internal static void RestoreRuntimeData(RuntimeDataStorage storage) | |||
| 107 | 101 | var rootHandle = storage.GetValue<IntPtr>("root"); | |
| 108 | 102 | root = (CLRModule)ManagedType.GetManagedObject(rootHandle); | |
| 109 | 103 | BorrowedReference dict = Runtime.PyImport_GetModuleDict(); | |
| 110 | - Runtime.PyDict_SetItemString(dict.DangerousGetAddress(), "CLR", py_clr_module); | ||
| 111 | 104 | Runtime.PyDict_SetItemString(dict.DangerousGetAddress(), "clr", py_clr_module); | |
| 112 | 105 | SetupNamespaceTracking(); | |
| 113 | 106 | } | |
| 114 | 107 | ||
| 115 | 108 | static void SetupImportHook() | |
| 116 | 109 | { | |
| 117 | 110 | // Create the import hook module | |
| 118 | - var import_hook_module_def = ModuleDefOffset.AllocModuleDef("clr.loader"); | ||
| 119 | - var import_hook_module = Runtime.PyModule_Create2(import_hook_module_def, 3); | ||
| 111 | + var import_hook_module = Runtime.PyModule_New("clr.loader"); | ||
| 120 | 112 | ||
| 121 | 113 | // Run the python code to create the module's classes. | |
| 122 | - var mod_dict = Runtime.PyModule_GetDict(new BorrowedReference(import_hook_module)); | ||
| 123 | 114 | var builtins = Runtime.PyEval_GetBuiltins(); | |
| 124 | 115 | var exec = Runtime.PyDict_GetItemString(builtins, "exec"); | |
| 125 | 116 | using var args = NewReference.DangerousFromPointer(Runtime.PyTuple_New(2)); | |
| 126 | 117 | ||
| 127 | - var codeStr = Runtime.PyString_FromString(LoaderCode); | ||
| 118 | + IntPtr codeStr = Runtime.PyString_FromString(LoaderCode); | ||
| 128 | 119 | Runtime.PyTuple_SetItem(args.DangerousGetAddress(), 0, codeStr); | |
| 129 | 120 | // PyTuple_SetItem steals a reference, mod_dict is borrowed. | |
| 121 | + var mod_dict = Runtime.PyModule_GetDict(import_hook_module); | ||
| 130 | 122 | Runtime.XIncref(mod_dict.DangerousGetAddress()); | |
| 131 | 123 | Runtime.PyTuple_SetItem(args.DangerousGetAddress(), 1, mod_dict.DangerousGetAddress()); | |
| 132 | 124 | Runtime.PyObject_Call(exec.DangerousGetAddress(), args.DangerousGetAddress(), IntPtr.Zero); | |
| 133 | 125 | ||
| 134 | - var loader = Runtime.PyDict_GetItemString(mod_dict, "DotNetLoader").DangerousGetAddressOrNull(); | ||
| 135 | - Runtime.XIncref(loader); | ||
| 136 | - | ||
| 137 | - // Add the classes to the module | ||
| 138 | - // PyModule_AddObject steals a reference only on success | ||
| 139 | - if (Runtime.PyModule_AddObject(import_hook_module, "DotNetLoader", loader) != 0) | ||
| 140 | - { | ||
| 141 | - Runtime.XDecref(loader); | ||
| 142 | - throw new PythonException(); | ||
| 143 | - } | ||
| 144 | - | ||
| 145 | - var finder = Runtime.PyDict_GetItemString(mod_dict, "DotNetFinder").DangerousGetAddressOrNull(); | ||
| 146 | - Runtime.XIncref(finder); | ||
| 147 | - if (Runtime.PyModule_AddObject(import_hook_module, "DotNetFinder", finder) != 0) | ||
| 148 | - { | ||
| 149 | - Runtime.XDecref(finder); | ||
| 150 | - throw new PythonException(); | ||
| 151 | - } | ||
| 152 | - | ||
| 153 | 126 | // Set as a sub-module of clr. | |
| 154 | - Runtime.XIncref(import_hook_module); | ||
| 155 | - if(Runtime.PyModule_AddObject(py_clr_module, "loader", import_hook_module) != 0) | ||
| 127 | + if(Runtime.PyModule_AddObject(ClrModuleReference, "loader", import_hook_module) != 0) | ||
| 156 | 128 | { | |
| 157 | - Runtime.XDecref(import_hook_module); | ||
| 129 | + Runtime.XDecref(import_hook_module.DangerousGetAddress()); | ||
| 158 | 130 | throw new PythonException(); | |
| 159 | 131 | } | |
| 160 | 132 | ||
| 161 | 133 | // Finally, add the hook to the meta path | |
| 162 | - var finder_inst = Runtime.PyDict_GetItemString(mod_dict, "finder_inst").DangerousGetAddressOrNull(); | ||
| 163 | - Runtime.XIncref(finder); | ||
| 134 | + var findercls = Runtime.PyDict_GetItemString(mod_dict, "DotNetFinder"); | ||
| 135 | + var finderCtorArgs = Runtime.PyTuple_New(0); | ||
| 136 | + var finder_inst = Runtime.PyObject_CallObject(findercls.DangerousGetAddress(), finderCtorArgs); | ||
| 137 | + Runtime.XDecref(finderCtorArgs); | ||
| 164 | 138 | var metapath = Runtime.PySys_GetObject("meta_path"); | |
| 165 | - Runtime.PyList_Append(metapath, finder); | ||
| 139 | + Runtime.PyList_Append(metapath, finder_inst); | ||
| 166 | 140 | } | |
| 167 | 141 | ||
| 168 | 142 | /// <summary> | |
@@ -268,7 +242,8 @@ public static unsafe NewReference GetCLRModule() | |||
| 268 | 242 | } | |
| 269 | 243 | ||
| 270 | 244 | /// <summary> | |
| 271 | - /// The hook to import a CLR module into Python | ||
| 245 | + /// The hook to import a CLR module into Python. Returns a new reference | ||
| 246 | + /// to the module. | ||
| 272 | 247 | /// </summary> | |
| 273 | 248 | public static ModuleObject Import(string modname) | |
| 274 | 249 | { | |
@@ -305,7 +280,7 @@ public static ModuleObject Import(string modname) | |||
| 305 | 280 | tail.LoadNames(); | |
| 306 | 281 | } | |
| 307 | 282 | } | |
| 308 | - | ||
| 283 | + tail.IncrRefCount(); | ||
| 309 | 284 | return tail; | |
| 310 | 285 | } | |
| 311 | 286 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -53,7 +53,7 @@ public ModuleObject(string name) | |||
| 53 | 53 | var dictRef = Runtime.PyObject_GenericGetDict(ObjectReference); | |
| 54 | 54 | PythonException.ThrowIfIsNull(dictRef); | |
| 55 | 55 | dict = dictRef.DangerousMoveToPointer(); | |
| 56 | - | ||
| 56 | + __all__ = Runtime.PyList_New(0); | ||
| 57 | 57 | using var pyname = NewReference.DangerousFromPointer(Runtime.PyString_FromString(moduleName)); | |
| 58 | 58 | using var pyfilename = NewReference.DangerousFromPointer(Runtime.PyString_FromString(filename)); | |
| 59 | 59 | using var pydocstring = NewReference.DangerousFromPointer(Runtime.PyString_FromString(docstring)); | |
@@ -576,13 +576,6 @@ public static string[] ListAssemblies(bool verbose) | |||
| 576 | 576 | return names; | |
| 577 | 577 | } | |
| 578 | 578 | ||
| 579 | - [ModuleFunction] | ||
| 580 | - public static int _AtExit() | ||
| 581 | - { | ||
| 582 | - return Runtime.AtExit(); | ||
| 583 | - } | ||
| 584 | - | ||
| 585 | - | ||
| 586 | 579 | /// <summary> | |
| 587 | 580 | /// Note: This should *not* be called directly. | |
| 588 | 581 | /// The function that get/import a CLR assembly as a python module. | |
@@ -593,16 +586,14 @@ public static int _AtExit() | |||
| 593 | 586 | /// <returns>A new reference to the imported module, as a PyObject.</returns> | |
| 594 | 587 | [ModuleFunction] | |
| 595 | 588 | [ForbidPythonThreads] | |
| 596 | - public static PyObject _load_clr_module(PyObject spec) | ||
| 589 | + public static ModuleObject _load_clr_module(PyObject spec) | ||
| 597 | 590 | { | |
| 598 | 591 | ModuleObject mod = null; | |
| 599 | 592 | using (var modname = spec.GetAttr("name")) | |
| 600 | 593 | { | |
| 601 | 594 | mod = ImportHook.Import(modname.ToString()); | |
| 602 | 595 | } | |
| 603 | - // We can't return directly a ModuleObject, because the tpHandle is | ||
| 604 | - // not set, but we can return a PyObject. | ||
| 605 | - return new PyObject(mod.pyHandle); | ||
| 596 | + return mod; | ||
| 606 | 597 | } | |
| 607 | 598 | } | |
| 608 | 599 | } | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1944,7 +1944,7 @@ internal static string PyModule_GetFilename(IntPtr module) | |||
| 1944 | 1944 | ||
| 1945 | 1945 | ||
| 1946 | 1946 | internal static IntPtr PyImport_Import(IntPtr name) => Delegates.PyImport_Import(name); | |
| 1947 | - internal static int PyModule_AddObject(IntPtr module, string name, IntPtr stolenObject) | ||
| 1947 | + internal static int PyModule_AddObject(BorrowedReference module, string name, BorrowedReference stolenObject) | ||
| 1948 | 1948 | { | |
| 1949 | 1949 | using var namePtr = new StrPtr(name, Encoding.UTF8); | |
| 1950 | 1950 | return Delegates.PyModule_AddObject(module, namePtr, stolenObject); | |
@@ -2507,7 +2507,7 @@ static Delegates() | |||
| 2507 | 2507 | { | |
| 2508 | 2508 | PyModule_Create2 = (delegate* unmanaged[Cdecl]<IntPtr, int, IntPtr>)GetFunctionByName("PyModule_Create2TraceRefs", GetUnmanagedDll(_PythonDll)); | |
| 2509 | 2509 | } | |
| 2510 | - PyModule_AddObject = (delegate* unmanaged[Cdecl]<IntPtr, StrPtr, IntPtr, int>)GetFunctionByName(nameof(PyModule_AddObject), GetUnmanagedDll(_PythonDll)); | ||
| 2510 | + PyModule_AddObject = (delegate* unmanaged[Cdecl]<BorrowedReference, StrPtr, BorrowedReference, int>)GetFunctionByName(nameof(PyModule_AddObject), GetUnmanagedDll(_PythonDll)); | ||
| 2511 | 2511 | PyImport_Import = (delegate* unmanaged[Cdecl]<IntPtr, IntPtr>)GetFunctionByName(nameof(PyImport_Import), GetUnmanagedDll(_PythonDll)); | |
| 2512 | 2512 | PyImport_ImportModule = (delegate* unmanaged[Cdecl]<StrPtr, NewReference>)GetFunctionByName(nameof(PyImport_ImportModule), GetUnmanagedDll(_PythonDll)); | |
| 2513 | 2513 | PyImport_ReloadModule = (delegate* unmanaged[Cdecl]<BorrowedReference, NewReference>)GetFunctionByName(nameof(PyImport_ReloadModule), GetUnmanagedDll(_PythonDll)); | |
@@ -2797,7 +2797,7 @@ static Delegates() | |||
| 2797 | 2797 | internal static delegate* unmanaged[Cdecl]<BorrowedReference, BorrowedReference> PyModule_GetDict { get; } | |
| 2798 | 2798 | internal static delegate* unmanaged[Cdecl]<IntPtr, StrPtr> PyModule_GetFilename { get; } | |
| 2799 | 2799 | internal static delegate* unmanaged[Cdecl]<IntPtr, int, IntPtr> PyModule_Create2 { get; } | |
| 2800 | - internal static delegate* unmanaged[Cdecl]<IntPtr, StrPtr, IntPtr, int> PyModule_AddObject { get; } | ||
| 2800 | + internal static delegate* unmanaged[Cdecl]<BorrowedReference, StrPtr, BorrowedReference, int> PyModule_AddObject { get; } | ||
| 2801 | 2801 | internal static delegate* unmanaged[Cdecl]<IntPtr, IntPtr> PyImport_Import { get; } | |
| 2802 | 2802 | internal static delegate* unmanaged[Cdecl]<StrPtr, NewReference> PyImport_ImportModule { get; } | |
| 2803 | 2803 | internal static delegate* unmanaged[Cdecl]<BorrowedReference, NewReference> PyImport_ReloadModule { get; } | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -30,6 +30,11 @@ namespace Python.DomainReloadTests | |||
| 30 | 30 | /// which test case to run. That's because pytest assumes we'll run | |
| 31 | 31 | /// everything in one process, but we really want a clean process on each | |
| 32 | 32 | /// test case to test the init/reload/teardown parts of the domain reload. | |
| 33 | + /// | ||
| 34 | + /// ### Debugging tips: ### | ||
| 35 | + /// * Running pytest with the `-s` argument prevents stdout capture by pytest | ||
| 36 | + /// * Add a sleep into the python test case before the crash/failure, then while | ||
| 37 | + /// sleeping, attach the debugger to the Python.TestDomainReload.exe process. | ||
| 33 | 38 | /// </summary> | |
| 34 | 39 | /// | |
| 35 | 40 | class TestRunner | |
@@ -1287,7 +1292,13 @@ static string CreateAssembly(string name, string code, bool exe = false) | |||
| 1287 | 1292 | } | |
| 1288 | 1293 | parameters.ReferencedAssemblies.Add(netstandard); | |
| 1289 | 1294 | parameters.ReferencedAssemblies.Add(PythonDllLocation); | |
| 1290 | - CompilerResults results = provider.CompileAssemblyFromSource(parameters, code); | ||
| 1295 | + // Write code to file so it can debugged. | ||
| 1296 | + var sourcePath = Path.Combine(TestPath, name+"_source.cs"); | ||
| 1297 | + using(var file = new StreamWriter(sourcePath)) | ||
| 1298 | + { | ||
| 1299 | + file.Write(code); | ||
| 1300 | + } | ||
| 1301 | + CompilerResults results = provider.CompileAssemblyFromFile(parameters, sourcePath); | ||
| 1291 | 1302 | if (results.NativeCompilerReturnValue != 0) | |
| 1292 | 1303 | { | |
| 1293 | 1304 | var stderr = System.Console.Error; | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -89,6 +89,5 @@ def test_in_to_ref_param(): | |||
| 89 | 89 | def test_nested_type(): | |
| 90 | 90 | _run_test("nested_type") | |
| 91 | 91 | ||
| 92 | - @pytest.mark.skipif(platform.system() == 'Darwin', reason='FIXME: macos can\'t find the python library') | ||
| 93 | 92 | def test_import_after_reload(): | |
| 94 | 93 | _run_test("import_after_reload") | |
| Back | FazBrowse Home | New Git URL |
0 commit comments