mirror of
https://github.com/python/cpython.git
synced 2025-09-26 18:29:57 +00:00
parent
8e7cdb2586
commit
d5f9223981
5 changed files with 35 additions and 21 deletions
|
@ -11,6 +11,10 @@
|
||||||
This module provides utilities for the import system, in particular package
|
This module provides utilities for the import system, in particular package
|
||||||
support.
|
support.
|
||||||
|
|
||||||
|
.. class:: ModuleInfo(module_finder, name, ispkg)
|
||||||
|
|
||||||
|
A namedtuple that holds a brief summary of a module's info.
|
||||||
|
|
||||||
|
|
||||||
.. function:: extend_path(path, name)
|
.. function:: extend_path(path, name)
|
||||||
|
|
||||||
|
@ -139,7 +143,7 @@ support.
|
||||||
|
|
||||||
.. function:: iter_modules(path=None, prefix='')
|
.. function:: iter_modules(path=None, prefix='')
|
||||||
|
|
||||||
Yields ``(module_finder, name, ispkg)`` for all submodules on *path*, or, if
|
Yields :class:`ModuleInfo` for all submodules on *path*, or, if
|
||||||
*path* is ``None``, all top-level modules on ``sys.path``.
|
*path* is ``None``, all top-level modules on ``sys.path``.
|
||||||
|
|
||||||
*path* should be either ``None`` or a list of paths to look for modules in.
|
*path* should be either ``None`` or a list of paths to look for modules in.
|
||||||
|
@ -160,7 +164,7 @@ support.
|
||||||
|
|
||||||
.. function:: walk_packages(path=None, prefix='', onerror=None)
|
.. function:: walk_packages(path=None, prefix='', onerror=None)
|
||||||
|
|
||||||
Yields ``(module_finder, name, ispkg)`` for all modules recursively on
|
Yields :class:`ModuleInfo` for all modules recursively on
|
||||||
*path*, or, if *path* is ``None``, all accessible modules.
|
*path*, or, if *path* is ``None``, all accessible modules.
|
||||||
|
|
||||||
*path* should be either ``None`` or a list of paths to look for modules in.
|
*path* should be either ``None`` or a list of paths to look for modules in.
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
"""Utilities to support packages."""
|
"""Utilities to support packages."""
|
||||||
|
|
||||||
|
from collections import namedtuple
|
||||||
from functools import singledispatch as simplegeneric
|
from functools import singledispatch as simplegeneric
|
||||||
import importlib
|
import importlib
|
||||||
import importlib.util
|
import importlib.util
|
||||||
|
@ -14,9 +15,14 @@ __all__ = [
|
||||||
'get_importer', 'iter_importers', 'get_loader', 'find_loader',
|
'get_importer', 'iter_importers', 'get_loader', 'find_loader',
|
||||||
'walk_packages', 'iter_modules', 'get_data',
|
'walk_packages', 'iter_modules', 'get_data',
|
||||||
'ImpImporter', 'ImpLoader', 'read_code', 'extend_path',
|
'ImpImporter', 'ImpLoader', 'read_code', 'extend_path',
|
||||||
|
'ModuleInfo',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
ModuleInfo = namedtuple('ModuleInfo', 'module_finder name ispkg')
|
||||||
|
ModuleInfo.__doc__ = 'A namedtuple with minimal info about a module.'
|
||||||
|
|
||||||
|
|
||||||
def _get_spec(finder, name):
|
def _get_spec(finder, name):
|
||||||
"""Return the finder-specific module spec."""
|
"""Return the finder-specific module spec."""
|
||||||
# Works with legacy finders.
|
# Works with legacy finders.
|
||||||
|
@ -45,7 +51,7 @@ def read_code(stream):
|
||||||
|
|
||||||
|
|
||||||
def walk_packages(path=None, prefix='', onerror=None):
|
def walk_packages(path=None, prefix='', onerror=None):
|
||||||
"""Yields (module_finder, name, ispkg) for all modules recursively
|
"""Yields ModuleInfo for all modules recursively
|
||||||
on path, or, if path is None, all accessible modules.
|
on path, or, if path is None, all accessible modules.
|
||||||
|
|
||||||
'path' should be either None or a list of paths to look for
|
'path' should be either None or a list of paths to look for
|
||||||
|
@ -78,31 +84,31 @@ def walk_packages(path=None, prefix='', onerror=None):
|
||||||
return True
|
return True
|
||||||
m[p] = True
|
m[p] = True
|
||||||
|
|
||||||
for importer, name, ispkg in iter_modules(path, prefix):
|
for info in iter_modules(path, prefix):
|
||||||
yield importer, name, ispkg
|
yield info
|
||||||
|
|
||||||
if ispkg:
|
if info.ispkg:
|
||||||
try:
|
try:
|
||||||
__import__(name)
|
__import__(info.name)
|
||||||
except ImportError:
|
except ImportError:
|
||||||
if onerror is not None:
|
if onerror is not None:
|
||||||
onerror(name)
|
onerror(info.name)
|
||||||
except Exception:
|
except Exception:
|
||||||
if onerror is not None:
|
if onerror is not None:
|
||||||
onerror(name)
|
onerror(info.name)
|
||||||
else:
|
else:
|
||||||
raise
|
raise
|
||||||
else:
|
else:
|
||||||
path = getattr(sys.modules[name], '__path__', None) or []
|
path = getattr(sys.modules[info.name], '__path__', None) or []
|
||||||
|
|
||||||
# don't traverse path items we've seen before
|
# don't traverse path items we've seen before
|
||||||
path = [p for p in path if not seen(p)]
|
path = [p for p in path if not seen(p)]
|
||||||
|
|
||||||
yield from walk_packages(path, name+'.', onerror)
|
yield from walk_packages(path, info.name+'.', onerror)
|
||||||
|
|
||||||
|
|
||||||
def iter_modules(path=None, prefix=''):
|
def iter_modules(path=None, prefix=''):
|
||||||
"""Yields (module_finder, name, ispkg) for all submodules on path,
|
"""Yields ModuleInfo for all submodules on path,
|
||||||
or, if path is None, all top-level modules on sys.path.
|
or, if path is None, all top-level modules on sys.path.
|
||||||
|
|
||||||
'path' should be either None or a list of paths to look for
|
'path' should be either None or a list of paths to look for
|
||||||
|
@ -111,7 +117,6 @@ def iter_modules(path=None, prefix=''):
|
||||||
'prefix' is a string to output on the front of every module name
|
'prefix' is a string to output on the front of every module name
|
||||||
on output.
|
on output.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if path is None:
|
if path is None:
|
||||||
importers = iter_importers()
|
importers = iter_importers()
|
||||||
else:
|
else:
|
||||||
|
@ -122,7 +127,7 @@ def iter_modules(path=None, prefix=''):
|
||||||
for name, ispkg in iter_importer_modules(i, prefix):
|
for name, ispkg in iter_importer_modules(i, prefix):
|
||||||
if name not in yielded:
|
if name not in yielded:
|
||||||
yielded[name] = 1
|
yielded[name] = 1
|
||||||
yield i, name, ispkg
|
yield ModuleInfo(i, name, ispkg)
|
||||||
|
|
||||||
|
|
||||||
@simplegeneric
|
@simplegeneric
|
||||||
|
|
|
@ -81,8 +81,9 @@ class PkgutilTests(unittest.TestCase):
|
||||||
self.assertEqual(res2, RESOURCE_DATA)
|
self.assertEqual(res2, RESOURCE_DATA)
|
||||||
|
|
||||||
names = []
|
names = []
|
||||||
for loader, name, ispkg in pkgutil.iter_modules([zip_file]):
|
for moduleinfo in pkgutil.iter_modules([zip_file]):
|
||||||
names.append(name)
|
self.assertIsInstance(moduleinfo, pkgutil.ModuleInfo)
|
||||||
|
names.append(moduleinfo.name)
|
||||||
self.assertEqual(names, ['test_getdata_zipfile'])
|
self.assertEqual(names, ['test_getdata_zipfile'])
|
||||||
|
|
||||||
del sys.path[0]
|
del sys.path[0]
|
||||||
|
|
|
@ -577,13 +577,14 @@ from ..uncle.cousin import nephew
|
||||||
self.addCleanup(self._del_pkg, pkg_dir)
|
self.addCleanup(self._del_pkg, pkg_dir)
|
||||||
for depth in range(2, max_depth+1):
|
for depth in range(2, max_depth+1):
|
||||||
self._add_relative_modules(pkg_dir, "", depth)
|
self._add_relative_modules(pkg_dir, "", depth)
|
||||||
for finder, mod_name, ispkg in pkgutil.walk_packages([pkg_dir]):
|
for moduleinfo in pkgutil.walk_packages([pkg_dir]):
|
||||||
self.assertIsInstance(finder,
|
self.assertIsInstance(moduleinfo, pkgutil.ModuleInfo)
|
||||||
|
self.assertIsInstance(moduleinfo.module_finder,
|
||||||
importlib.machinery.FileFinder)
|
importlib.machinery.FileFinder)
|
||||||
if ispkg:
|
if moduleinfo.ispkg:
|
||||||
expected_packages.remove(mod_name)
|
expected_packages.remove(moduleinfo.name)
|
||||||
else:
|
else:
|
||||||
expected_modules.remove(mod_name)
|
expected_modules.remove(moduleinfo.name)
|
||||||
self.assertEqual(len(expected_packages), 0, expected_packages)
|
self.assertEqual(len(expected_packages), 0, expected_packages)
|
||||||
self.assertEqual(len(expected_modules), 0, expected_modules)
|
self.assertEqual(len(expected_modules), 0, expected_modules)
|
||||||
|
|
||||||
|
|
|
@ -7845,6 +7845,9 @@ Library
|
||||||
- Issue #16809: Tkinter's splitlist() and split() methods now accept Tcl_Obj
|
- Issue #16809: Tkinter's splitlist() and split() methods now accept Tcl_Obj
|
||||||
argument.
|
argument.
|
||||||
|
|
||||||
|
- Issue #17211: Yield a namedtuple in pkgutil.
|
||||||
|
Patch by Ramchandra Apte.
|
||||||
|
|
||||||
- Issue #18324: set_payload now correctly handles binary input. This also
|
- Issue #18324: set_payload now correctly handles binary input. This also
|
||||||
supersedes the previous fixes for #14360, #1717, and #16564.
|
supersedes the previous fixes for #14360, #1717, and #16564.
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue