@@ -19,7 +19,7 @@ import sys
19
19
class DotNetLoader(importlib.abc.Loader):
20
20
21
21
def __init__(self):
22
- super(DotNetLoader, self ).__init__()
22
+ super().__init__()
23
23
24
24
@classmethod
25
25
def exec_module(klass, mod):
@@ -29,21 +29,19 @@ def exec_module(klass, mod):
29
29
@classmethod
30
30
def create_module(klass, spec):
31
31
import clr
32
- return clr._LoadClrModule (spec)
32
+ return clr._load_clr_module (spec)
33
33
34
34
class DotNetFinder(importlib.abc.MetaPathFinder):
35
35
36
36
def __init__(self):
37
- super(DotNetFinder, self ).__init__()
37
+ super().__init__()
38
38
39
39
@classmethod
40
40
def find_spec(klass, fullname, paths=None, target=None):
41
41
import clr
42
- if (hasattr( clr, ' _availableNamespaces') and fullname in clr._availableNamespaces) :
42
+ if clr. _availableNamespaces and fullname in clr._availableNamespaces:
43
43
return importlib.machinery.ModuleSpec(fullname, DotNetLoader(), is_package=True)
44
44
return None
45
-
46
- sys.meta_path.append(DotNetFinder())
47
45
" ;
48
46
const string availableNsKey = "_availableNamespaces" ;
49
47
@@ -69,7 +67,7 @@ internal static unsafe void Initialize()
69
67
70
68
// Add/create the MetaPathLoader
71
69
SetupNamespaceTracking ( ) ;
72
- PythonEngine . Exec ( LoaderCode ) ;
70
+ SetupImportHook ( ) ;
73
71
}
74
72
75
73
@@ -114,13 +112,66 @@ internal static void RestoreRuntimeData(RuntimeDataStorage storage)
114
112
SetupNamespaceTracking ( ) ;
115
113
}
116
114
115
+ static void SetupImportHook ( )
116
+ {
117
+ // 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 ) ;
120
+
121
+ // Run the python code to create the module's classes.
122
+ var mod_dict = Runtime . PyModule_GetDict ( new BorrowedReference ( import_hook_module ) ) ;
123
+ var builtins = Runtime . PyEval_GetBuiltins ( ) ;
124
+ var exec = Runtime . PyDict_GetItemString ( builtins , "exec" ) ;
125
+ using var args = NewReference . DangerousFromPointer ( Runtime . PyTuple_New ( 2 ) ) ;
126
+
127
+ var codeStr = Runtime . PyString_FromString ( LoaderCode ) ;
128
+ Runtime . PyTuple_SetItem ( args . DangerousGetAddress ( ) , 0 , codeStr ) ;
129
+ // PyTuple_SetItem steals a reference, mod_dict is borrowed.
130
+ Runtime . XIncref ( mod_dict . DangerousGetAddress ( ) ) ;
131
+ Runtime . PyTuple_SetItem ( args . DangerousGetAddress ( ) , 1 , mod_dict . DangerousGetAddress ( ) ) ;
132
+ Runtime . PyObject_Call ( exec . DangerousGetAddress ( ) , args . DangerousGetAddress ( ) , IntPtr . Zero ) ;
133
+
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
+ // 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 )
156
+ {
157
+ Runtime . XDecref ( import_hook_module ) ;
158
+ throw new PythonException ( ) ;
159
+ }
160
+
161
+ // Finally, add the hook to the meta path
162
+ var finder_inst = Runtime . PyDict_GetItemString ( mod_dict , "finder_inst" ) . DangerousGetAddressOrNull ( ) ;
163
+ Runtime . XIncref ( finder ) ;
164
+ var metapath = Runtime . PySys_GetObject ( "meta_path" ) ;
165
+ Runtime . PyList_Append ( metapath , finder ) ;
166
+ }
167
+
117
168
/// <summary>
118
169
/// Sets up the tracking of loaded namespaces. This makes available to
119
170
/// Python, as a Python object, the loaded namespaces. The set of loaded
120
171
/// namespaces is used during the import to verify if we can import a
121
172
/// CLR assembly as a module or not. The set is stored on the clr module.
122
173
/// </summary>
123
- static void SetupNamespaceTracking ( )
174
+ static void SetupNamespaceTracking ( )
124
175
{
125
176
var newset = Runtime . PySet_New ( new BorrowedReference ( IntPtr . Zero ) ) ;
126
177
try
@@ -130,7 +181,7 @@ static void SetupNamespaceTracking ()
130
181
var pyNs = Runtime . PyString_FromString ( ns ) ;
131
182
try
132
183
{
133
- if ( Runtime . PySet_Add ( newset , new BorrowedReference ( pyNs ) ) != 0 )
184
+ if ( Runtime . PySet_Add ( newset , new BorrowedReference ( pyNs ) ) != 0 )
134
185
{
135
186
throw new PythonException ( ) ;
136
187
}
@@ -141,7 +192,7 @@ static void SetupNamespaceTracking ()
141
192
}
142
193
}
143
194
144
- if ( Runtime . PyDict_SetItemString ( root . dict , availableNsKey , newset . DangerousGetAddress ( ) ) != 0 )
195
+ if ( Runtime . PyDict_SetItemString ( root . dict , availableNsKey , newset . DangerousGetAddress ( ) ) != 0 )
145
196
{
146
197
throw new PythonException ( ) ;
147
198
}
@@ -152,7 +203,7 @@ static void SetupNamespaceTracking ()
152
203
}
153
204
154
205
AssemblyManager . namespaceAdded += OnNamespaceAdded ;
155
- PythonEngine . AddShutdownHandler ( ( ) => AssemblyManager . namespaceAdded -= OnNamespaceAdded ) ;
206
+ PythonEngine . AddShutdownHandler ( ( ) => AssemblyManager . namespaceAdded -= OnNamespaceAdded ) ;
156
207
}
157
208
158
209
/// <summary>
@@ -162,27 +213,21 @@ static void SetupNamespaceTracking ()
162
213
static void TeardownNameSpaceTracking ( )
163
214
{
164
215
AssemblyManager . namespaceAdded -= OnNamespaceAdded ;
165
- // If the C# runtime isn't loaded, then there is no namespaces available
166
- if ( ( Runtime . PyDict_DelItemString ( new BorrowedReference ( root . dict ) , availableNsKey ) != 0 ) &&
167
- ( Exceptions . ExceptionMatches ( Exceptions . KeyError ) ) )
168
- {
169
- // Trying to remove a key that's not in the dictionary
170
- // raises an error. We don't care about it.
171
- Runtime . PyErr_Clear ( ) ;
172
- }
216
+ // If the C# runtime isn't loaded, then there are no namespaces available
217
+ Runtime . PyDict_SetItemString ( root . dict , availableNsKey , Runtime . PyNone ) ;
173
218
}
174
219
175
- static void OnNamespaceAdded ( string name )
220
+ static void OnNamespaceAdded ( string name )
176
221
{
177
- using ( Py . GIL ( ) )
222
+ using ( Py . GIL ( ) )
178
223
{
179
224
var pyNs = Runtime . PyString_FromString ( name ) ;
180
225
try
181
226
{
182
227
var nsSet = Runtime . PyDict_GetItemString ( new BorrowedReference ( root . dict ) , availableNsKey ) ;
183
- if ( ! nsSet . IsNull )
228
+ if ( ! nsSet . IsNull || nsSet . DangerousGetAddress ( ) != Runtime . PyNone )
184
229
{
185
- if ( Runtime . PySet_Add ( nsSet , new BorrowedReference ( pyNs ) ) != 0 )
230
+ if ( Runtime . PySet_Add ( nsSet , new BorrowedReference ( pyNs ) ) != 0 )
186
231
{
187
232
throw new PythonException ( ) ;
188
233
}
@@ -225,7 +270,7 @@ public static unsafe NewReference GetCLRModule()
225
270
/// <summary>
226
271
/// The hook to import a CLR module into Python
227
272
/// </summary>
228
- public static ModuleObject __import__ ( string modname )
273
+ public static ModuleObject Import ( string modname )
229
274
{
230
275
// Traverse the qualified module name to get the named module.
231
276
// Note that if
0 commit comments