diff --git a/src/runtime/importhook.cs b/src/runtime/importhook.cs
index 7e4a208f5..06ba7a56d 100644
--- a/src/runtime/importhook.cs
+++ b/src/runtime/importhook.cs
@@ -26,25 +26,64 @@ internal static void InitializeModuleDef()
#endif
///
- /// Initialization performed on startup of the Python runtime.
+ /// Get a New reference to the builtins module.
///
- internal static void Initialize()
+ static IntPtr GetNewRefToBuiltins()
{
- // Initialize the Python <--> CLR module hook. We replace the
- // built-in Python __import__ with our own. This isn't ideal,
- // but it provides the most "Pythonic" way of dealing with CLR
- // modules (Python doesn't provide a way to emulate packages).
- IntPtr dict = Runtime.PyImport_GetModuleDict();
+ if (Runtime.IsPython3)
+ {
+ return Runtime.PyImport_ImportModule("builtins");
+ }
+ else
+ {
+ // dict is a borrowed ref, no need to decref
+ IntPtr dict = Runtime.PyImport_GetModuleDict();
- IntPtr mod = Runtime.IsPython3
- ? Runtime.PyImport_ImportModule("builtins")
- : Runtime.PyDict_GetItemString(dict, "__builtin__");
+ // GetItemString is a borrowed ref; incref to get a new ref
+ IntPtr builtins = Runtime.PyDict_GetItemString(dict, "__builtin__");
+ Runtime.XIncref(builtins);
+ return builtins;
+ }
+ }
- py_import = Runtime.PyObject_GetAttrString(mod, "__import__");
+ ///
+ /// Initialize just the __import__ hook itself.
+ ///
+ static void InitImport()
+ {
+ // We replace the built-in Python __import__ with our own: first
+ // look in CLR modules, then if we don't find any call the default
+ // Python __import__.
+ IntPtr builtins = GetNewRefToBuiltins();
+ py_import = Runtime.PyObject_GetAttrString(builtins, "__import__");
hook = new MethodWrapper(typeof(ImportHook), "__import__", "TernaryFunc");
- Runtime.PyObject_SetAttrString(mod, "__import__", hook.ptr);
+ Runtime.PyObject_SetAttrString(builtins, "__import__", hook.ptr);
Runtime.XDecref(hook.ptr);
+ Runtime.XDecref(builtins);
+ }
+
+ ///
+ /// Restore the __import__ hook.
+ ///
+ static void RestoreImport()
+ {
+ IntPtr builtins = GetNewRefToBuiltins();
+
+ Runtime.PyObject_SetAttrString(builtins, "__import__", py_import);
+ Runtime.XDecref(py_import);
+ py_import = IntPtr.Zero;
+
+ Runtime.XDecref(builtins);
+ }
+
+ ///
+ /// Initialization performed on startup of the Python runtime.
+ ///
+ internal static void Initialize()
+ {
+ InitImport();
+ // Initialize the clr module and tell Python about it.
root = new CLRModule();
#if PYTHON3
@@ -62,6 +101,7 @@ internal static void Initialize()
Runtime.XIncref(root.pyHandle); // we are using the module two times
py_clr_module = root.pyHandle; // Alias handle for PY2/PY3
#endif
+ IntPtr dict = Runtime.PyImport_GetModuleDict();
Runtime.PyDict_SetItemString(dict, "CLR", py_clr_module);
Runtime.PyDict_SetItemString(dict, "clr", py_clr_module);
}
@@ -74,9 +114,10 @@ internal static void Shutdown()
{
if (Runtime.Py_IsInitialized() != 0)
{
+ RestoreImport();
+
Runtime.XDecref(py_clr_module);
Runtime.XDecref(root.pyHandle);
- Runtime.XDecref(py_import);
}
}