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.
--- 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