Update importlib-metadata==5.0.0

[skip ci]
This commit is contained in:
JonnyWong16 2022-11-12 17:02:37 -08:00
parent 20be945e8c
commit 5bb9dbd0f6
No known key found for this signature in database
GPG key ID: B1F1F9807184697A
3 changed files with 69 additions and 211 deletions

View file

@ -14,7 +14,7 @@ import itertools
import posixpath import posixpath
import collections import collections
from . import _adapters, _meta from . import _adapters, _meta, _py39compat
from ._collections import FreezableDefaultDict, Pair from ._collections import FreezableDefaultDict, Pair
from ._compat import ( from ._compat import (
NullFinder, NullFinder,
@ -29,7 +29,7 @@ from contextlib import suppress
from importlib import import_module from importlib import import_module
from importlib.abc import MetaPathFinder from importlib.abc import MetaPathFinder
from itertools import starmap from itertools import starmap
from typing import List, Mapping, Optional, Union from typing import List, Mapping, Optional
__all__ = [ __all__ = [
@ -189,6 +189,10 @@ class EntryPoint(DeprecatedTuple):
following the attr, and following any extras. following the attr, and following any extras.
""" """
name: str
value: str
group: str
dist: Optional['Distribution'] = None dist: Optional['Distribution'] = None
def __init__(self, name, value, group): def __init__(self, name, value, group):
@ -223,17 +227,6 @@ class EntryPoint(DeprecatedTuple):
vars(self).update(dist=dist) vars(self).update(dist=dist)
return self return self
def __iter__(self):
"""
Supply iter so one may construct dicts of EntryPoints by name.
"""
msg = (
"Construction of dict of EntryPoints is deprecated in "
"favor of EntryPoints."
)
warnings.warn(msg, DeprecationWarning)
return iter((self.name, self))
def matches(self, **params): def matches(self, **params):
""" """
EntryPoint matches the given parameters. EntryPoint matches the given parameters.
@ -279,77 +272,7 @@ class EntryPoint(DeprecatedTuple):
return hash(self._key()) return hash(self._key())
class DeprecatedList(list): class EntryPoints(tuple):
"""
Allow an otherwise immutable object to implement mutability
for compatibility.
>>> recwarn = getfixture('recwarn')
>>> dl = DeprecatedList(range(3))
>>> dl[0] = 1
>>> dl.append(3)
>>> del dl[3]
>>> dl.reverse()
>>> dl.sort()
>>> dl.extend([4])
>>> dl.pop(-1)
4
>>> dl.remove(1)
>>> dl += [5]
>>> dl + [6]
[1, 2, 5, 6]
>>> dl + (6,)
[1, 2, 5, 6]
>>> dl.insert(0, 0)
>>> dl
[0, 1, 2, 5]
>>> dl == [0, 1, 2, 5]
True
>>> dl == (0, 1, 2, 5)
True
>>> len(recwarn)
1
"""
__slots__ = ()
_warn = functools.partial(
warnings.warn,
"EntryPoints list interface is deprecated. Cast to list if needed.",
DeprecationWarning,
stacklevel=pypy_partial(2),
)
def _wrap_deprecated_method(method_name: str): # type: ignore
def wrapped(self, *args, **kwargs):
self._warn()
return getattr(super(), method_name)(*args, **kwargs)
return method_name, wrapped
locals().update(
map(
_wrap_deprecated_method,
'__setitem__ __delitem__ append reverse extend pop remove '
'__iadd__ insert sort'.split(),
)
)
def __add__(self, other):
if not isinstance(other, tuple):
self._warn()
other = tuple(other)
return self.__class__(tuple(self) + other)
def __eq__(self, other):
if not isinstance(other, tuple):
self._warn()
other = tuple(other)
return tuple(self).__eq__(other)
class EntryPoints(DeprecatedList):
""" """
An immutable collection of selectable EntryPoint objects. An immutable collection of selectable EntryPoint objects.
""" """
@ -360,14 +283,6 @@ class EntryPoints(DeprecatedList):
""" """
Get the EntryPoint in self matching name. Get the EntryPoint in self matching name.
""" """
if isinstance(name, int):
warnings.warn(
"Accessing entry points by index is deprecated. "
"Cast to tuple if needed.",
DeprecationWarning,
stacklevel=2,
)
return super().__getitem__(name)
try: try:
return next(iter(self.select(name=name))) return next(iter(self.select(name=name)))
except StopIteration: except StopIteration:
@ -378,7 +293,8 @@ class EntryPoints(DeprecatedList):
Select entry points from self that match the Select entry points from self that match the
given parameters (typically group and/or name). given parameters (typically group and/or name).
""" """
return EntryPoints(ep for ep in self if ep.matches(**params)) candidates = (_py39compat.ep_matches(ep, **params) for ep in self)
return EntryPoints(ep for ep, predicate in candidates if predicate)
@property @property
def names(self): def names(self):
@ -391,10 +307,6 @@ class EntryPoints(DeprecatedList):
def groups(self): def groups(self):
""" """
Return the set of all groups of all entry points. Return the set of all groups of all entry points.
For coverage while SelectableGroups is present.
>>> EntryPoints().groups
set()
""" """
return {ep.group for ep in self} return {ep.group for ep in self}
@ -410,101 +322,6 @@ class EntryPoints(DeprecatedList):
) )
class Deprecated:
"""
Compatibility add-in for mapping to indicate that
mapping behavior is deprecated.
>>> recwarn = getfixture('recwarn')
>>> class DeprecatedDict(Deprecated, dict): pass
>>> dd = DeprecatedDict(foo='bar')
>>> dd.get('baz', None)
>>> dd['foo']
'bar'
>>> list(dd)
['foo']
>>> list(dd.keys())
['foo']
>>> 'foo' in dd
True
>>> list(dd.values())
['bar']
>>> len(recwarn)
1
"""
_warn = functools.partial(
warnings.warn,
"SelectableGroups dict interface is deprecated. Use select.",
DeprecationWarning,
stacklevel=pypy_partial(2),
)
def __getitem__(self, name):
self._warn()
return super().__getitem__(name)
def get(self, name, default=None):
self._warn()
return super().get(name, default)
def __iter__(self):
self._warn()
return super().__iter__()
def __contains__(self, *args):
self._warn()
return super().__contains__(*args)
def keys(self):
self._warn()
return super().keys()
def values(self):
self._warn()
return super().values()
class SelectableGroups(Deprecated, dict):
"""
A backward- and forward-compatible result from
entry_points that fully implements the dict interface.
"""
@classmethod
def load(cls, eps):
by_group = operator.attrgetter('group')
ordered = sorted(eps, key=by_group)
grouped = itertools.groupby(ordered, by_group)
return cls((group, EntryPoints(eps)) for group, eps in grouped)
@property
def _all(self):
"""
Reconstruct a list of all entrypoints from the groups.
"""
groups = super(Deprecated, self).values()
return EntryPoints(itertools.chain.from_iterable(groups))
@property
def groups(self):
return self._all.groups
@property
def names(self):
"""
for coverage:
>>> SelectableGroups().names
set()
"""
return self._all.names
def select(self, **params):
if not params:
return self
return self._all.select(**params)
class PackagePath(pathlib.PurePosixPath): class PackagePath(pathlib.PurePosixPath):
"""A reference to a path in a package""" """A reference to a path in a package"""
@ -548,7 +365,7 @@ class Distribution:
""" """
@classmethod @classmethod
def from_name(cls, name): def from_name(cls, name: str):
"""Return the Distribution for the given package name. """Return the Distribution for the given package name.
:param name: The name of the distribution package to search for. :param name: The name of the distribution package to search for.
@ -556,13 +373,13 @@ class Distribution:
package, if found. package, if found.
:raises PackageNotFoundError: When the named package's distribution :raises PackageNotFoundError: When the named package's distribution
metadata cannot be found. metadata cannot be found.
:raises ValueError: When an invalid value is supplied for name.
""" """
for resolver in cls._discover_resolvers(): if not name:
dists = resolver(DistributionFinder.Context(name=name)) raise ValueError("A distribution name is required.")
dist = next(iter(dists), None) try:
if dist is not None: return next(cls.discover(name=name))
return dist except StopIteration:
else:
raise PackageNotFoundError(name) raise PackageNotFoundError(name)
@classmethod @classmethod
@ -1017,34 +834,26 @@ def version(distribution_name):
_unique = functools.partial( _unique = functools.partial(
unique_everseen, unique_everseen,
key=operator.attrgetter('_normalized_name'), key=_py39compat.normalized_name,
) )
""" """
Wrapper for ``distributions`` to return unique distributions by name. Wrapper for ``distributions`` to return unique distributions by name.
""" """
def entry_points(**params) -> Union[EntryPoints, SelectableGroups]: def entry_points(**params) -> EntryPoints:
"""Return EntryPoint objects for all installed packages. """Return EntryPoint objects for all installed packages.
Pass selection parameters (group or name) to filter the Pass selection parameters (group or name) to filter the
result to entry points matching those properties (see result to entry points matching those properties (see
EntryPoints.select()). EntryPoints.select()).
For compatibility, returns ``SelectableGroups`` object unless :return: EntryPoints for all installed packages.
selection parameters are supplied. In the future, this function
will return ``EntryPoints`` instead of ``SelectableGroups``
even when no selection parameters are supplied.
For maximum future compatibility, pass selection parameters
or invoke ``.select`` with parameters on the result.
:return: EntryPoints or SelectableGroups for all installed packages.
""" """
eps = itertools.chain.from_iterable( eps = itertools.chain.from_iterable(
dist.entry_points for dist in _unique(distributions()) dist.entry_points for dist in _unique(distributions())
) )
return SelectableGroups.load(eps).select(**params) return EntryPoints(eps).select(**params)
def files(distribution_name): def files(distribution_name):

View file

@ -8,6 +8,7 @@ __all__ = ['install', 'NullFinder', 'Protocol']
try: try:
from typing import Protocol from typing import Protocol
except ImportError: # pragma: no cover except ImportError: # pragma: no cover
# Python 3.7 compatibility
from typing_extensions import Protocol # type: ignore from typing_extensions import Protocol # type: ignore

View file

@ -0,0 +1,48 @@
"""
Compatibility layer with Python 3.8/3.9
"""
from typing import TYPE_CHECKING, Any, Optional, Tuple
if TYPE_CHECKING: # pragma: no cover
# Prevent circular imports on runtime.
from . import Distribution, EntryPoint
else:
Distribution = EntryPoint = Any
def normalized_name(dist: Distribution) -> Optional[str]:
"""
Honor name normalization for distributions that don't provide ``_normalized_name``.
"""
try:
return dist._normalized_name
except AttributeError:
from . import Prepared # -> delay to prevent circular imports.
return Prepared.normalize(getattr(dist, "name", None) or dist.metadata['Name'])
def ep_matches(ep: EntryPoint, **params) -> Tuple[EntryPoint, bool]:
"""
Workaround for ``EntryPoint`` objects without the ``matches`` method.
For the sake of convenience, a tuple is returned containing not only the
boolean value corresponding to the predicate evalutation, but also a compatible
``EntryPoint`` object that can be safely used at a later stage.
For example, the following sequences of expressions should be compatible:
# Sequence 1: using the compatibility layer
candidates = (_py39compat.ep_matches(ep, **params) for ep in entry_points)
[ep for ep, predicate in candidates if predicate]
# Sequence 2: using Python 3.9+
[ep for ep in entry_points if ep.matches(**params)]
"""
try:
return ep, ep.matches(**params)
except AttributeError:
from . import EntryPoint # -> delay to prevent circular imports.
# Reconstruct the EntryPoint object to make sure it is compatible.
_ep = EntryPoint(ep.name, ep.value, ep.group)
return _ep, _ep.matches(**params)