mirror of
https://github.com/Tautulli/Tautulli.git
synced 2025-07-07 13:41:15 -07:00
Update importlib-metadata==5.0.0
[skip ci]
This commit is contained in:
parent
20be945e8c
commit
5bb9dbd0f6
3 changed files with 69 additions and 211 deletions
|
@ -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):
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
||||||
|
|
48
lib/importlib_metadata/_py39compat.py
Normal file
48
lib/importlib_metadata/_py39compat.py
Normal 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)
|
Loading…
Add table
Add a link
Reference in a new issue