demandimport: support lazy loading for absolute_import
authorGregory Szorc <gregory.szorc@gmail.com>
Sat, 08 Aug 2015 16:13:27 -0700
changeset 25937 4f1144c3c72b
parent 25936 f90bb2002bcf
child 25938 e194ada8d45f
demandimport: support lazy loading for absolute_import Before, we didn't support lazy loading if absolute_import was in effect and a fromlist was used. This meant that "from . import X" wasn't lazy and performance could suffer as a result. With this patch, we now support lazy loading for this scenario. As part of developing this, I discovered issues when module names are defined. Since the enforced import style only allows "from X import Y" or "from .X import Y" in very few scenarios when absolute_import is enabled - scenarios where Y is not a module and thus there is nothing to lazy load - I decided to drop support for this case instead of chasing down the errors. I don't think much harm will come from this. But I'd like to take another look once all modules are using absolute_import and I can see the full extent of what is using names in absolute_import mode.
mercurial/demandimport.py
--- a/mercurial/demandimport.py	Sat Aug 08 17:07:34 2015 -0700
+++ b/mercurial/demandimport.py	Sat Aug 08 16:13:27 2015 -0700
@@ -139,7 +139,24 @@
         # so modern Mercurial code will have level >= 0.
 
         if level >= 0:
-            return _origimport(name, globals, locals, fromlist, level)
+            # Mercurial's enforced import style does not use
+            # "from a import b,c,d" or "from .a import b,c,d" syntax. In
+            # addition, this appears to be giving errors with some modules
+            # for unknown reasons. Since we shouldn't be using this syntax
+            # much, work around the problems.
+            if name:
+                return _hgextimport(_origimport, name, globals, locals,
+                                    fromlist, level)
+
+            mod = _hgextimport(_origimport, name, globals, locals, level=level)
+            for x in fromlist:
+                # Missing symbols mean they weren't defined in the module
+                # itself which means they are sub-modules.
+                if getattr(mod, x, nothing) is nothing:
+                    setattr(mod, x,
+                            _demandmod(x, mod.__dict__, locals, level=level))
+
+            return mod
 
         # But, we still need to support lazy loading of standard library and 3rd
         # party modules. So handle level == -1.