summaryrefslogtreecommitdiffstats
path: root/Lib/importlib/_bootstrap_external.py
diff options
context:
space:
mode:
authorJason R. Coombs <jaraco@jaraco.com>2019-05-24 23:59:01 (GMT)
committerBarry Warsaw <barry@python.org>2019-05-24 23:59:01 (GMT)
commit1bbf7b661f0ac8aac12d5531928d9a85c98ec1a9 (patch)
treec0c36b2d2756929655da47e4843188363886fce5 /Lib/importlib/_bootstrap_external.py
parent6dbbe748e101a173b4cff8aada41e9313e287e0f (diff)
downloadcpython-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.py52
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: