Commits

Anders Hammarquist  committed ad478c8

Make import behave like CPython when a path_hook find_module()
raises ImportError: treat it as if the find_module() had returned None

  • Participants
  • Parent commits ffc2d9b

Comments (0)

Files changed (4)

File pypy/module/imp/importing.py

 def find_in_path_hooks(space, w_modulename, w_pathitem):
     w_importer = _getimporter(space, w_pathitem)
     if w_importer is not None and space.is_true(w_importer):
-        w_loader = space.call_method(w_importer, "find_module", w_modulename)
+        try:
+            w_loader = space.call_method(w_importer, "find_module", w_modulename)
+        except OperationError, e:
+            if e.match(space, space.w_ImportError):
+                return None
+            raise
         if space.is_true(w_loader):
             return w_loader
 

File pypy/module/imp/test/hooktest.py

+import sys, imp
+
+__path__ = [ ]
+
+class Loader(object):
+    def __init__(self, file, filename, stuff):
+        self.file = file
+        self.filename = filename
+        self.stuff = stuff
+
+    def load_module(self, fullname):
+        mod = imp.load_module(fullname, self.file, self.filename, self.stuff)
+        if self.file:
+            self.file.close()
+        mod.__loader__ = self  # for introspection
+        return mod
+
+class Importer(object):
+    def __init__(self, path):
+        if path not in __path__:
+            raise ImportError
+
+    def find_module(self, fullname, path=None):
+        if not fullname.startswith('hooktest'):
+            return None
+
+        _, mod_name = fullname.rsplit('.',1)
+        found = imp.find_module(mod_name, path or __path__)
+
+        return Loader(*found)

File pypy/module/imp/test/hooktest/foo.py

+import errno # Any existing toplevel module

File pypy/module/imp/test/test_import.py

 class AppTestImportHooks(object):
 
     def setup_class(cls):
-        cls.space = gettestobjspace(usemodules=('struct',))
-    
+        space = cls.space = gettestobjspace(usemodules=('struct',))
+        mydir = os.path.dirname(__file__)
+        cls.w_hooktest = space.wrap(os.path.join(mydir, 'hooktest'))
+        space.appexec([space.wrap(mydir)], """
+            (mydir):
+                import sys
+                sys.path.append(mydir)
+        """)
+
+    def teardown_class(cls):
+        cls.space.appexec([], """
+            ():
+                import sys
+                sys.path.pop()
+        """)
+
     def test_meta_path(self):
         tried_imports = []
         class Importer(object):
             sys.meta_path.pop()
             sys.path_hooks.pop()
 
+    def test_path_hooks_module(self):
+        "Verify that non-sibling imports from module loaded by path hook works"
+
+        import sys
+        import hooktest
+
+        hooktest.__path__.append(self.hooktest) # Avoid importing os at applevel
+
+        sys.path_hooks.append(hooktest.Importer)
+
+        try:
+            import hooktest.foo
+            def import_nonexisting():
+                import hooktest.errno
+            raises(ImportError, import_nonexisting)
+        finally:
+            sys.path_hooks.pop()
 
 class AppTestPyPyExtension(object):
     def setup_class(cls):