py-demandimport icon indicating copy to clipboard operation
py-demandimport copied to clipboard

`import a.b as c` isn't imported lazily

Open lieryan opened this issue 5 years ago • 1 comments

So in the following situation, import a is a package that is slow to import and we want to avoid importing a until necessary, a.b is a submodule/subpackage.

with demandimport.enabled():
    # these works as expected
    import a
    import a.b

    # but, this is not lazy imported:
    import a.b as c

The README claims that import a.b as c should be lazy imported, but that's not actually the full story. IIUC, using this form only lazy imports module b, but would actually eagerly import and executes a.

Desired behaviour is that a should only be executed the first time that any c.xxx is accessed, at which point c should import a.b.

If this behaviour isn't easy/possible to implement, then we should document this limitation, similar to how we document similar limitations for from import.

lieryan avatar Oct 13 '20 11:10 lieryan

Thanks for reporting the issue. I can't reproduce it. I added the following test

diff --git a/src/tests/test_issues.py b/src/tests/test_issues.py
index df61e25..42e9d8b 100644
--- a/src/tests/test_issues.py
+++ b/src/tests/test_issues.py
@@ -45,6 +45,22 @@ class TestIssues(unittest.TestCase):
                     f.write("from b import *")
                 __import__(m.name+'.a.c', locals={'foo': 'bar'}).a.c.__name__
 
+    def test_issue9(self):
+        with TestModule() as m:
+            with demandimport.enabled():
+                os.mkdir(os.path.join(m.path, 'a'))
+                os.mkdir(os.path.join(m.path, 'b'))
+                with open(os.path.join(m.path, 'a', '__init__.py'), 'w') as f:
+                    pass
+                with open(os.path.join(m.path, 'a', 'b.py'), 'w') as f:
+                    f.write("assert(False)")
+                with open(os.path.join(m.path, 'b', '__init__.py'), 'w') as f:
+                    # f.write("import {}.a\n".format(m.name))
+                    # f.write("import {}.a.b\n".format(m.name))
+                    f.write("import {}.a.b as d\n".format(m.name))
+                self.assertFalse(demandimport.is_loaded(
+                        __import__(m.name+'.b', locals={'foo': 'bar'}).b.d))
+
 if __name__ == '__main__':
     def log(msg, *args):
         print(msg % args)

and ran it with Python2.7 and Python3.9 as is and with the commented lines uncommented, but the test passed every time. Could you please provide me with code to reproduce the issue?

bwesterb avatar Nov 22 '20 12:11 bwesterb