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

Skip to content

Commit 2dee597

Browse files
committed
Do some cleanup in importlib:
+ Ditch using arguments to super(). + Ditch subclassing from object directly. + Move directory check out of chaining path hook to file path hook/finder. + Rename some classes to better reflect they are finders, not importers.
1 parent a2fcb1d commit 2dee597

8 files changed

Lines changed: 56 additions & 62 deletions

File tree

Lib/importlib/_bootstrap.py

Lines changed: 47 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -174,51 +174,43 @@ def load_module(cls, fullname):
174174
raise
175175

176176

177-
class ChainedImporter(object):
177+
def chained_path_hook(*path_hooks):
178+
"""Create a closure which sequentially checks path hooks to see which ones
179+
(if any) can work with a path."""
180+
def path_hook(entry):
181+
"""Check to see if 'entry' matches any of the enclosed path hooks."""
182+
finders = []
183+
for hook in path_hooks:
184+
try:
185+
finder = hook(entry)
186+
except ImportError:
187+
continue
188+
else:
189+
finders.append(finder)
190+
if not finders:
191+
raise ImportError("no finder found")
192+
else:
193+
return ChainedFinder(*finders)
194+
195+
return path_hook
196+
197+
198+
class ChainedFinder:
178199

179200
"""Finder that sequentially calls other finders."""
180201

181-
def __init__(self, *importers):
182-
self._importers = importers
202+
def __init__(self, *finders):
203+
self._finders = finders
183204

184205
def find_module(self, fullname, path=None):
185-
for importer in self._importers:
186-
result = importer.find_module(fullname, path)
206+
for finder in self._finders:
207+
result = finder.find_module(fullname, path)
187208
if result:
188209
return result
189210
else:
190211
return None
191212

192213

193-
# XXX Don't make filesystem-specific and instead make generic for any path
194-
# hooks.
195-
def chaining_fs_path_hook(*path_hooks):
196-
"""Create a closure which calls the path hooks sequentially looking for
197-
which path hooks can handle a path entry.
198-
199-
200-
Passed-in path hooks work as any other path hooks, raising ImportError if
201-
they cannot handle the path, otherwise returning a finder.
202-
203-
"""
204-
def chained_fs_path_hook(path_entry):
205-
"""Closure which sees which of the captured path hooks can handle the
206-
path entry."""
207-
absolute_path = _path_absolute(path_entry)
208-
if not _path_isdir(absolute_path):
209-
raise ImportError("only directories are supported")
210-
accepted = []
211-
for path_hook in path_hooks:
212-
try:
213-
accepted.append(path_hook(absolute_path))
214-
except ImportError:
215-
continue
216-
if not accepted:
217-
raise ImportError("no path hooks could handle %s" % path_entry)
218-
return ChainedImporter(*accepted)
219-
return chained_fs_path_hook
220-
221-
222214
def check_name(method):
223215
"""Decorator to verify that the module being requested matches the one the
224216
loader can handle.
@@ -235,11 +227,11 @@ def inner(self, name, *args, **kwargs):
235227
return inner
236228

237229

238-
class _ExtensionFileLoader(object):
230+
class _ExtensionFileLoader:
239231

240232
"""Loader for extension modules.
241233
242-
The constructor is designed to work with FileImporter.
234+
The constructor is designed to work with FileFinder.
243235
244236
"""
245237

@@ -323,10 +315,10 @@ def decorated(self, fullname):
323315
return decorated
324316

325317

326-
class _PyFileLoader(object):
318+
class _PyFileLoader:
327319
# XXX Still smart to have this as a separate class? Or would it work
328-
# better to integrate with PyFileImporter? Could cache _is_pkg info.
329-
# FileImporter can be changed to return self instead of a specific loader
320+
# better to integrate with PyFileFinder? Could cache _is_pkg info.
321+
# FileFinder can be changed to return self instead of a specific loader
330322
# call. Otherwise _base_path can be calculated on the fly without issue if
331323
# it is known whether a module should be treated as a path or package to
332324
# minimize stat calls. Could even go as far as to stat the directory the
@@ -515,9 +507,9 @@ def is_package(self, fullname):
515507
return self._is_pkg
516508

517509

518-
class FileImporter(object):
510+
class FileFinder:
519511

520-
"""Base class for file importers.
512+
"""Base class for file finders.
521513
522514
Subclasses are expected to define the following attributes:
523515
@@ -541,10 +533,13 @@ def __init__(self, path_entry):
541533
Can be used as an entry on sys.path_hook.
542534
543535
"""
544-
self._path_entry = path_entry
536+
absolute_path = _path_absolute(path_entry)
537+
if not _path_isdir(absolute_path):
538+
raise ImportError("only directories are supported")
539+
self._path_entry = absolute_path
545540

546541
def find_module(self, fullname, path=None):
547-
tail_module = fullname.rsplit('.', 1)[-1]
542+
tail_module = fullname.rpartition('.')[2]
548543
package_directory = None
549544
if self._possible_package:
550545
for ext in self._suffixes:
@@ -571,7 +566,7 @@ def find_module(self, fullname, path=None):
571566
return None
572567

573568

574-
class ExtensionFileImporter(FileImporter):
569+
class ExtensionFileFinder(FileFinder):
575570

576571
"""Importer for extension files."""
577572

@@ -582,10 +577,10 @@ def __init__(self, path_entry):
582577
# Assigning to _suffixes here instead of at the class level because
583578
# imp is not imported at the time of class creation.
584579
self._suffixes = suffix_list(imp.C_EXTENSION)
585-
super(ExtensionFileImporter, self).__init__(path_entry)
580+
super().__init__(path_entry)
586581

