@@ -26,25 +26,64 @@ internal static void InitializeModuleDef()
2626#endif
2727
2828 /// <summary>
29- /// Initialization performed on startup of the Python runtime .
29+ /// Get a <i>New reference</i> to the builtins module .
3030 /// </summary>
31- internal static void Initialize ( )
31+ static IntPtr GetNewRefToBuiltins ( )
3232 {
33- // Initialize the Python <--> CLR module hook. We replace the
34- // built-in Python __import__ with our own. This isn't ideal,
35- // but it provides the most "Pythonic" way of dealing with CLR
36- // modules (Python doesn't provide a way to emulate packages).
37- IntPtr dict = Runtime . PyImport_GetModuleDict ( ) ;
33+ if ( Runtime . IsPython3 )
34+ {
35+ return Runtime . PyImport_ImportModule ( "builtins" ) ;
36+ }
37+ else
38+ {
39+ // dict is a borrowed ref, no need to decref
40+ IntPtr dict = Runtime . PyImport_GetModuleDict ( ) ;
3841
39- IntPtr mod = Runtime . IsPython3
40- ? Runtime . PyImport_ImportModule ( "builtins" )
41- : Runtime . PyDict_GetItemString ( dict , "__builtin__" ) ;
42+ // GetItemString is a borrowed ref; incref to get a new ref
43+ IntPtr builtins = Runtime . PyDict_GetItemString ( dict , "__builtin__" ) ;
44+ Runtime . XIncref ( builtins ) ;
45+ return builtins ;
46+ }
47+ }
4248
43- py_import = Runtime . PyObject_GetAttrString ( mod , "__import__" ) ;
49+ /// <summary>
50+ /// Initialize just the __import__ hook itself.
51+ /// </summary>
52+ static void InitImport ( )
53+ {
54+ // We replace the built-in Python __import__ with our own: first
55+ // look in CLR modules, then if we don't find any call the default
56+ // Python __import__.
57+ IntPtr builtins = GetNewRefToBuiltins ( ) ;
58+ py_import = Runtime . PyObject_GetAttrString ( builtins , "__import__" ) ;
4459 hook = new MethodWrapper ( typeof ( ImportHook ) , "__import__" , "TernaryFunc" ) ;
45- Runtime . PyObject_SetAttrString ( mod , "__import__" , hook . ptr ) ;
60+ Runtime . PyObject_SetAttrString ( builtins , "__import__" , hook . ptr ) ;
4661 Runtime . XDecref ( hook . ptr ) ;
62+ Runtime . XDecref ( builtins ) ;
63+ }
64+
65+ /// <summary>
66+ /// Restore the __import__ hook.
67+ /// </summary>
68+ static void RestoreImport ( )
69+ {
70+ IntPtr builtins = GetNewRefToBuiltins ( ) ;
71+
72+ Runtime . PyObject_SetAttrString ( builtins , "__import__" , py_import ) ;
73+ Runtime . XDecref ( py_import ) ;
74+ py_import = IntPtr . Zero ;
75+
76+ Runtime . XDecref ( builtins ) ;
77+ }
78+
79+ /// <summary>
80+ /// Initialization performed on startup of the Python runtime.
81+ /// </summary>
82+ internal static void Initialize ( )
83+ {
84+ InitImport ( ) ;
4785
86+ // Initialize the clr module and tell Python about it.
4887 root = new CLRModule ( ) ;
4988
5089#if PYTHON3
@@ -62,6 +101,7 @@ internal static void Initialize()
62101 Runtime . XIncref ( root . pyHandle ) ; // we are using the module two times
63102 py_clr_module = root . pyHandle ; // Alias handle for PY2/PY3
64103#endif
104+ IntPtr dict = Runtime . PyImport_GetModuleDict ( ) ;
65105 Runtime . PyDict_SetItemString ( dict , "CLR" , py_clr_module ) ;
66106 Runtime . PyDict_SetItemString ( dict , "clr" , py_clr_module ) ;
67107 }
@@ -74,9 +114,10 @@ internal static void Shutdown()
74114 {
75115 if ( Runtime . Py_IsInitialized ( ) != 0 )
76116 {
117+ RestoreImport ( ) ;
118+
77119 Runtime . XDecref ( py_clr_module ) ;
78120 Runtime . XDecref ( root . pyHandle ) ;
79- Runtime . XDecref ( py_import ) ;
80121 }
81122 }
82123
0 commit comments