diff options
author | Jason R. Coombs <jaraco@jaraco.com> | 2019-05-24 23:59:01 (GMT) |
---|---|---|
committer | Barry Warsaw <barry@python.org> | 2019-05-24 23:59:01 (GMT) |
commit | 1bbf7b661f0ac8aac12d5531928d9a85c98ec1a9 (patch) | |
tree | c0c36b2d2756929655da47e4843188363886fce5 /Lib/importlib/_bootstrap_external.py | |
parent | 6dbbe748e101a173b4cff8aada41e9313e287e0f (diff) | |
download | cpython-1bbf7b661f0ac8aac12d5531928d9a85c98ec1a9.zip cpython-1bbf7b661f0ac8aac12d5531928d9a85c98ec1a9.tar.gz cpython-1bbf7b661f0ac8aac12d5531928d9a85c98ec1a9.tar.bz2 |
bpo-34632: Add importlib.metadata (GH-12547)
Add importlib.metadata module as forward port of the standalone importlib_metadata.
Diffstat (limited to 'Lib/importlib/_bootstrap_external.py')
-rw-r--r-- | Lib/importlib/_bootstrap_external.py | 52 |
1 files changed, 52 insertions, 0 deletions
diff --git a/Lib/importlib/_bootstrap_external.py b/Lib/importlib/_bootstrap_external.py index 7da0cd0..9b5db81 100644 --- a/Lib/importlib/_bootstrap_external.py +++ b/Lib/importlib/_bootstrap_external.py @@ -1363,6 +1363,58 @@ class PathFinder: return None return spec.loader + search_template = r'(?:{pattern}(-.*)?\.(dist|egg)-info|EGG-INFO)' + + @classmethod + def find_distributions(cls, name=None, path=None): + """ + 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). + """ + import re + from importlib.metadata import PathDistribution + if path is None: + path = sys.path + pattern = '.*' if name is None else re.escape(name) + found = cls._search_paths(pattern, path) + return map(PathDistribution, found) + + @classmethod + def _search_paths(cls, pattern, paths): + """Find metadata directories in paths heuristically.""" + import itertools + return itertools.chain.from_iterable( + cls._search_path(path, pattern) + for path in map(cls._switch_path, paths) + ) + + @staticmethod + def _switch_path(path): + from contextlib import suppress + import zipfile + from pathlib import Path + with suppress(Exception): + return zipfile.Path(path) + return Path(path) + + @classmethod + def _predicate(cls, pattern, root, item): + import re + return re.match(pattern, str(item.name), flags=re.IGNORECASE) + + @classmethod + def _search_path(cls, root, pattern): + if not root.is_dir(): + return () + normalized = pattern.replace('-', '_') + matcher = cls.search_template.format(pattern=normalized) + return (item for item in root.iterdir() + if cls._predicate(matcher, root, item)) + class FileFinder: |