fix PY-14649 Importing in debug mode fails; works fine in run mode
authorElizaveta Shashkova <Elizaveta.Shashkova@jetbrains.com>
Tue, 9 Dec 2014 16:15:54 +0000 (19:15 +0300)
committerElizaveta Shashkova <Elizaveta.Shashkova@jetbrains.com>
Tue, 9 Dec 2014 16:15:54 +0000 (19:15 +0300)
python/helpers/pydev/_pydev_imps/_pydev_django_oscar_patch.py [new file with mode: 0644]
python/helpers/pydev/_pydev_imps/_pydev_pluginbase.py
python/helpers/pydev/pydevd.py

diff --git a/python/helpers/pydev/_pydev_imps/_pydev_django_oscar_patch.py b/python/helpers/pydev/_pydev_imps/_pydev_django_oscar_patch.py
new file mode 100644 (file)
index 0000000..e0a82f7
--- /dev/null
@@ -0,0 +1,38 @@
+
+import sys
+import traceback
+
+
+def _import_module_patched(module_label, classnames):
+    """
+    Imports the module with the given name.
+    Returns None if the module doesn't exist, but propagates any import errors.
+    """
+    try:
+        return __import__(module_label, fromlist=classnames)
+    except ImportError:
+        # There are 2 reasons why there could be an ImportError:
+        #
+        #  1. Module does not exist. In that case, we ignore the import and
+        #     return None
+        #  2. Module exists but another ImportError occurred when trying to
+        #     import the module. In that case, it is important to propagate the
+        #     error.
+        #
+        # ImportError does not provide easy way to distinguish those two cases.
+        # Fortunately, the traceback of the ImportError starts at __import__
+        # statement. If the traceback has more than one frame, it means that
+        # application was found and ImportError originates within the local app
+        #
+        # Changes in patch: change 1 to 2 frames because of the frame, added by
+        # plugin_import.
+        #
+        __, __, exc_traceback = sys.exc_info()
+        frames = traceback.extract_tb(exc_traceback)
+        if len(frames) > 2:
+            raise
+
+
+def patch_oscar_loading():
+    module = sys.modules['oscar.core.loading']
+    setattr(module, '_import_module', _import_module_patched)
index f3c0a5fd533be92d83eb16e584df0a161136e920..dc1ab05907a126a8c8cd9724343282625617f858 100644 (file)
@@ -12,8 +12,7 @@
 import os
 import sys
 
-from pydevd_constants import IS_PY24, IS_PY3K, IS_JYTHON
-
+from pydevd_constants import IS_PY24, IS_PY3K, IS_JYTHON, DictContains, DictPop
 
 if IS_PY24:
     from _pydev_imps._pydev_uuid_old import uuid4
@@ -406,6 +405,16 @@ class _ImportHook(ModuleType):
         ModuleType.__init__(self, name)
         self._system_import = system_import
         self.enabled = True
+        self._modules_to_patch = {}
+        self._add_modules_for_patching()
+
+    def _add_modules_for_patching(self):
+        try:
+            from _pydev_imps._pydev_django_oscar_patch import \
+                patch_oscar_loading
+            self._modules_to_patch['oscar.core.loading'] = patch_oscar_loading
+        except:
+            sys.stderr.write("Adding modules to patch in pluginbase failed\n")
 
     def enable(self):
         """Enables the import hook which drives the plugin base system.
@@ -423,15 +432,19 @@ class _ImportHook(ModuleType):
     def plugin_import(self, name, globals=None, locals=None,
                       fromlist=None, level=-2):
         import_name = name
-        if self.enabled:
-            ref_globals = globals
-            if ref_globals is None:
-                ref_globals = sys._getframe(1).f_globals
-            space = _discover_space(name, ref_globals)
-            if space is not None:
-                actual_name = space._rewrite_module_path(name)
-                if actual_name is not None:
-                    import_name = actual_name
+        try:
+            if self.enabled:
+                ref_globals = globals
+                if ref_globals is None:
+                    ref_globals = sys._getframe(1).f_globals
+                space = _discover_space(name, ref_globals)
+                if space is not None:
+                    actual_name = space._rewrite_module_path(name)
+                    if actual_name is not None:
+                        import_name = actual_name
+        except:
+            sys.stderr.write("Failed to get import name for name %s\n" % name)
+
         if level == -2:
             # fake impossible value; default value depends on version
             if IS_PY24:
@@ -445,8 +458,18 @@ class _ImportHook(ModuleType):
                 level = -1
         if IS_JYTHON:
             import_name = name
-        return self._system_import(import_name, globals, locals,
-                                   fromlist, level)
+
+        activate_func = None
+        if name == import_name and DictContains(self._modules_to_patch, name):
+            activate_func = DictPop(self._modules_to_patch, name)
+
+        module = self._system_import(import_name, globals, locals, fromlist, level)
+        try:
+            if activate_func:
+                activate_func() #call activate function
+        except:
+            sys.stderr.write("Patching modules in pluginbase failed\n")
+        return module
 
 
 try:
index 954b072747a6ab3fb6261044bff7d1b191810db1..5aadbe1a19831fe6de3560fdfd69f0d02c925dc9 100644 (file)
@@ -122,7 +122,7 @@ DONT_TRACE = {
               '_pydev_pluginbase.py':1,
               '_pydev_pkgutil_old.py':1,
               '_pydev_uuid_old.py':1,
-
+              '_pydev_django_oscar_patch.py':1,
 
               #things from pydev that we don't want to trace
               '_pydev_execfile.py':1,