changeset 27536:f7d890bc5e01

demandimport: add support for PyPy PyPy's implementation of __import__ differs subtly from that of CPython. If invoked without a name or fromlist, it throws an ImportError, whereas CPython returns a reference to the level-appropriate importing package. Here, we achieve the same behaviour by hand.
author Bryan O'Sullivan <bos@serpentine.com>
date Wed, 23 Dec 2015 16:22:20 -0800
parents 0d0f4070f6d7
children ffb1ab1e4bba
files mercurial/demandimport.py
diffstat 1 files changed, 17 insertions(+), 5 deletions(-) [+]
line wrap: on
line diff
--- a/mercurial/demandimport.py	Wed Dec 23 16:22:20 2015 -0800
+++ b/mercurial/demandimport.py	Wed Dec 23 16:22:20 2015 -0800
@@ -133,6 +133,8 @@
         self._load()
         setattr(self._module, attr, val)
 
+_pypy = '__pypy__' in sys.builtin_module_names
+
 def _demandimport(name, globals=None, locals=None, fromlist=None, level=level):
     if not locals or name in ignore or fromlist == ('*',):
         # these cases we can't really delay
@@ -191,7 +193,21 @@
                 return _hgextimport(_origimport, name, globals, locals,
                                     fromlist, level)
 
-            mod = _hgextimport(_origimport, name, globals, locals, level=level)
+            if _pypy:
+                # PyPy's __import__ throws an exception if invoked
+                # with an empty name and no fromlist.  Recreate the
+                # desired behaviour by hand.
+                mn = globalname
+                mod = sys.modules[mn]
+                if getattr(mod, '__path__', nothing) is nothing:
+                    mn = mn.rsplit('.', 1)[0]
+                    mod = sys.modules[mn]
+                if level > 1:
+                    mn = mn.rsplit('.', level - 1)[0]
+                    mod = sys.modules[mn]
+            else:
+                mod = _hgextimport(_origimport, name, globals, locals,
+                                   level=level)
 
             for x in fromlist:
                 processfromitem(mod, x)
@@ -245,10 +261,6 @@
 
 def enable():
     "enable global demand-loading of modules"
-    # PyPy doesn't work with demand import.
-    if '__pypy__' in sys.builtin_module_names:
-        return
-
     if os.environ.get('HGDEMANDIMPORT') != 'disable':
         builtins.__import__ = _demandimport