Browse Source

Workaround for weird import bug in Python3.2

Ask Solem 11 years ago
parent
commit
4479c561ff
1 changed files with 59 additions and 1 deletions
  1. 59 1
      celery/__init__.py

+ 59 - 1
celery/__init__.py

@@ -25,8 +25,8 @@ VERSION_BANNER = '{0} ({1})'.format(__version__, SERIES)
 # -eof meta-
 
 import os
+import sys
 if os.environ.get('C_IMPDEBUG'):  # pragma: no cover
-    import sys
     from .five import builtins
     real_import = builtins.__import__
 
@@ -74,3 +74,61 @@ old_module, new_module = recreate_module(  # pragma: no cover
     __homepage__=__homepage__, __docformat__=__docformat__,
     VERSION=VERSION, SERIES=SERIES, VERSION_BANNER=VERSION_BANNER,
 )
+
+
+if sys.version_info[0:2] == (3, 2):
+    # There is a problem in Python3's import system where it
+    # returns the raw module object instead of the one
+    # kept in ``sys.modules``.
+
+    # This breaks our dynamically generated modules because we insert
+    # them into sys.modules, and expect the import statement to return
+    # that.
+
+    # I'm not entirely sure of why, or when it happens, but this import hook
+    # fixes the problem.  The bug can be reproduced by disabling the hook
+    # and doing the following:
+    #
+    #   >>> import celery
+    #   >>> from celery.task import sets
+    #   >>> from celery import task
+    #   >>> type(celery.task)
+    #   <class 'celery.task'>
+    #   >>> import sys
+    #   >>> import celery
+    #   >>> sys.modules.pop('celery.task')
+    #   <module 'celery.task' from 'celery/task/__init__.py'>
+    #   >>> from celery.task import sets
+    #   Traceback (most recent call last):
+    #     File "<stdin>", line 1, in <module>
+    #   ImportError: cannot import name sets
+    #   >>> type(celery.task)
+    #   <class 'module'>      # <-- where did this come from?!?
+
+    # Note that popping the module from sys.modules is just a way to force
+    # this to happen and I'm sure it happens in other cases too.
+
+    # [ask]
+
+    import imp
+
+    class FixBrokenImportHook(object):
+        generated_modules = ('celery', 'celery.task')
+
+        def load_module(self, name, *args):
+            try:
+                return sys.modules[name]
+            except KeyError:
+                modname, path = name, None
+                if '.' in name:
+                    modname, path = name.split('.')[-1], __path__
+                module_info = imp.find_module(modname, path)
+                module = imp.load_module(name, *module_info)
+                return sys.modules[name]
+
+        def find_module(self, name, path):
+            if name in self.generated_modules:
+                return self
+            return None
+
+    sys.meta_path.insert(0, FixBrokenImportHook())