Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 32732e3

Browse files
committed
Change importlib.machinery.PathFinder to not have implicit semantics (that's
not handled by importlib._bootstrap._DefaultPathFinder).
1 parent 4b4a4a5 commit 32732e3

3 files changed

Lines changed: 72 additions & 57 deletions

File tree

Lib/importlib/_bootstrap.py

Lines changed: 37 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -610,36 +610,25 @@ class PathFinder:
610610

611611
"""Meta path finder for sys.(path|path_hooks|path_importer_cache)."""
612612

613-
_default_hook = staticmethod(chaining_fs_path_hook(ExtensionFileImporter,
614-
PyFileImporter))
615-
616-
# The list of implicit hooks cannot be a class attribute because of
617-
# bootstrapping issues for accessing imp.
618613
@classmethod
619-
def _implicit_hooks(cls):
620-
"""Return a list of the implicit path hooks."""
621-
return [cls._default_hook, imp.NullImporter]
622-
623-
@classmethod
624-
def _path_hooks(cls, path):
625-
"""Search sys.path_hooks for a finder for 'path'.
614+
def _path_hooks(cls, path, hooks=None):
615+
"""Search sequence of hooks for a finder for 'path'.
626616
627-
Guaranteed to return a finder for the path as NullImporter is the
628-
default importer for any path that does not have an explicit finder.
617+
If 'hooks' is false then use sys.path_hooks.
629618
630619
"""
631-
for hook in sys.path_hooks + cls._implicit_hooks():
620+
if not hooks:
621+
hooks = sys.path_hooks
622+
for hook in hooks:
632623
try:
633624
return hook(path)
634625
except ImportError:
635626
continue
636627
else:
637-
# This point should never be reached thanks to NullImporter.
638-
raise SystemError("no hook could find an importer for "
639-
"{0}".format(path))
628+
raise ImportError("no path hook found for {0}".format(path))
640629

641630
@classmethod
642-
def _path_importer_cache(cls, path):
631+
def _path_importer_cache(cls, path, default=None):
643632
"""Get the finder for the path from sys.path_importer_cache.
644633
645634
If the path is not in the cache, find the appropriate finder and cache
@@ -657,9 +646,9 @@ def _path_importer_cache(cls, path):
657646
finder = cls._path_hooks(path)
658647
sys.path_importer_cache[path] = finder
659648
else:
660-
if finder is None:
649+
if finder is None and default:
661650
# Raises ImportError on failure.
662-
finder = cls._default_hook(path)
651+
finder = default(path)
663652
sys.path_importer_cache[path] = finder
664653
return finder
665654

@@ -680,6 +669,30 @@ def find_module(cls, fullname, path=None):
680669
return None
681670

682671

672+
class _DefaultPathFinder(PathFinder):
673+
674+
"""Subclass of PathFinder that implements implicit semantics for
675+
__import__."""
676+
677+
_default_hook = staticmethod(chaining_fs_path_hook(ExtensionFileImporter,
678+
PyFileImporter))
679+
680+
@classmethod
681+
def _path_hooks(cls, path):
682+
"""Search sys.path_hooks as well as implicit path hooks."""
683+
try:
684+
return super()._path_hooks(path)
685+
except ImportError:
686+
implicit_hooks = [cls._default_hook, imp.NullImporter]
687+
return super()._path_hooks(path, implicit_hooks)
688+
689+
@classmethod
690+
def _path_importer_cache(cls, path):
691+
"""Use the default path hook when None is stored in
692+
sys.path_importer_cache."""
693+
return super()._path_importer_cache(path, cls._default_hook)
694+
695+
683696
class ImportLockContext(object):
684697

685698
"""Context manager for the import lock."""
@@ -693,6 +706,8 @@ def __exit__(self, exc_type, exc_value, exc_traceback):
693706
imp.release_lock()
694707

695708

