[Python-checkins] cpython: Issue #17211: Yield a namedtuple in pkgutil.

eric.snow python-checkins at python.org
Wed Sep 7 21:38:22 EDT 2016


https://hg.python.org/cpython/rev/4f023e60564b
changeset: 103283:4f023e60564b
user: Eric Snow <ericsnowcurrently at gmail.com>
date: Wed Sep 07 18:37:17 2016 -0700
summary:
 Issue #17211: Yield a namedtuple in pkgutil.
Patch by Ramchandra Apte.
files:
 Doc/library/pkgutil.rst | 8 +++++-
 Lib/pkgutil.py | 29 ++++++++++++++++-----------
 Lib/test/test_pkgutil.py | 5 ++-
 Lib/test/test_runpy.py | 11 +++++----
 Misc/NEWS | 3 ++
 5 files changed, 35 insertions(+), 21 deletions(-)
diff --git a/Doc/library/pkgutil.rst b/Doc/library/pkgutil.rst
--- a/Doc/library/pkgutil.rst
+++ b/Doc/library/pkgutil.rst
@@ -11,6 +11,10 @@
 This module provides utilities for the import system, in particular package
 support.
 
+.. class:: ModuleInfo(module_finder, name, ispkg)
+
+ A namedtuple that holds a brief summary of a module's info.
+
 
 .. function:: extend_path(path, name)
 
@@ -139,7 +143,7 @@
 
 .. 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* should be either ``None`` or a list of paths to look for modules in.
@@ -160,7 +164,7 @@
 
 .. 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* should be either ``None`` or a list of paths to look for modules in.
diff --git a/Lib/pkgutil.py b/Lib/pkgutil.py
--- a/Lib/pkgutil.py
+++ b/Lib/pkgutil.py
@@ -1,5 +1,6 @@
 """Utilities to support packages."""
 
+from collections import namedtuple
 from functools import singledispatch as simplegeneric
 import importlib
 import importlib.util
@@ -14,9 +15,14 @@
 'get_importer', 'iter_importers', 'get_loader', 'find_loader',
 'walk_packages', 'iter_modules', 'get_data',
 '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):
 """Return the finder-specific module spec."""
 # Works with legacy finders.
@@ -45,7 +51,7 @@
 
 
 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.
 
 'path' should be either None or a list of paths to look for
@@ -78,31 +84,31 @@
 return True
 m[p] = True
 
- for importer, name, ispkg in iter_modules(path, prefix):
- yield importer, name, ispkg
+ for info in iter_modules(path, prefix):
+ yield info
 
- if ispkg:
+ if info.ispkg:
 try:
- __import__(name)
+ __import__(info.name)
 except ImportError:
 if onerror is not None:
- onerror(name)
+ onerror(info.name)
 except Exception:
 if onerror is not None:
- onerror(name)
+ onerror(info.name)
 else:
 raise
 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
 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=''):
- """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.
 
 'path' should be either None or a list of paths to look for
@@ -111,7 +117,6 @@
 'prefix' is a string to output on the front of every module name
 on output.
 """
-
 if path is None:
 importers = iter_importers()
 else:
@@ -122,7 +127,7 @@
 for name, ispkg in iter_importer_modules(i, prefix):
 if name not in yielded:
 yielded[name] = 1
- yield i, name, ispkg
+ yield ModuleInfo(i, name, ispkg)
 
 
 @simplegeneric
diff --git a/Lib/test/test_pkgutil.py b/Lib/test/test_pkgutil.py
--- a/Lib/test/test_pkgutil.py
+++ b/Lib/test/test_pkgutil.py
@@ -81,8 +81,9 @@
 self.assertEqual(res2, RESOURCE_DATA)
 
 names = []
- for loader, name, ispkg in pkgutil.iter_modules([zip_file]):
- names.append(name)
+ for moduleinfo in pkgutil.iter_modules([zip_file]):
+ self.assertIsInstance(moduleinfo, pkgutil.ModuleInfo)
+ names.append(moduleinfo.name)
 self.assertEqual(names, ['test_getdata_zipfile'])
 
 del sys.path[0]
diff --git a/Lib/test/test_runpy.py b/Lib/test/test_runpy.py
--- a/Lib/test/test_runpy.py
+++ b/Lib/test/test_runpy.py
@@ -577,13 +577,14 @@
 self.addCleanup(self._del_pkg, pkg_dir)
 for depth in range(2, max_depth+1):
 self._add_relative_modules(pkg_dir, "", depth)
- for finder, mod_name, ispkg in pkgutil.walk_packages([pkg_dir]):
- self.assertIsInstance(finder,
+ for moduleinfo in pkgutil.walk_packages([pkg_dir]):
+ self.assertIsInstance(moduleinfo, pkgutil.ModuleInfo)
+ self.assertIsInstance(moduleinfo.module_finder,
 importlib.machinery.FileFinder)
- if ispkg:
- expected_packages.remove(mod_name)
+ if moduleinfo.ispkg:
+ expected_packages.remove(moduleinfo.name)
 else:
- expected_modules.remove(mod_name)
+ expected_modules.remove(moduleinfo.name)
 self.assertEqual(len(expected_packages), 0, expected_packages)
 self.assertEqual(len(expected_modules), 0, expected_modules)
 
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -7845,6 +7845,9 @@
 - Issue #16809: Tkinter's splitlist() and split() methods now accept Tcl_Obj
 argument.
 
+- Issue #17211: Yield a namedtuple in pkgutil.
+ Patch by Ramchandra Apte.
+
 - Issue #18324: set_payload now correctly handles binary input. This also
 supersedes the previous fixes for #14360, #1717, and #16564.
 
-- 
Repository URL: https://hg.python.org/cpython


More information about the Python-checkins mailing list

AltStyle によって変換されたページ (->オリジナル) /