diff options
Diffstat (limited to 'Lib/importlib/metadata.py')
-rw-r--r-- | Lib/importlib/metadata.py | 63 |
1 files changed, 51 insertions, 12 deletions
diff --git a/Lib/importlib/metadata.py b/Lib/importlib/metadata.py index 3b46142..e230766 100644 --- a/Lib/importlib/metadata.py +++ b/Lib/importlib/metadata.py @@ -19,6 +19,7 @@ from itertools import starmap __all__ = [ 'Distribution', + 'DistributionFinder', 'PackageNotFoundError', 'distribution', 'distributions', @@ -158,7 +159,7 @@ class Distribution: metadata cannot be found. """ for resolver in cls._discover_resolvers(): - dists = resolver(name) + dists = resolver(DistributionFinder.Context(name=name)) dist = next(dists, None) if dist is not None: return dist @@ -166,17 +167,34 @@ class Distribution: raise PackageNotFoundError(name) @classmethod - def discover(cls): + def discover(cls, **kwargs): """Return an iterable of Distribution objects for all packages. + Pass a ``context`` or pass keyword arguments for constructing + a context. + + :context: A ``DistributionFinder.Context`` object. :return: Iterable of Distribution objects for all packages. """ + context = kwargs.pop('context', None) + if context and kwargs: + raise ValueError("cannot accept context and kwargs") + context = context or DistributionFinder.Context(**kwargs) return itertools.chain.from_iterable( - resolver() + resolver(context) for resolver in cls._discover_resolvers() ) @staticmethod + def at(path): + """Return a Distribution for the indicated metadata path + + :param path: a string or path-like object + :return: a concrete Distribution instance for the path + """ + return PathDistribution(pathlib.Path(path)) + + @staticmethod def _discover_resolvers(): """Search the meta_path for resolvers.""" declared = ( @@ -215,7 +233,7 @@ class Distribution: def files(self): """Files in this distribution. - :return: Iterable of PackagePath for this distribution or None + :return: List of PackagePath for this distribution or None Result is `None` if the metadata file that enumerates files (i.e. RECORD for dist-info or SOURCES.txt for egg-info) is @@ -231,7 +249,7 @@ class Distribution: result.dist = self return result - return file_lines and starmap(make_file, csv.reader(file_lines)) + return file_lines and list(starmap(make_file, csv.reader(file_lines))) def _read_files_distinfo(self): """ @@ -251,7 +269,8 @@ class Distribution: @property def requires(self): """Generated requirements specified for this Distribution""" - return self._read_dist_info_reqs() or self._read_egg_info_reqs() + reqs = self._read_dist_info_reqs() or self._read_egg_info_reqs() + return reqs and list(reqs) def _read_dist_info_reqs(self): return self.metadata.get_all('Requires-Dist') @@ -312,15 +331,35 @@ class DistributionFinder(MetaPathFinder): A MetaPathFinder capable of discovering installed distributions. """ + class Context: + + name = None + """ + Specific name for which a distribution finder should match. + """ + + def __init__(self, **kwargs): + vars(self).update(kwargs) + + @property + def path(self): + """ + The path that a distribution finder should search. + """ + return vars(self).get('path', sys.path) + + @property + def pattern(self): + return '.*' if self.name is None else re.escape(self.name) + @abc.abstractmethod - def find_distributions(self, name=None, path=None): + def find_distributions(self, context=Context()): """ Find distributions. Return an iterable of all Distribution instances capable of - loading the metadata for packages matching the ``name`` - (or all names if not supplied) along the paths in the list - of directories ``path`` (defaults to sys.path). + loading the metadata for packages matching the ``context``, + a DistributionFinder.Context instance. """ @@ -352,12 +391,12 @@ def distribution(package): return Distribution.from_name(package) -def distributions(): +def distributions(**kwargs): """Get all ``Distribution`` instances in the current environment. :return: An iterable of ``Distribution`` instances. """ - return Distribution.discover() + return Distribution.discover(**kwargs) def metadata(package): |