587582

588-
class PyFileImporter(FileImporter):
583+
class PyFileFinder(FileFinder):
589584

590585
"""Importer for source/bytecode files."""
591586

@@ -598,7 +593,7 @@ def __init__(self, path_entry):
598593
# optimization by the loader.
599594
self._suffixes = suffix_list(imp.PY_SOURCE)
600595
self._suffixes += suffix_list(imp.PY_COMPILED)
601-
super(PyFileImporter, self).__init__(path_entry)
596+
super().__init__(path_entry)
602597

603598

604599
class PathFinder:
@@ -664,31 +659,30 @@ def find_module(cls, fullname, path=None):
664659
return None
665660

666661

662+
_DEFAULT_PATH_HOOK = chained_path_hook(ExtensionFileFinder, PyFileFinder)
663+
667664
class _DefaultPathFinder(PathFinder):
668665

669666
"""Subclass of PathFinder that implements implicit semantics for
670667
__import__."""
671668

672-
_default_hook = staticmethod(chaining_fs_path_hook(ExtensionFileImporter,
673-
PyFileImporter))
674-
675669
@classmethod
676670
def _path_hooks(cls, path):
677671
"""Search sys.path_hooks as well as implicit path hooks."""
678672
try:
679673
return super()._path_hooks(path)
680674
except ImportError:
681-
implicit_hooks = [cls._default_hook, imp.NullImporter]
675+
implicit_hooks = [_DEFAULT_PATH_HOOK, imp.NullImporter]
682676
return super()._path_hooks(path, implicit_hooks)
683677

684678
@classmethod
685679
def _path_importer_cache(cls, path):
686680
"""Use the default path hook when None is stored in
687681
sys.path_importer_cache."""
688-
return super()._path_importer_cache(path, cls._default_hook)
682+
return super()._path_importer_cache(path, _DEFAULT_PATH_HOOK)
689683

690684

691-
class ImportLockContext(object):
685+
class ImportLockContext:
692686

693687
"""Context manager for the import lock."""
694688

Lib/importlib/test/extension/test_case_sensitivity.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ def find_module(self):
1313
good_name = ext_util.NAME
1414
bad_name = good_name.upper()
1515
assert good_name != bad_name
16-
finder = importlib.ExtensionFileImporter(ext_util.PATH)
16+
finder = importlib.ExtensionFileFinder(ext_util.PATH)
1717
return finder.find_module(bad_name)
1818

1919
def test_case_sensitive(self):

Lib/importlib/test/extension/test_finder.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ class FinderTests(abc.FinderTests):
99
"""Test the finder for extension modules."""
1010

1111
def find_module(self, fullname):
12-
importer = importlib.ExtensionFileImporter(util.PATH)
12+
importer = importlib.ExtensionFileFinder(util.PATH)
1313
return importer.find_module(fullname)
1414

1515
def test_module(self):

Lib/importlib/test/extension/test_path_hook.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ class PathHookTests(unittest.TestCase):
1414
# XXX Should it only work for directories containing an extension module?
1515

1616
def hook(self, entry):
17-
return importlib.ExtensionFileImporter(entry)
17+
return importlib.ExtensionFileFinder(entry)
1818

1919
def test_success(self):
2020
# Path hook should handle a directory where a known extension module

Lib/importlib/test/import_/test_path.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -87,16 +87,16 @@ def test_path_importer_cache_has_None(self):
8787
importer = util.mock_modules(module)
8888
path = '<test path>'
8989
# XXX Not blackbox.
90-
original_hook = _bootstrap._DefaultPathFinder._default_hook
90+
original_hook = _bootstrap._DEFAULT_PATH_HOOK
9191
mock_hook = import_util.mock_path_hook(path, importer=importer)
92-
_bootstrap._DefaultPathFinder._default_hook = staticmethod(mock_hook)
92+
_bootstrap._DEFAULT_PATH_HOOK = mock_hook
9393
try:
9494
with util.import_state(path_importer_cache={path: None}):
9595
loader = _bootstrap._DefaultPathFinder.find_module(module,
9696
path=[path])
9797
self.assert_(loader is importer)
9898
finally:
99-
_bootstrap._DefaultPathFinder._default_hook = original_hook
99+
_bootstrap._DEFAULT_PATH_HOOK = original_hook
100100

101101

102102
def test_main():

Lib/importlib/test/source/test_case_sensitivity.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ class CaseSensitivityTest(unittest.TestCase):
1919
assert name != name.lower()
2020

2121
def find(self, path):
22-
finder = importlib.PyFileImporter(path)
22+
finder = importlib.PyFileFinder(path)
2323
return finder.find_module(self.name)
2424

2525
def sensitivity_test(self):

Lib/importlib/test/source/test_finder.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ class FinderTests(abc.FinderTests):
3232
"""
3333

3434
def import_(self, root, module):
35-
finder = importlib.PyFileImporter(root)
35+
finder = importlib.PyFileFinder(root)
3636
return finder.find_module(module)
3737

3838
def run_test(self, test, create=None, *, compile_=None, unlink=None):

Lib/importlib/test/source/test_path_hook.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ class PathHookTest(unittest.TestCase):
1010
def test_success(self):
1111
# XXX Only work on existing directories?
1212
with source_util.create_modules('dummy') as mapping:
13-
self.assert_(hasattr(importlib.FileImporter(mapping['.root']),
13+
self.assert_(hasattr(importlib.FileFinder(mapping['.root']),
1414
'find_module'))
1515

1616

0 commit comments

Comments
 (0)