[pypy-commit] pypy dummy-importlib: add enough logic to import packages and modules inside packages

antocuni pypy.commits at gmail.com
Thu Dec 19 19:37:32 EST 2019


Author: Antonio Cuni <anto.cuni at gmail.com>
Branch: dummy-importlib
Changeset: r98334:98132b9252a9
Date: 2019-12-19 14:47 +0100
http://bitbucket.org/pypy/pypy/changeset/98132b9252a9/

Log:	add enough logic to import packages and modules inside packages

diff --git a/pypy/module/_dummy_importlib/interp_import.py b/pypy/module/_dummy_importlib/interp_import.py
--- a/pypy/module/_dummy_importlib/interp_import.py
+++ b/pypy/module/_dummy_importlib/interp_import.py
@@ -16,8 +16,8 @@
     raise OperationError(space.w_ImportError, space.newtext(modname + '\n' + err))
 
 
- at unwrap_spec(name='text0', level=int)
-def importhook(space, name, w_globals=None,
+ at unwrap_spec(modname='text0', level=int)
+def importhook(space, modname, w_globals=None,
                w_locals=None, w_fromlist=None, level=0):
     """
     NOT_RPYTHON
@@ -26,33 +26,63 @@
     non-rpython tricks to implement it :)
     """
     assert level == 0
-    if name in space.builtin_modules:
-        return space.getbuiltinmodule(name)
+    if modname in space.builtin_modules:
+        return space.getbuiltinmodule(modname)
 
     w_path = space.sys.get('path')
+    parts = modname.split('.')
+    if parts[-1] == '':
+        del parts[-1]
+
+    ## if modname == 'dummypkg.mod':
+    ##     import pdb;pdb.set_trace()
+    w_mod = None
+    w_firstmod = None
+    for part in parts:
+        w_mod = load_part(space, part, w_mod)
+        if w_mod and w_firstmod is None:
+            w_firstmod = w_mod
+
+    if w_mod is None:
+        raise_ImportError(space, modname)
+    return w_firstmod
+
+def load_part(space, modname, w_parent):
+    if w_parent is None:
+        w_path = space.sys.get('path')
+    else:
+        w_path = space.getattr(w_parent, space.newtext('__path__'))
+    #
+    w_mod = load_part_in_path(space, modname, w_path)
+    if w_mod is not None and w_parent is not None:
+        space.setattr(w_parent, space.newtext(modname), w_mod)
+    return w_mod
+
+def load_part_in_path(space, modname, w_path):
     for w_item in space.unpackiterable(w_path):
         item = space.fsdecode_w(w_item)
         d = py.path.local(item)
         #
-        pyfile = d.join(name + '.py')
+        pyfile = d.join(modname + '.py')
         if pyfile.check(file=True):
-            return import_pyfile(space, name, pyfile)
+            return load_pyfile(space, modname, pyfile)
         #
-        pydir = d.join(name)
+        pydir = d.join(modname)
         pyinit = pydir.join('__init__.py')
         if pydir.check(dir=True) and pyinit.check(file=True):
-            return import_pyfile(space, name, pyinit)
+            return load_pyfile(space, modname, pyinit, modpath=str(pydir))
+    return None
 
-    raise_ImportError(name)
-
-
-def import_pyfile(space, modulename, pyfile):
+def load_pyfile(space, modname, pyfile, modpath=None):
     ec = space.getexecutioncontext()
     source = pyfile.read()
     code_w = ec.compiler.compile(source, str(pyfile), 'exec', 0)
-    w_mod = add_module(space, space.newtext(modulename))
+    w_mod = add_module(space, space.newtext(modname))
     space.setitem(space.sys.get('modules'), w_mod.w_name, w_mod)
     space.setitem(w_mod.w_dict, space.newtext('__name__'), w_mod.w_name)
+    if modpath:
+        w_path = space.newlist([space.newtext(modpath)])
+        space.setitem(w_mod.w_dict, space.newtext('__path__'), w_path)
     code_w.exec_code(space, w_mod.w_dict, w_mod.w_dict)
-    assert check_sys_modules_w(space, modulename)
+    assert check_sys_modules_w(space, modname)
     return w_mod
diff --git a/pypy/module/_dummy_importlib/test/test__dummy_importlib.py b/pypy/module/_dummy_importlib/test/test__dummy_importlib.py
--- a/pypy/module/_dummy_importlib/test/test__dummy_importlib.py
+++ b/pypy/module/_dummy_importlib/test/test__dummy_importlib.py
@@ -18,21 +18,23 @@
 
     def setup_method(self, meth):
         space = self.space
-        self.w_thisidr = space.newtext(str(THISDIR))
-        space.appexec([self.w_thisidr], """(dir):
+        self.w_thisdir = space.newtext(str(THISDIR))
+        space.appexec([self.w_thisdir], """(dir):
             import sys
             sys.path.append(dir)
         """)
 
-
     def teardown_method(self, meth):
         space = self.space
-        space.appexec([self.w_thisidr], """(dir):
+        space.appexec([self.w_thisdir], """(dir):
         import sys
         if dir in sys.path:
             sys.path.remove(dir)
         """)
 
+    def test_ImportError(self):
+        raises(ImportError, "import i_dont_exist")
+
     def test_import_builtin(self):
         import sys
         assert sys.__name__ == 'sys'
@@ -43,9 +45,21 @@
         assert sys is sys2
 
     def test_import_lib_pypy(self):
+        import sys
         import _structseq
+        assert _structseq.__name__ == '_structseq'
         assert hasattr(_structseq, 'structseq_new')
+        assert sys.modules['_structseq'] is _structseq
 
     def test_import_package(self):
+        import sys
         import dummypkg
+        assert dummypkg.__name__ == 'dummypkg'
+        assert dummypkg.__path__ == [self.thisdir + '/' + 'dummypkg']
         assert dummypkg.FOO == 42
+        assert sys.modules['dummypkg'] is dummypkg
+
+    def test_import_package_dot_mod(self):
+        import dummypkg.mod
+        assert dummypkg.FOO == 42
+        assert dummypkg.mod.BAR == 43


More information about the pypy-commit mailing list