mirror of
https://github.com/SickGear/SickGear.git
synced 2025-01-07 10:33:38 +00:00
Merge pull request #634 from JackDandy/feature/AddLibs
Add backports_abc 0.4 and singledispatch 3.4.0.3.
This commit is contained in:
commit
69608ce31e
4 changed files with 593 additions and 0 deletions
|
@ -19,6 +19,8 @@
|
||||||
* Update Requests library 2.7.0 (5d6d1bc) to 2.9.1 (a1c9b84)
|
* Update Requests library 2.7.0 (5d6d1bc) to 2.9.1 (a1c9b84)
|
||||||
* Update SimpleJSON library 3.8.0 (a37a9bd) to 3.8.1 (6022794)
|
* Update SimpleJSON library 3.8.0 (a37a9bd) to 3.8.1 (6022794)
|
||||||
* Update Six compatibility library 1.9.0 (r400) to 1.10.0 (r405)
|
* Update Six compatibility library 1.9.0 (r400) to 1.10.0 (r405)
|
||||||
|
* Add backports_abc 0.4
|
||||||
|
* Add singledispatch 3.4.0.3
|
||||||
* Change refactor email notifier
|
* Change refactor email notifier
|
||||||
* Change emails to Unicode aware
|
* Change emails to Unicode aware
|
||||||
|
|
||||||
|
|
202
lib/backports_abc.py
Normal file
202
lib/backports_abc.py
Normal file
|
@ -0,0 +1,202 @@
|
||||||
|
"""
|
||||||
|
Patch recently added ABCs into the standard lib module
|
||||||
|
``collections.abc`` (Py3) or ``collections`` (Py2).
|
||||||
|
|
||||||
|
Usage::
|
||||||
|
|
||||||
|
import backports_abc
|
||||||
|
backports_abc.patch()
|
||||||
|
|
||||||
|
or::
|
||||||
|
|
||||||
|
try:
|
||||||
|
from collections.abc import Generator
|
||||||
|
except ImportError:
|
||||||
|
from backports_abc import Generator
|
||||||
|
"""
|
||||||
|
|
||||||
|
try:
|
||||||
|
import collections.abc as _collections_abc
|
||||||
|
except ImportError:
|
||||||
|
import collections as _collections_abc
|
||||||
|
|
||||||
|
|
||||||
|
def mk_gen():
|
||||||
|
from abc import abstractmethod
|
||||||
|
|
||||||
|
required_methods = (
|
||||||
|
'__iter__', '__next__' if hasattr(iter(()), '__next__') else 'next',
|
||||||
|
'send', 'throw', 'close')
|
||||||
|
|
||||||
|
class Generator(_collections_abc.Iterator):
|
||||||
|
__slots__ = ()
|
||||||
|
|
||||||
|
if '__next__' in required_methods:
|
||||||
|
def __next__(self):
|
||||||
|
return self.send(None)
|
||||||
|
else:
|
||||||
|
def next(self):
|
||||||
|
return self.send(None)
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def send(self, value):
|
||||||
|
raise StopIteration
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def throw(self, typ, val=None, tb=None):
|
||||||
|
if val is None:
|
||||||
|
if tb is None:
|
||||||
|
raise typ
|
||||||
|
val = typ()
|
||||||
|
if tb is not None:
|
||||||
|
val = val.with_traceback(tb)
|
||||||
|
raise val
|
||||||
|
|
||||||
|
def close(self):
|
||||||
|
try:
|
||||||
|
self.throw(GeneratorExit)
|
||||||
|
except (GeneratorExit, StopIteration):
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
raise RuntimeError('generator ignored GeneratorExit')
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def __subclasshook__(cls, C):
|
||||||
|
if cls is Generator:
|
||||||
|
mro = C.__mro__
|
||||||
|
for method in required_methods:
|
||||||
|
for base in mro:
|
||||||
|
if method in base.__dict__:
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
return NotImplemented
|
||||||
|
return True
|
||||||
|
return NotImplemented
|
||||||
|
|
||||||
|
generator = type((lambda: (yield))())
|
||||||
|
Generator.register(generator)
|
||||||
|
return Generator
|
||||||
|
|
||||||
|
|
||||||
|
def mk_awaitable():
|
||||||
|
from abc import abstractmethod, ABCMeta
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def __await__(self):
|
||||||
|
yield
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def __subclasshook__(cls, C):
|
||||||
|
if cls is Awaitable:
|
||||||
|
for B in C.__mro__:
|
||||||
|
if '__await__' in B.__dict__:
|
||||||
|
if B.__dict__['__await__']:
|
||||||
|
return True
|
||||||
|
break
|
||||||
|
return NotImplemented
|
||||||
|
|
||||||
|
# calling metaclass directly as syntax differs in Py2/Py3
|
||||||
|
Awaitable = ABCMeta('Awaitable', (), {
|
||||||
|
'__slots__': (),
|
||||||
|
'__await__': __await__,
|
||||||
|
'__subclasshook__': __subclasshook__,
|
||||||
|
})
|
||||||
|
|
||||||
|
return Awaitable
|
||||||
|
|
||||||
|
|
||||||
|
def mk_coroutine():
|
||||||
|
from abc import abstractmethod
|
||||||
|
|
||||||
|
class Coroutine(Awaitable):
|
||||||
|
__slots__ = ()
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def send(self, value):
|
||||||
|
"""Send a value into the coroutine.
|
||||||
|
Return next yielded value or raise StopIteration.
|
||||||
|
"""
|
||||||
|
raise StopIteration
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def throw(self, typ, val=None, tb=None):
|
||||||
|
"""Raise an exception in the coroutine.
|
||||||
|
Return next yielded value or raise StopIteration.
|
||||||
|
"""
|
||||||
|
if val is None:
|
||||||
|
if tb is None:
|
||||||
|
raise typ
|
||||||
|
val = typ()
|
||||||
|
if tb is not None:
|
||||||
|
val = val.with_traceback(tb)
|
||||||
|
raise val
|
||||||
|
|
||||||
|
def close(self):
|
||||||
|
"""Raise GeneratorExit inside coroutine.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
self.throw(GeneratorExit)
|
||||||
|
except (GeneratorExit, StopIteration):
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
raise RuntimeError('coroutine ignored GeneratorExit')
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def __subclasshook__(cls, C):
|
||||||
|
if cls is Coroutine:
|
||||||
|
mro = C.__mro__
|
||||||
|
for method in ('__await__', 'send', 'throw', 'close'):
|
||||||
|
for base in mro:
|
||||||
|
if method in base.__dict__:
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
return NotImplemented
|
||||||
|
return True
|
||||||
|
return NotImplemented
|
||||||
|
|
||||||
|
return Coroutine
|
||||||
|
|
||||||
|
|
||||||
|
###
|
||||||
|
# make all ABCs available in this module
|
||||||
|
|
||||||
|
try:
|
||||||
|
Generator = _collections_abc.Generator
|
||||||
|
except AttributeError:
|
||||||
|
Generator = mk_gen()
|
||||||
|
|
||||||
|
try:
|
||||||
|
Awaitable = _collections_abc.Awaitable
|
||||||
|
except AttributeError:
|
||||||
|
Awaitable = mk_awaitable()
|
||||||
|
|
||||||
|
try:
|
||||||
|
Coroutine = _collections_abc.Coroutine
|
||||||
|
except AttributeError:
|
||||||
|
Coroutine = mk_coroutine()
|
||||||
|
|
||||||
|
try:
|
||||||
|
from inspect import isawaitable
|
||||||
|
except ImportError:
|
||||||
|
def isawaitable(obj):
|
||||||
|
return isinstance(obj, Awaitable)
|
||||||
|
|
||||||
|
|
||||||
|
###
|
||||||
|
# allow patching the stdlib
|
||||||
|
|
||||||
|
PATCHED = {}
|
||||||
|
|
||||||
|
|
||||||
|
def patch(patch_inspect=True):
|
||||||
|
"""
|
||||||
|
Main entry point for patching the ``collections.abc`` and ``inspect``
|
||||||
|
standard library modules.
|
||||||
|
"""
|
||||||
|
PATCHED['collections.abc.Generator'] = _collections_abc.Generator = Generator
|
||||||
|
PATCHED['collections.abc.Coroutine'] = _collections_abc.Coroutine = Coroutine
|
||||||
|
PATCHED['collections.abc.Awaitable'] = _collections_abc.Awaitable = Awaitable
|
||||||
|
|
||||||
|
if patch_inspect:
|
||||||
|
import inspect
|
||||||
|
PATCHED['inspect.isawaitable'] = inspect.isawaitable = isawaitable
|
219
lib/singledispatch.py
Normal file
219
lib/singledispatch.py
Normal file
|
@ -0,0 +1,219 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from __future__ import absolute_import
|
||||||
|
from __future__ import division
|
||||||
|
from __future__ import print_function
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
__all__ = ['singledispatch']
|
||||||
|
|
||||||
|
from functools import update_wrapper
|
||||||
|
from weakref import WeakKeyDictionary
|
||||||
|
from singledispatch_helpers import MappingProxyType, get_cache_token
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
### singledispatch() - single-dispatch generic function decorator
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
def _c3_merge(sequences):
|
||||||
|
"""Merges MROs in *sequences* to a single MRO using the C3 algorithm.
|
||||||
|
|
||||||
|
Adapted from http://www.python.org/download/releases/2.3/mro/.
|
||||||
|
|
||||||
|
"""
|
||||||
|
result = []
|
||||||
|
while True:
|
||||||
|
sequences = [s for s in sequences if s] # purge empty sequences
|
||||||
|
if not sequences:
|
||||||
|
return result
|
||||||
|
for s1 in sequences: # find merge candidates among seq heads
|
||||||
|
candidate = s1[0]
|
||||||
|
for s2 in sequences:
|
||||||
|
if candidate in s2[1:]:
|
||||||
|
candidate = None
|
||||||
|
break # reject the current head, it appears later
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
if not candidate:
|
||||||
|
raise RuntimeError("Inconsistent hierarchy")
|
||||||
|
result.append(candidate)
|
||||||
|
# remove the chosen candidate
|
||||||
|
for seq in sequences:
|
||||||
|
if seq[0] == candidate:
|
||||||
|
del seq[0]
|
||||||
|
|
||||||
|
def _c3_mro(cls, abcs=None):
|
||||||
|
"""Computes the method resolution order using extended C3 linearization.
|
||||||
|
|
||||||
|
If no *abcs* are given, the algorithm works exactly like the built-in C3
|
||||||
|
linearization used for method resolution.
|
||||||
|
|
||||||
|
If given, *abcs* is a list of abstract base classes that should be inserted
|
||||||
|
into the resulting MRO. Unrelated ABCs are ignored and don't end up in the
|
||||||
|
result. The algorithm inserts ABCs where their functionality is introduced,
|
||||||
|
i.e. issubclass(cls, abc) returns True for the class itself but returns
|
||||||
|
False for all its direct base classes. Implicit ABCs for a given class
|
||||||
|
(either registered or inferred from the presence of a special method like
|
||||||
|
__len__) are inserted directly after the last ABC explicitly listed in the
|
||||||
|
MRO of said class. If two implicit ABCs end up next to each other in the
|
||||||
|
resulting MRO, their ordering depends on the order of types in *abcs*.
|
||||||
|
|
||||||
|
"""
|
||||||
|
for i, base in enumerate(reversed(cls.__bases__)):
|
||||||
|
if hasattr(base, '__abstractmethods__'):
|
||||||
|
boundary = len(cls.__bases__) - i
|
||||||
|
break # Bases up to the last explicit ABC are considered first.
|
||||||
|
else:
|
||||||
|
boundary = 0
|
||||||
|
abcs = list(abcs) if abcs else []
|
||||||
|
explicit_bases = list(cls.__bases__[:boundary])
|
||||||
|
abstract_bases = []
|
||||||
|
other_bases = list(cls.__bases__[boundary:])
|
||||||
|
for base in abcs:
|
||||||
|
if issubclass(cls, base) and not any(
|
||||||
|
issubclass(b, base) for b in cls.__bases__
|
||||||
|
):
|
||||||
|
# If *cls* is the class that introduces behaviour described by
|
||||||
|
# an ABC *base*, insert said ABC to its MRO.
|
||||||
|
abstract_bases.append(base)
|
||||||
|
for base in abstract_bases:
|
||||||
|
abcs.remove(base)
|
||||||
|
explicit_c3_mros = [_c3_mro(base, abcs=abcs) for base in explicit_bases]
|
||||||
|
abstract_c3_mros = [_c3_mro(base, abcs=abcs) for base in abstract_bases]
|
||||||
|
other_c3_mros = [_c3_mro(base, abcs=abcs) for base in other_bases]
|
||||||
|
return _c3_merge(
|
||||||
|
[[cls]] +
|
||||||
|
explicit_c3_mros + abstract_c3_mros + other_c3_mros +
|
||||||
|
[explicit_bases] + [abstract_bases] + [other_bases]
|
||||||
|
)
|
||||||
|
|
||||||
|
def _compose_mro(cls, types):
|
||||||
|
"""Calculates the method resolution order for a given class *cls*.
|
||||||
|
|
||||||
|
Includes relevant abstract base classes (with their respective bases) from
|
||||||
|
the *types* iterable. Uses a modified C3 linearization algorithm.
|
||||||
|
|
||||||
|
"""
|
||||||
|
bases = set(cls.__mro__)
|
||||||
|
# Remove entries which are already present in the __mro__ or unrelated.
|
||||||
|
def is_related(typ):
|
||||||
|
return (typ not in bases and hasattr(typ, '__mro__')
|
||||||
|
and issubclass(cls, typ))
|
||||||
|
types = [n for n in types if is_related(n)]
|
||||||
|
# Remove entries which are strict bases of other entries (they will end up
|
||||||
|
# in the MRO anyway.
|
||||||
|
def is_strict_base(typ):
|
||||||
|
for other in types:
|
||||||
|
if typ != other and typ in other.__mro__:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
types = [n for n in types if not is_strict_base(n)]
|
||||||
|
# Subclasses of the ABCs in *types* which are also implemented by
|
||||||
|
# *cls* can be used to stabilize ABC ordering.
|
||||||
|
type_set = set(types)
|
||||||
|
mro = []
|
||||||
|
for typ in types:
|
||||||
|
found = []
|
||||||
|
for sub in typ.__subclasses__():
|
||||||
|
if sub not in bases and issubclass(cls, sub):
|
||||||
|
found.append([s for s in sub.__mro__ if s in type_set])
|
||||||
|
if not found:
|
||||||
|
mro.append(typ)
|
||||||
|
continue
|
||||||
|
# Favor subclasses with the biggest number of useful bases
|
||||||
|
found.sort(key=len, reverse=True)
|
||||||
|
for sub in found:
|
||||||
|
for subcls in sub:
|
||||||
|
if subcls not in mro:
|
||||||
|
mro.append(subcls)
|
||||||
|
return _c3_mro(cls, abcs=mro)
|
||||||
|
|
||||||
|
def _find_impl(cls, registry):
|
||||||
|
"""Returns the best matching implementation from *registry* for type *cls*.
|
||||||
|
|
||||||
|
Where there is no registered implementation for a specific type, its method
|
||||||
|
resolution order is used to find a more generic implementation.
|
||||||
|
|
||||||
|
Note: if *registry* does not contain an implementation for the base
|
||||||
|
*object* type, this function may return None.
|
||||||
|
|
||||||
|
"""
|
||||||
|
mro = _compose_mro(cls, registry.keys())
|
||||||
|
match = None
|
||||||
|
for t in mro:
|
||||||
|
if match is not None:
|
||||||
|
# If *match* is an implicit ABC but there is another unrelated,
|
||||||
|
# equally matching implicit ABC, refuse the temptation to guess.
|
||||||
|
if (t in registry and t not in cls.__mro__
|
||||||
|
and match not in cls.__mro__
|
||||||
|
and not issubclass(match, t)):
|
||||||
|
raise RuntimeError("Ambiguous dispatch: {0} or {1}".format(
|
||||||
|
match, t))
|
||||||
|
break
|
||||||
|
if t in registry:
|
||||||
|
match = t
|
||||||
|
return registry.get(match)
|
||||||
|
|
||||||
|
def singledispatch(func):
|
||||||
|
"""Single-dispatch generic function decorator.
|
||||||
|
|
||||||
|
Transforms a function into a generic function, which can have different
|
||||||
|
behaviours depending upon the type of its first argument. The decorated
|
||||||
|
function acts as the default implementation, and additional
|
||||||
|
implementations can be registered using the register() attribute of the
|
||||||
|
generic function.
|
||||||
|
|
||||||
|
"""
|
||||||
|
registry = {}
|
||||||
|
dispatch_cache = WeakKeyDictionary()
|
||||||
|
def ns(): pass
|
||||||
|
ns.cache_token = None
|
||||||
|
|
||||||
|
def dispatch(cls):
|
||||||
|
"""generic_func.dispatch(cls) -> <function implementation>
|
||||||
|
|
||||||
|
Runs the dispatch algorithm to return the best available implementation
|
||||||
|
for the given *cls* registered on *generic_func*.
|
||||||
|
|
||||||
|
"""
|
||||||
|
if ns.cache_token is not None:
|
||||||
|
current_token = get_cache_token()
|
||||||
|
if ns.cache_token != current_token:
|
||||||
|
dispatch_cache.clear()
|
||||||
|
ns.cache_token = current_token
|
||||||
|
try:
|
||||||
|
impl = dispatch_cache[cls]
|
||||||
|
except KeyError:
|
||||||
|
try:
|
||||||
|
impl = registry[cls]
|
||||||
|
except KeyError:
|
||||||
|
impl = _find_impl(cls, registry)
|
||||||
|
dispatch_cache[cls] = impl
|
||||||
|
return impl
|
||||||
|
|
||||||
|
def register(cls, func=None):
|
||||||
|
"""generic_func.register(cls, func) -> func
|
||||||
|
|
||||||
|
Registers a new implementation for the given *cls* on a *generic_func*.
|
||||||
|
|
||||||
|
"""
|
||||||
|
if func is None:
|
||||||
|
return lambda f: register(cls, f)
|
||||||
|
registry[cls] = func
|
||||||
|
if ns.cache_token is None and hasattr(cls, '__abstractmethods__'):
|
||||||
|
ns.cache_token = get_cache_token()
|
||||||
|
dispatch_cache.clear()
|
||||||
|
return func
|
||||||
|
|
||||||
|
def wrapper(*args, **kw):
|
||||||
|
return dispatch(args[0].__class__)(*args, **kw)
|
||||||
|
|
||||||
|
registry[object] = func
|
||||||
|
wrapper.register = register
|
||||||
|
wrapper.dispatch = dispatch
|
||||||
|
wrapper.registry = MappingProxyType(registry)
|
||||||
|
wrapper._clear_cache = dispatch_cache.clear
|
||||||
|
update_wrapper(wrapper, func)
|
||||||
|
return wrapper
|
||||||
|
|
170
lib/singledispatch_helpers.py
Normal file
170
lib/singledispatch_helpers.py
Normal file
|
@ -0,0 +1,170 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from __future__ import absolute_import
|
||||||
|
from __future__ import division
|
||||||
|
from __future__ import print_function
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from abc import ABCMeta
|
||||||
|
from collections import MutableMapping
|
||||||
|
import sys
|
||||||
|
try:
|
||||||
|
from collections import UserDict
|
||||||
|
except ImportError:
|
||||||
|
from UserDict import UserDict
|
||||||
|
try:
|
||||||
|
from collections import OrderedDict
|
||||||
|
except ImportError:
|
||||||
|
from ordereddict import OrderedDict
|
||||||
|
try:
|
||||||
|
from thread import get_ident
|
||||||
|
except ImportError:
|
||||||
|
try:
|
||||||
|
from _thread import get_ident
|
||||||
|
except ImportError:
|
||||||
|
from _dummy_thread import get_ident
|
||||||
|
|
||||||
|
|
||||||
|
def recursive_repr(fillvalue='...'):
|
||||||
|
'Decorator to make a repr function return fillvalue for a recursive call'
|
||||||
|
|
||||||
|
def decorating_function(user_function):
|
||||||
|
repr_running = set()
|
||||||
|
|
||||||
|
def wrapper(self):
|
||||||
|
key = id(self), get_ident()
|
||||||
|
if key in repr_running:
|
||||||
|
return fillvalue
|
||||||
|
repr_running.add(key)
|
||||||
|
try:
|
||||||
|
result = user_function(self)
|
||||||
|
finally:
|
||||||
|
repr_running.discard(key)
|
||||||
|
return result
|
||||||
|
|
||||||
|
# Can't use functools.wraps() here because of bootstrap issues
|
||||||
|
wrapper.__module__ = getattr(user_function, '__module__')
|
||||||
|
wrapper.__doc__ = getattr(user_function, '__doc__')
|
||||||
|
wrapper.__name__ = getattr(user_function, '__name__')
|
||||||
|
wrapper.__annotations__ = getattr(user_function, '__annotations__', {})
|
||||||
|
return wrapper
|
||||||
|
|
||||||
|
return decorating_function
|
||||||
|
|
||||||
|
|
||||||
|
class ChainMap(MutableMapping):
|
||||||
|
''' A ChainMap groups multiple dicts (or other mappings) together
|
||||||
|
to create a single, updateable view.
|
||||||
|
|
||||||
|
The underlying mappings are stored in a list. That list is public and can
|
||||||
|
accessed or updated using the *maps* attribute. There is no other state.
|
||||||
|
|
||||||
|
Lookups search the underlying mappings successively until a key is found.
|
||||||
|
In contrast, writes, updates, and deletions only operate on the first
|
||||||
|
mapping.
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
def __init__(self, *maps):
|
||||||
|
'''Initialize a ChainMap by setting *maps* to the given mappings.
|
||||||
|
If no mappings are provided, a single empty dictionary is used.
|
||||||
|
|
||||||
|
'''
|
||||||
|
self.maps = list(maps) or [{}] # always at least one map
|
||||||
|
|
||||||
|
def __missing__(self, key):
|
||||||
|
raise KeyError(key)
|
||||||
|
|
||||||
|
def __getitem__(self, key):
|
||||||
|
for mapping in self.maps:
|
||||||
|
try:
|
||||||
|
return mapping[key] # can't use 'key in mapping' with defaultdict
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
return self.__missing__(key) # support subclasses that define __missing__
|
||||||
|
|
||||||
|
def get(self, key, default=None):
|
||||||
|
return self[key] if key in self else default
|
||||||
|
|
||||||
|
def __len__(self):
|
||||||
|
return len(set().union(*self.maps)) # reuses stored hash values if possible
|
||||||
|
|
||||||
|
def __iter__(self):
|
||||||
|
return iter(set().union(*self.maps))
|
||||||
|
|
||||||
|
def __contains__(self, key):
|
||||||
|
return any(key in m for m in self.maps)
|
||||||
|
|
||||||
|
@recursive_repr()
|
||||||
|
def __repr__(self):
|
||||||
|
return '{0.__class__.__name__}({1})'.format(
|
||||||
|
self, ', '.join(map(repr, self.maps)))
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def fromkeys(cls, iterable, *args):
|
||||||
|
'Create a ChainMap with a single dict created from the iterable.'
|
||||||
|
return cls(dict.fromkeys(iterable, *args))
|
||||||
|
|
||||||
|
def copy(self):
|
||||||
|
'New ChainMap or subclass with a new copy of maps[0] and refs to maps[1:]'
|
||||||
|
return self.__class__(self.maps[0].copy(), *self.maps[1:])
|
||||||
|
|
||||||
|
__copy__ = copy
|
||||||
|
|
||||||
|
def new_child(self): # like Django's Context.push()
|
||||||
|
'New ChainMap with a new dict followed by all previous maps.'
|
||||||
|
return self.__class__({}, *self.maps)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def parents(self): # like Django's Context.pop()
|
||||||
|
'New ChainMap from maps[1:].'
|
||||||
|
return self.__class__(*self.maps[1:])
|
||||||
|
|
||||||
|
def __setitem__(self, key, value):
|
||||||
|
self.maps[0][key] = value
|
||||||
|
|
||||||
|
def __delitem__(self, key):
|
||||||
|
try:
|
||||||
|
del self.maps[0][key]
|
||||||
|
except KeyError:
|
||||||
|
raise KeyError('Key not found in the first mapping: {!r}'.format(key))
|
||||||
|
|
||||||
|
def popitem(self):
|
||||||
|
'Remove and return an item pair from maps[0]. Raise KeyError is maps[0] is empty.'
|
||||||
|
try:
|
||||||
|
return self.maps[0].popitem()
|
||||||
|
except KeyError:
|
||||||
|
raise KeyError('No keys found in the first mapping.')
|
||||||
|
|
||||||
|
def pop(self, key, *args):
|
||||||
|
'Remove *key* from maps[0] and return its value. Raise KeyError if *key* not in maps[0].'
|
||||||
|
try:
|
||||||
|
return self.maps[0].pop(key, *args)
|
||||||
|
except KeyError:
|
||||||
|
raise KeyError('Key not found in the first mapping: {!r}'.format(key))
|
||||||
|
|
||||||
|
def clear(self):
|
||||||
|
'Clear maps[0], leaving maps[1:] intact.'
|
||||||
|
self.maps[0].clear()
|
||||||
|
|
||||||
|
|
||||||
|
class MappingProxyType(UserDict):
|
||||||
|
def __init__(self, data):
|
||||||
|
UserDict.__init__(self)
|
||||||
|
self.data = data
|
||||||
|
|
||||||
|
|
||||||
|
def get_cache_token():
|
||||||
|
return ABCMeta._abc_invalidation_counter
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class Support(object):
|
||||||
|
def dummy(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def cpython_only(self, func):
|
||||||
|
if 'PyPy' in sys.version:
|
||||||
|
return self.dummy
|
||||||
|
return func
|
Loading…
Reference in a new issue