mirror of
https://github.com/clinton-hall/nzbToMedia.git
synced 2025-08-21 13:53:15 -07:00
Updated importlib-metadata to 2.1.3
This commit is contained in:
parent
684cca8c9b
commit
f1624a586f
17 changed files with 154 additions and 64 deletions
|
@ -1,3 +1,5 @@
|
|||
from __future__ import unicode_literals, absolute_import
|
||||
|
||||
import io
|
||||
import os
|
||||
import re
|
||||
|
@ -5,8 +7,6 @@ import abc
|
|||
import csv
|
||||
import sys
|
||||
import zipp
|
||||
import email
|
||||
import pathlib
|
||||
import operator
|
||||
import functools
|
||||
import itertools
|
||||
|
@ -14,18 +14,30 @@ import posixpath
|
|||
import collections
|
||||
|
||||
from ._compat import (
|
||||
NullFinder,
|
||||
PyPy_repr,
|
||||
install,
|
||||
)
|
||||
|
||||
from configparser import ConfigParser
|
||||
from contextlib import suppress
|
||||
NullFinder,
|
||||
ConfigParser,
|
||||
suppress,
|
||||
map,
|
||||
FileNotFoundError,
|
||||
IsADirectoryError,
|
||||
NotADirectoryError,
|
||||
PermissionError,
|
||||
pathlib,
|
||||
ModuleNotFoundError,
|
||||
MetaPathFinder,
|
||||
email_message_from_string,
|
||||
PyPy_repr,
|
||||
unique_ordered,
|
||||
str,
|
||||
)
|
||||
from importlib import import_module
|
||||
from importlib.abc import MetaPathFinder
|
||||
from itertools import starmap
|
||||
|
||||
|
||||
__metaclass__ = type
|
||||
|
||||
|
||||
__all__ = [
|
||||
'Distribution',
|
||||
'DistributionFinder',
|
||||
|
@ -37,7 +49,7 @@ __all__ = [
|
|||
'metadata',
|
||||
'requires',
|
||||
'version',
|
||||
]
|
||||
]
|
||||
|
||||
|
||||
class PackageNotFoundError(ModuleNotFoundError):
|
||||
|
@ -49,13 +61,13 @@ class PackageNotFoundError(ModuleNotFoundError):
|
|||
|
||||
@property
|
||||
def name(self):
|
||||
(name,) = self.args
|
||||
name, = self.args
|
||||
return name
|
||||
|
||||
|
||||
class EntryPoint(
|
||||
PyPy_repr, collections.namedtuple('EntryPointBase', 'name value group')
|
||||
):
|
||||
PyPy_repr,
|
||||
collections.namedtuple('EntryPointBase', 'name value group')):
|
||||
"""An entry point as defined by Python packaging conventions.
|
||||
|
||||
See `the packaging docs on entry points
|
||||
|
@ -65,9 +77,9 @@ class EntryPoint(
|
|||
|
||||
pattern = re.compile(
|
||||
r'(?P<module>[\w.]+)\s*'
|
||||
r'(:\s*(?P<attr>[\w.]+))?\s*'
|
||||
r'(?P<extras>\[.*\])?\s*$'
|
||||
)
|
||||
r'(:\s*(?P<attr>[\w.]+)\s*)?'
|
||||
r'((?P<extras>\[.*\])\s*)?$'
|
||||
)
|
||||
"""
|
||||
A regular expression describing the syntax for an entry point,
|
||||
which might look like:
|
||||
|
@ -115,7 +127,7 @@ class EntryPoint(
|
|||
cls(name, value, group)
|
||||
for group in config.sections()
|
||||
for name, value in config.items(group)
|
||||
]
|
||||
]
|
||||
|
||||
@classmethod
|
||||
def _from_text(cls, text):
|
||||
|
@ -139,7 +151,7 @@ class EntryPoint(
|
|||
return (
|
||||
self.__class__,
|
||||
(self.name, self.value, self.group),
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
class PackagePath(pathlib.PurePosixPath):
|
||||
|
@ -217,8 +229,9 @@ class Distribution:
|
|||
raise ValueError("cannot accept context and kwargs")
|
||||
context = context or DistributionFinder.Context(**kwargs)
|
||||
return itertools.chain.from_iterable(
|
||||
resolver(context) for resolver in cls._discover_resolvers()
|
||||
)
|
||||
resolver(context)
|
||||
for resolver in cls._discover_resolvers()
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def at(path):
|
||||
|
@ -233,20 +246,20 @@ class Distribution:
|
|||
def _discover_resolvers():
|
||||
"""Search the meta_path for resolvers."""
|
||||
declared = (
|
||||
getattr(finder, 'find_distributions', None) for finder in sys.meta_path
|
||||
)
|
||||
getattr(finder, 'find_distributions', None)
|
||||
for finder in sys.meta_path
|
||||
)
|
||||
return filter(None, declared)
|
||||
|
||||
@classmethod
|
||||
def _local(cls, root='.'):
|
||||
from pep517 import build, meta
|
||||
|
||||
system = build.compat_system(root)
|
||||
builder = functools.partial(
|
||||
meta.build,
|
||||
source_dir=root,
|
||||
system=system,
|
||||
)
|
||||
)
|
||||
return PathDistribution(zipp.Path(meta.build_as_zip(builder)))
|
||||
|
||||
@property
|
||||
|
@ -263,8 +276,8 @@ class Distribution:
|
|||
# effect is to just end up using the PathDistribution's self._path
|
||||
# (which points to the egg-info file) attribute unchanged.
|
||||
or self.read_text('')
|
||||
)
|
||||
return email.message_from_string(text)
|
||||
)
|
||||
return email_message_from_string(text)
|
||||
|
||||
@property
|
||||
def version(self):
|
||||
|
@ -330,10 +343,9 @@ class Distribution:
|
|||
section_pairs = cls._read_sections(source.splitlines())
|
||||
sections = {
|
||||
section: list(map(operator.itemgetter('line'), results))
|
||||
for section, results in itertools.groupby(
|
||||
section_pairs, operator.itemgetter('section')
|
||||
)
|
||||
}
|
||||
for section, results in
|
||||
itertools.groupby(section_pairs, operator.itemgetter('section'))
|
||||
}
|
||||
return cls._convert_egg_info_reqs_to_simple_reqs(sections)
|
||||
|
||||
@staticmethod
|
||||
|
@ -357,7 +369,6 @@ class Distribution:
|
|||
requirement. This method converts the former to the
|
||||
latter. See _test_deps_from_requires_text for an example.
|
||||
"""
|
||||
|
||||
def make_condition(name):
|
||||
return name and 'extra == "{name}"'.format(name=name)
|
||||
|
||||
|
@ -436,7 +447,7 @@ class FastPath:
|
|||
|
||||
def children(self):
|
||||
with suppress(Exception):
|
||||
return os.listdir(self.root or '')
|
||||
return os.listdir(self.root or '.')
|
||||
with suppress(Exception):
|
||||
return self.zip_children()
|
||||
return []
|
||||
|
@ -446,21 +457,23 @@ class FastPath:
|
|||
names = zip_path.root.namelist()
|
||||
self.joinpath = zip_path.joinpath
|
||||
|
||||
return dict.fromkeys(child.split(posixpath.sep, 1)[0] for child in names)
|
||||
return unique_ordered(
|
||||
child.split(posixpath.sep, 1)[0]
|
||||
for child in names
|
||||
)
|
||||
|
||||
def search(self, name):
|
||||
return (
|
||||
self.joinpath(child)
|
||||
for child in self.children()
|
||||
if name.matches(child, self.base)
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
class Prepared:
|
||||
"""
|
||||
A prepared search for metadata on a possibly-named package.
|
||||
"""
|
||||
|
||||
normalized = None
|
||||
suffixes = '.dist-info', '.egg-info'
|
||||
exact_matches = [''][:0]
|
||||
|
@ -470,7 +483,8 @@ class Prepared:
|
|||
if name is None:
|
||||
return
|
||||
self.normalized = self.normalize(name)
|
||||
self.exact_matches = [self.normalized + suffix for suffix in self.suffixes]
|
||||
self.exact_matches = [
|
||||
self.normalized + suffix for suffix in self.suffixes]
|
||||
|
||||
@staticmethod
|
||||
def normalize(name):
|
||||
|
@ -493,12 +507,13 @@ class Prepared:
|
|||
name, sep, rest = pre.partition('-')
|
||||
return (
|
||||
low in self.exact_matches
|
||||
or ext in self.suffixes
|
||||
and (not self.normalized or name.replace('.', '_') == self.normalized)
|
||||
or ext in self.suffixes and (
|
||||
not self.normalized or
|
||||
name.replace('.', '_') == self.normalized
|
||||
)
|
||||
# legacy case:
|
||||
or self.is_egg(base)
|
||||
and low == 'egg-info'
|
||||
)
|
||||
or self.is_egg(base) and low == 'egg-info'
|
||||
)
|
||||
|
||||
def is_egg(self, base):
|
||||
normalized = self.legacy_normalize(self.name or '')
|
||||
|
@ -507,8 +522,7 @@ class Prepared:
|
|||
return (
|
||||
base == versionless_egg_name
|
||||
or base.startswith(prefix)
|
||||
and base.endswith('.egg')
|
||||
)
|
||||
and base.endswith('.egg'))
|
||||
|
||||
|
||||
@install
|
||||
|
@ -535,8 +549,9 @@ class MetadataPathFinder(NullFinder, DistributionFinder):
|
|||
def _search_paths(cls, name, paths):
|
||||
"""Find metadata directories in paths heuristically."""
|
||||
return itertools.chain.from_iterable(
|
||||
path.search(Prepared(name)) for path in map(FastPath, paths)
|
||||
)
|
||||
path.search(Prepared(name))
|
||||
for path in map(FastPath, paths)
|
||||
)
|
||||
|
||||
|
||||
class PathDistribution(Distribution):
|
||||
|
@ -549,15 +564,9 @@ class PathDistribution(Distribution):
|
|||
self._path = path
|
||||
|
||||
def read_text(self, filename):
|
||||
with suppress(
|
||||
FileNotFoundError,
|
||||
IsADirectoryError,
|
||||
KeyError,
|
||||
NotADirectoryError,
|
||||
PermissionError,
|
||||
):
|
||||
with suppress(FileNotFoundError, IsADirectoryError, KeyError,
|
||||
NotADirectoryError, PermissionError):
|
||||
return self._path.joinpath(filename).read_text(encoding='utf-8')
|
||||
|
||||
read_text.__doc__ = Distribution.read_text.__doc__
|
||||
|
||||
def locate_file(self, path):
|
||||
|
@ -605,11 +614,15 @@ def entry_points():
|
|||
|
||||
:return: EntryPoint objects for all installed packages.
|
||||
"""
|
||||
eps = itertools.chain.from_iterable(dist.entry_points for dist in distributions())
|
||||
eps = itertools.chain.from_iterable(
|
||||
dist.entry_points for dist in distributions())
|
||||
by_group = operator.attrgetter('group')
|
||||
ordered = sorted(eps, key=by_group)
|
||||
grouped = itertools.groupby(ordered, by_group)
|
||||
return {group: tuple(eps) for group, eps in grouped}
|
||||
return {
|
||||
group: tuple(eps)
|
||||
for group, eps in grouped
|
||||
}
|
||||
|
||||
|
||||
def files(distribution_name):
|
||||
|
|
|
@ -1,7 +1,59 @@
|
|||
from __future__ import absolute_import, unicode_literals
|
||||
|
||||
import io
|
||||
import abc
|
||||
import sys
|
||||
import email
|
||||
|
||||
|
||||
__all__ = ['install', 'NullFinder', 'PyPy_repr']
|
||||
if sys.version_info > (3,): # pragma: nocover
|
||||
import builtins
|
||||
from configparser import ConfigParser
|
||||
import contextlib
|
||||
FileNotFoundError = builtins.FileNotFoundError
|
||||
IsADirectoryError = builtins.IsADirectoryError
|
||||
NotADirectoryError = builtins.NotADirectoryError
|
||||
PermissionError = builtins.PermissionError
|
||||
map = builtins.map
|
||||
from itertools import filterfalse
|
||||
else: # pragma: nocover
|
||||
from backports.configparser import ConfigParser
|
||||
from itertools import imap as map # type: ignore
|
||||
from itertools import ifilterfalse as filterfalse
|
||||
import contextlib2 as contextlib
|
||||
FileNotFoundError = IOError, OSError
|
||||
IsADirectoryError = IOError, OSError
|
||||
NotADirectoryError = IOError, OSError
|
||||
PermissionError = IOError, OSError
|
||||
|
||||
str = type('')
|
||||
|
||||
suppress = contextlib.suppress
|
||||
|
||||
if sys.version_info > (3, 5): # pragma: nocover
|
||||
import pathlib
|
||||
else: # pragma: nocover
|
||||
import pathlib2 as pathlib
|
||||
|
||||
try:
|
||||
ModuleNotFoundError = builtins.FileNotFoundError
|
||||
except (NameError, AttributeError): # pragma: nocover
|
||||
ModuleNotFoundError = ImportError # type: ignore
|
||||
|
||||
|
||||
if sys.version_info >= (3,): # pragma: nocover
|
||||
from importlib.abc import MetaPathFinder
|
||||
else: # pragma: nocover
|
||||
class MetaPathFinder(object):
|
||||
__metaclass__ = abc.ABCMeta
|
||||
|
||||
|
||||
__metaclass__ = type
|
||||
__all__ = [
|
||||
'install', 'NullFinder', 'MetaPathFinder', 'ModuleNotFoundError',
|
||||
'pathlib', 'ConfigParser', 'map', 'suppress', 'FileNotFoundError',
|
||||
'NotADirectoryError', 'email_message_from_string',
|
||||
]
|
||||
|
||||
|
||||
def install(cls):
|
||||
|
@ -25,12 +77,11 @@ def disable_stdlib_finder():
|
|||
See #91 for more background for rationale on this sketchy
|
||||
behavior.
|
||||
"""
|
||||
|
||||
def matches(finder):
|
||||
return getattr(
|
||||
finder, '__module__', None
|
||||
) == '_frozen_importlib_external' and hasattr(finder, 'find_distributions')
|
||||
|
||||
return (
|
||||
getattr(finder, '__module__', None) == '_frozen_importlib_external'
|
||||
and hasattr(finder, 'find_distributions')
|
||||
)
|
||||
for finder in filter(matches, sys.meta_path): # pragma: nocover
|
||||
del finder.find_distributions
|
||||
|
||||
|
@ -40,7 +91,6 @@ class NullFinder:
|
|||
A "Finder" (aka "MetaClassFinder") that never finds any modules,
|
||||
but may find distributions.
|
||||
"""
|
||||
|
||||
@staticmethod
|
||||
def find_spec(*args, **kwargs):
|
||||
return None
|
||||
|
@ -54,22 +104,49 @@ class NullFinder:
|
|||
find_module = find_spec
|
||||
|
||||
|
||||
def py2_message_from_string(text): # nocoverpy3
|
||||
# Work around https://bugs.python.org/issue25545 where
|
||||
# email.message_from_string cannot handle Unicode on Python 2.
|
||||
io_buffer = io.StringIO(text)
|
||||
return email.message_from_file(io_buffer)
|
||||
|
||||
|
||||
email_message_from_string = (
|
||||
py2_message_from_string
|
||||
if sys.version_info < (3,) else
|
||||
email.message_from_string
|
||||
)
|
||||
|
||||
|
||||
class PyPy_repr:
|
||||
"""
|
||||
Override repr for EntryPoint objects on PyPy to avoid __iter__ access.
|
||||
Ref #97, #102.
|
||||
"""
|
||||
|
||||
affected = hasattr(sys, 'pypy_version_info')
|
||||
|
||||
def __compat_repr__(self): # pragma: nocover
|
||||
def make_param(name):
|
||||
value = getattr(self, name)
|
||||
return '{name}={value!r}'.format(**locals())
|
||||
|
||||
params = ', '.join(map(make_param, self._fields))
|
||||
return 'EntryPoint({params})'.format(**locals())
|
||||
|
||||
if affected: # pragma: nocover
|
||||
__repr__ = __compat_repr__
|
||||
del affected
|
||||
|
||||
|
||||
# from itertools recipes
|
||||
def unique_everseen(iterable): # pragma: nocover
|
||||
"List unique elements, preserving order. Remember all elements ever seen."
|
||||
seen = set()
|
||||
seen_add = seen.add
|
||||
|
||||
for element in filterfalse(seen.__contains__, iterable):
|
||||
seen_add(element)
|
||||
yield element
|
||||
|
||||
|
||||
unique_ordered = (
|
||||
unique_everseen if sys.version_info < (3, 7) else dict.fromkeys)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue