From 83b48ec85f27b65b01969bfc453f30308ca9d138 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Wed, 11 Sep 2019 07:35:07 +0100 Subject: [PATCH] Move MetadataPathFinder back into the metadata package. Let importlib.PathFinder.find_distributions just call into MetadataPathFinder.find_distributions. Ref #88. --- Lib/importlib/_bootstrap_external.py | 63 ---------------------------- Lib/importlib/metadata.py | 54 ++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 63 deletions(-) delete mode 100644 Lib/importlib/_bootstrap_external.py diff --git a/Lib/importlib/_bootstrap_external.py b/Lib/importlib/_bootstrap_external.py deleted file mode 100644 index 88ea8574..00000000 --- a/Lib/importlib/_bootstrap_external.py +++ /dev/null @@ -1,63 +0,0 @@ -import os - - -# Merge the body of this class into _bootstrap_external: -class PathFinder: - @classmethod - def find_distributions(self, context=None): - """ - Find distributions. - - Return an iterable of all Distribution instances capable of - loading the metadata for packages matching ``context.name`` - (or all names if ``None`` indicated) along the paths in the list - of directories ``context.path``. - """ - from importlib.metadata import PathDistribution, DistributionFinder - if context is None: - context = DistributionFinder.Context() - found = self._search_paths(context.pattern, context.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 - import pathlib - PYPY_OPEN_BUG = False - if not PYPY_OPEN_BUG or os.path.isfile(path): # pragma: no branch - with suppress(Exception): - return zipfile.Path(path) - return pathlib.Path(path) - - @classmethod - def _matches_info(cls, normalized, item): - import re - template = r'{pattern}(-.*)?\.(dist|egg)-info' - manifest = template.format(pattern=normalized) - return re.match(manifest, item.name, flags=re.IGNORECASE) - - @classmethod - def _matches_legacy(cls, normalized, item): - import re - template = r'{pattern}-.*\.egg[\\/]EGG-INFO' - manifest = template.format(pattern=normalized) - return re.search(manifest, str(item), flags=re.IGNORECASE) - - @classmethod - def _search_path(cls, root, pattern): - if not root.is_dir(): - return () - normalized = pattern.replace('-', '_') - return (item for item in root.iterdir() - if cls._matches_info(normalized, item) - or cls._matches_legacy(normalized, item)) diff --git a/Lib/importlib/metadata.py b/Lib/importlib/metadata.py index e2307665..612cb911 100644 --- a/Lib/importlib/metadata.py +++ b/Lib/importlib/metadata.py @@ -1,10 +1,12 @@ import io +import os import re import abc import csv import sys import email import pathlib +import zipfile import operator import functools import itertools @@ -363,6 +365,58 @@ def find_distributions(self, context=Context()): """ +class MetadataPathFinder(DistributionFinder): + @classmethod + def find_distributions(cls, context=DistributionFinder.Context()): + """ + Find distributions. + + Return an iterable of all Distribution instances capable of + loading the metadata for packages matching ``context.name`` + (or all names if ``None`` indicated) along the paths in the list + of directories ``context.path``. + """ + found = cls._search_paths(context.pattern, context.path) + return map(PathDistribution, found) + + @classmethod + def _search_paths(cls, pattern, paths): + """Find metadata directories in paths heuristically.""" + return itertools.chain.from_iterable( + cls._search_path(path, pattern) + for path in map(cls._switch_path, paths) + ) + + @staticmethod + def _switch_path(path): + PYPY_OPEN_BUG = False + if not PYPY_OPEN_BUG or os.path.isfile(path): # pragma: no branch + with suppress(Exception): + return zipfile.Path(path) + return pathlib.Path(path) + + @classmethod + def _matches_info(cls, normalized, item): + template = r'{pattern}(-.*)?\.(dist|egg)-info' + manifest = template.format(pattern=normalized) + return re.match(manifest, item.name, flags=re.IGNORECASE) + + @classmethod + def _matches_legacy(cls, normalized, item): + template = r'{pattern}-.*\.egg[\\/]EGG-INFO' + manifest = template.format(pattern=normalized) + return re.search(manifest, str(item), flags=re.IGNORECASE) + + @classmethod + def _search_path(cls, root, pattern): + if not root.is_dir(): + return () + normalized = pattern.replace('-', '_') + return (item for item in root.iterdir() + if cls._matches_info(normalized, item) + or cls._matches_legacy(normalized, item)) + + class PathDistribution(Distribution): def __init__(self, path): """Construct a distribution from a path to the metadata directory.