mirror of https://github.com/python/cpython
bpo-39297: Update for importlib_metadata 1.4. (GH-17947)
* bpo-39297: Update for importlib_metadata 1.4. Includes performance updates. * 📜🤖 Added by blurb_it. * Update blurb Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com>
This commit is contained in:
parent
5d978a2e73
commit
136735c1a2
|
@ -10,6 +10,7 @@ import zipfile
|
|||
import operator
|
||||
import functools
|
||||
import itertools
|
||||
import posixpath
|
||||
import collections
|
||||
|
||||
from configparser import ConfigParser
|
||||
|
@ -371,10 +372,6 @@ class DistributionFinder(MetaPathFinder):
|
|||
"""
|
||||
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, context=Context()):
|
||||
"""
|
||||
|
@ -386,6 +383,73 @@ class DistributionFinder(MetaPathFinder):
|
|||
"""
|
||||
|
||||
|
||||
class FastPath:
|
||||
"""
|
||||
Micro-optimized class for searching a path for
|
||||
children.
|
||||
"""
|
||||
|
||||
def __init__(self, root):
|
||||
self.root = root
|
||||
|
||||
def joinpath(self, child):
|
||||
return pathlib.Path(self.root, child)
|
||||
|
||||
def children(self):
|
||||
with suppress(Exception):
|
||||
return os.listdir(self.root or '')
|
||||
with suppress(Exception):
|
||||
return self.zip_children()
|
||||
return []
|
||||
|
||||
def zip_children(self):
|
||||
zip_path = zipfile.Path(self.root)
|
||||
names = zip_path.root.namelist()
|
||||
self.joinpath = zip_path.joinpath
|
||||
|
||||
return (
|
||||
posixpath.split(child)[0]
|
||||
for child in names
|
||||
)
|
||||
|
||||
def is_egg(self, search):
|
||||
root_n_low = os.path.split(self.root)[1].lower()
|
||||
|
||||
return (
|
||||
root_n_low == search.normalized + '.egg'
|
||||
or root_n_low.startswith(search.prefix)
|
||||
and root_n_low.endswith('.egg'))
|
||||
|
||||
def search(self, name):
|
||||
for child in self.children():
|
||||
n_low = child.lower()
|
||||
if (n_low in name.exact_matches
|
||||
or n_low.startswith(name.prefix)
|
||||
and n_low.endswith(name.suffixes)
|
||||
# legacy case:
|
||||
or self.is_egg(name) and n_low == 'egg-info'):
|
||||
yield self.joinpath(child)
|
||||
|
||||
|
||||
class Prepared:
|
||||
"""
|
||||
A prepared search for metadata on a possibly-named package.
|
||||
"""
|
||||
normalized = ''
|
||||
prefix = ''
|
||||
suffixes = '.dist-info', '.egg-info'
|
||||
exact_matches = [''][:0]
|
||||
|
||||
def __init__(self, name):
|
||||
self.name = name
|
||||
if name is None:
|
||||
return
|
||||
self.normalized = name.lower().replace('-', '_')
|
||||
self.prefix = self.normalized + '-'
|
||||
self.exact_matches = [
|
||||
self.normalized + suffix for suffix in self.suffixes]
|
||||
|
||||
|
||||
class MetadataPathFinder(DistributionFinder):
|
||||
@classmethod
|
||||
def find_distributions(cls, context=DistributionFinder.Context()):
|
||||
|
@ -397,45 +461,17 @@ class MetadataPathFinder(DistributionFinder):
|
|||
(or all names if ``None`` indicated) along the paths in the list
|
||||
of directories ``context.path``.
|
||||
"""
|
||||
found = cls._search_paths(context.pattern, context.path)
|
||||
found = cls._search_paths(context.name, context.path)
|
||||
return map(PathDistribution, found)
|
||||
|
||||
@classmethod
|
||||
def _search_paths(cls, pattern, paths):
|
||||
def _search_paths(cls, name, 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)
|
||||
path.search(Prepared(name))
|
||||
for path in map(FastPath, 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):
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Improved performance of importlib.metadata distribution discovery and resilients to inaccessible sys.path entries (importlib_metadata v1.4.0).
|
Loading…
Reference in New Issue