709+
_IMPLICIT_META_PATH = [BuiltinImporter, FrozenImporter, _DefaultPathFinder]
710+
696711
def _gcd_import(name, package=None, level=0):
697712
"""Import and return the module based on its name, the package the call is
698713
being made from, and the level adjustment.
@@ -736,8 +751,7 @@ def _gcd_import(name, package=None, level=0):
736751
# Backwards-compatibility; be nicer to skip the dict lookup.
737752
parent_module = sys.modules[parent]
738753
path = parent_module.__path__
739-
meta_path = (sys.meta_path +
740-
[BuiltinImporter, FrozenImporter, PathFinder])
754+
meta_path = sys.meta_path + _IMPLICIT_META_PATH
741755
for finder in meta_path:
742756
loader = finder.find_module(name, path)
743757
if loader is not None:
Lines changed: 33 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
from importlib import _bootstrap
12
from importlib import machinery
23
from .. import util
34
from . import util as import_util
@@ -12,20 +13,13 @@
1213

1314
class FinderTests(unittest.TestCase):
1415

15-
"""Tests for SysPathImporter."""
16+
"""Tests for PathFinder."""
1617

1718
def test_failure(self):
1819
# Test None returned upon not finding a suitable finder.
19-
def mock_implicit_hooks():
20-
return []
21-
# XXX Not blackbox.
22-
original_hooks = machinery.PathFinder._implicit_hooks
23-
machinery.PathFinder._implicit_hooks = staticmethod(mock_implicit_hooks)
24-
try:
25-
with util.import_state():
26-
self.assert_(machinery.PathFinder.find_module('XXX') is None)
27-
finally:
28-
machinery.PathFinder._implicit_hooks = original_hooks
20+
module = '<test module>'
21+
with util.import_state():
22+
self.assert_(machinery.PathFinder.find_module(module) is None)
2923

3024
def test_sys_path(self):
3125
# Test that sys.path is used when 'path' is None.
@@ -48,23 +42,6 @@ def test_path(self):
4842
loader = machinery.PathFinder.find_module(module, [path])
4943
self.assert_(loader is importer)
5044

51-
def test_path_importer_cache_has_None(self):
52-
# Test that the default hook is used when sys.path_importer_cache
53-
# contains None for a path.
54-
module = '<test module>'
55-
importer = util.mock_modules(module)
56-
path = '<test path>'
57-
# XXX Not blackbox.
58-
original_hook = machinery.PathFinder._default_hook
59-
mock_hook = import_util.mock_path_hook(path, importer=importer)
60-
machinery.PathFinder._default_hook = staticmethod(mock_hook)
61-
try:
62-
with util.import_state(path_importer_cache={path: None}):
63-
loader = machinery.PathFinder.find_module(module, path=[path])
64-
self.assert_(loader is importer)
65-
finally:
66-
machinery.PathFinder._default_hook = original_hook
67-
6845
def test_path_hooks(self):
6946
# Test that sys.path_hooks is used.
7047
# Test that sys.path_importer_cache is set.
@@ -78,29 +55,53 @@ def test_path_hooks(self):
7855
self.assert_(path in sys.path_importer_cache)
7956
self.assert_(sys.path_importer_cache[path] is importer)
8057

58+
59+
class DefaultPathFinderTests(unittest.TestCase):
60+
61+
"""Test importlib._bootstrap._DefaultPathFinder."""
62+
8163
def test_implicit_hooks(self):
8264
# Test that the implicit path hooks are used.
8365
existing_path = os.path.dirname(support.TESTFN)
8466
bad_path = '<path>'
8567
module = '<module>'
8668
assert not os.path.exists(bad_path)
8769
with util.import_state():
88-
nothing = machinery.PathFinder.find_module(module,
89-
path=[existing_path])
70+
nothing = _bootstrap._DefaultPathFinder.find_module(module,
71+
path=[existing_path])
9072
self.assert_(nothing is None)
9173
self.assert_(existing_path in sys.path_importer_cache)
9274
self.assert_(not isinstance(sys.path_importer_cache[existing_path],
9375
imp.NullImporter))
94-
nothing = machinery.PathFinder.find_module(module, path=[bad_path])
76+
nothing = _bootstrap._DefaultPathFinder.find_module(module,
77+
path=[bad_path])
9578
self.assert_(nothing is None)
9679
self.assert_(bad_path in sys.path_importer_cache)
9780
self.assert_(isinstance(sys.path_importer_cache[bad_path],
9881
imp.NullImporter))
9982

83+
def test_path_importer_cache_has_None(self):
84+
# Test that the default hook is used when sys.path_importer_cache
85+
# contains None for a path.
86+
module = '<test module>'
87+
importer = util.mock_modules(module)
88+
path = '<test path>'
89+
# XXX Not blackbox.
90+
original_hook = _bootstrap._DefaultPathFinder._default_hook
91+
mock_hook = import_util.mock_path_hook(path, importer=importer)
92+
_bootstrap._DefaultPathFinder._default_hook = staticmethod(mock_hook)
93+
try:
94+
with util.import_state(path_importer_cache={path: None}):
95+
loader = _bootstrap._DefaultPathFinder.find_module(module,
96+
path=[path])
97+
self.assert_(loader is importer)
98+
finally:
99+
_bootstrap._DefaultPathFinder._default_hook = original_hook
100+
100101

101102
def test_main():
102103
from test.support import run_unittest
103-
run_unittest(PathTests, __path__Tests, FinderTests)
104+
run_unittest(FinderTests, DefaultPathFinderTests)
104105

105106
if __name__ == '__main__':
106107
test_main()

Lib/importlib/test/import_/util.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ def import_(*args, **kwargs):
99
"""Delegate to allow for injecting different implementations of import."""
1010
if using___import__:
1111
return __import__(*args, **kwargs)
12-
#return importlib.Import()(*args, **kwargs)
13-
return importlib._bootstrap._import(*args, **kwargs)
12+
else:
13+
return importlib._bootstrap._import(*args, **kwargs)
1414

1515

1616
def importlib_only(fxn):

0 commit comments

Comments
 (0)