153 lines
4.3 KiB
Python
153 lines
4.3 KiB
Python
|
from __future__ import absolute_import, unicode_literals
|
||
|
|
||
|
import io
|
||
|
import abc
|
||
|
import sys
|
||
|
import email
|
||
|
|
||
|
|
||
|
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):
|
||
|
"""
|
||
|
Class decorator for installation on sys.meta_path.
|
||
|
|
||
|
Adds the backport DistributionFinder to sys.meta_path and
|
||
|
attempts to disable the finder functionality of the stdlib
|
||
|
DistributionFinder.
|
||
|
"""
|
||
|
sys.meta_path.append(cls())
|
||
|
disable_stdlib_finder()
|
||
|
return cls
|
||
|
|
||
|
|
||
|
def disable_stdlib_finder():
|
||
|
"""
|
||
|
Give the backport primacy for discovering path-based distributions
|
||
|
by monkey-patching the stdlib O_O.
|
||
|
|
||
|
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')
|
||
|
)
|
||
|
for finder in filter(matches, sys.meta_path): # pragma: nocover
|
||
|
del finder.find_distributions
|
||
|
|
||
|
|
||
|
class NullFinder:
|
||
|
"""
|
||
|
A "Finder" (aka "MetaClassFinder") that never finds any modules,
|
||
|
but may find distributions.
|
||
|
"""
|
||
|
@staticmethod
|
||
|
def find_spec(*args, **kwargs):
|
||
|
return None
|
||
|
|
||
|
# In Python 2, the import system requires finders
|
||
|
# to have a find_module() method, but this usage
|
||
|
# is deprecated in Python 3 in favor of find_spec().
|
||
|
# For the purposes of this finder (i.e. being present
|
||
|
# on sys.meta_path but having no other import
|
||
|
# system functionality), the two methods are identical.
|
||
|
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)
|