Skip to content

[3.8] bpo-38121: Sync importlib.metadata with 0.22 backport (GH-15993) #16064

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Sep 12, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
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
[3.8] bpo-38121: Sync importlib.metadata with 0.22 backport (GH-15993)
* bpo-38121: Sync importlib.metadata with 0.22 backport

* 📜🤖 Added by blurb_it..
(cherry picked from commit 8ed6503)

Co-authored-by: Jason R. Coombs <jaraco@jaraco.com>
  • Loading branch information
jaraco committed Sep 12, 2019
commit 3e206f4e1858fd4093124c8780f5021574b51d9d
52 changes: 3 additions & 49 deletions Lib/importlib/_bootstrap_external.py
Original file line number Diff line number Diff line change
Expand Up @@ -1369,7 +1369,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 @@ -1378,54 +1378,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
return MetadataPathFinder.find_distributions(*args, **kwargs)


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
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
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Update parameter names on functions in importlib.metadata matching the changes in the 0.22 release of importlib_metadata.
Loading