Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
bpo-38121: Sync importlib.metadata with 0.22 backport
  • Loading branch information
jaraco committed Sep 11, 2019
commit d3b76ca5aa8e01e2ae3a535a8ede9a414429efd7
52 changes: 3 additions & 49 deletions Lib/importlib/_bootstrap_external.py
Original file line number Diff line number Diff line change
Expand Up @@ -1370,7 +1370,7 @@ def find_module(cls, fullname, path=None):
return spec.loader

@classmethod
def find_distributions(self, context=None):
def find_distributions(cls, *args, **kwargs):
"""
Find distributions.

Expand All @@ -1379,54 +1379,8 @@ def find_distributions(self, context=None):
(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))
from importlib.metadata import MetadataPathFinder
MetadataPathFinder.find_distributions(*args, **kwargs)
Comment thread
jaraco marked this conversation as resolved.
Outdated


class FileFinder:
Expand Down
91 changes: 75 additions & 16 deletions Lib/importlib/metadata.py
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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
Comment thread
pganssle marked this conversation as resolved.
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.
Expand All @@ -382,13 +436,13 @@ def locate_file(self, path):
return self._path.parent / path


def distribution(package):
"""Get the ``Distribution`` instance for the given package.
def distribution(distribution_name):
"""Get the ``Distribution`` instance for the named package.

:param package: The name of the package as a string.
:param distribution_name: The name of the distribution package as a string.
:return: A ``Distribution`` instance (or subclass thereof).
"""
return Distribution.from_name(package)
return Distribution.from_name(distribution_name)


def distributions(**kwargs):
Expand All @@ -399,23 +453,23 @@ def distributions(**kwargs):
return Distribution.discover(**kwargs)


def metadata(package):
"""Get the metadata for the package.
def metadata(distribution_name):
"""Get the metadata for the named package.

:param package: The name of the distribution package to query.
:param distribution_name: The name of the distribution package to query.
:return: An email.Message containing the parsed metadata.
"""
return Distribution.from_name(package).metadata
return Distribution.from_name(distribution_name).metadata


def version(package):
def version(distribution_name):
"""Get the version string for the named package.

:param package: The name of the distribution package to query.
:param distribution_name: The name of the distribution package to query.
:return: The version string for the package as defined in the package's
"Version" metadata key.
"""
return distribution(package).version
return distribution(distribution_name).version


def entry_points():
Expand All @@ -434,15 +488,20 @@ def entry_points():
}


def files(package):
return distribution(package).files
def files(distribution_name):
"""Return a list of files for the named package.

:param distribution_name: The name of the distribution package to query.
:return: List of files composing the distribution.
"""
return distribution(distribution_name).files


def requires(package):
def requires(distribution_name):
"""
Return a list of requirements for the indicated distribution.
Return a list of requirements for the named package.

:return: An iterator of requirements, suitable for
packaging.requirement.Requirement.
"""
return distribution(package).requires
return distribution(distribution_name).requires
Loading