Show More
Commit Description:
merge with algo and add brython files that were missing
Commit Description:
merge with algo and add brython files that were missing
References:
File last commit:
Show/Diff file:
Action:
lib/assets/Lib/collections/__init__.py
| 932 lines
| 35.0 KiB
| text/x-python
| PythonLexer
|
r584 | #__all__ = ['deque', 'defaultdict', 'Counter'] | |||
from _collections import deque, defaultdict | ||||
#from itertools import repeat as _repeat, chain as _chain, starmap as _starmap | ||||
__all__ = ['deque', 'defaultdict', 'namedtuple', 'UserDict', 'UserList', | ||||
'UserString', 'Counter', 'OrderedDict'] | ||||
# For bootstrapping reasons, the collection ABCs are defined in _abcoll.py. | ||||
# They should however be considered an integral part of collections.py. | ||||
# fixme brython.. there is an issue with _abcoll | ||||
#from _abcoll import * | ||||
#from _abcoll import Set | ||||
from _abcoll import MutableMapping | ||||
#import _abcoll | ||||
#__all__ += _abcoll.__all__ | ||||
from collections.abc import * | ||||
import collections.abc | ||||
__all__ += collections.abc.__all__ | ||||
from _collections import deque, defaultdict, namedtuple | ||||
from operator import itemgetter as _itemgetter | ||||
from keyword import iskeyword as _iskeyword | ||||
import sys as _sys | ||||
import heapq as _heapq | ||||
#fixme brython | ||||
#from weakref import proxy as _proxy | ||||
from itertools import repeat as _repeat, chain as _chain, starmap as _starmap | ||||
from reprlib import recursive_repr as _recursive_repr | ||||
class Set(set): | ||||
pass | ||||
class Sequence(list): | ||||
pass | ||||
def _proxy(obj): | ||||
return obj | ||||
################################################################################ | ||||
### OrderedDict | ||||
################################################################################ | ||||
class _Link(object): | ||||
__slots__ = 'prev', 'next', 'key', '__weakref__' | ||||
class OrderedDict(dict): | ||||
'Dictionary that remembers insertion order' | ||||
# An inherited dict maps keys to values. | ||||
# The inherited dict provides __getitem__, __len__, __contains__, and get. | ||||
# The remaining methods are order-aware. | ||||
# Big-O running times for all methods are the same as regular dictionaries. | ||||
# The internal self.__map dict maps keys to links in a doubly linked list. | ||||
# The circular doubly linked list starts and ends with a sentinel element. | ||||
# The sentinel element never gets deleted (this simplifies the algorithm). | ||||
# The sentinel is in self.__hardroot with a weakref proxy in self.__root. | ||||
# The prev links are weakref proxies (to prevent circular references). | ||||
# Individual links are kept alive by the hard reference in self.__map. | ||||
# Those hard references disappear when a key is deleted from an OrderedDict. | ||||
def __init__(self, *args, **kwds): | ||||
'''Initialize an ordered dictionary. The signature is the same as | ||||
regular dictionaries, but keyword arguments are not recommended because | ||||
their insertion order is arbitrary. | ||||
''' | ||||
if len(args) > 1: | ||||
raise TypeError('expected at most 1 arguments, got %d' % len(args)) | ||||
try: | ||||
self.__root | ||||
except AttributeError: | ||||
self.__hardroot = _Link() | ||||
self.__root = root = _proxy(self.__hardroot) | ||||
root.prev = root.next = root | ||||
self.__map = {} | ||||
self.__update(*args, **kwds) | ||||
def __setitem__(self, key, value, | ||||
dict_setitem=dict.__setitem__, proxy=_proxy, Link=_Link): | ||||
'od.__setitem__(i, y) <==> od[i]=y' | ||||
# Setting a new item creates a new link at the end of the linked list, | ||||
# and the inherited dictionary is updated with the new key/value pair. | ||||
if key not in self: | ||||
self.__map[key] = link = Link() | ||||
root = self.__root | ||||
last = root.prev | ||||
link.prev, link.next, link.key = last, root, key | ||||
last.next = link | ||||
root.prev = proxy(link) | ||||
dict_setitem(self, key, value) | ||||
def __delitem__(self, key, dict_delitem=dict.__delitem__): | ||||
'od.__delitem__(y) <==> del od[y]' | ||||
# Deleting an existing item uses self.__map to find the link which gets | ||||
# removed by updating the links in the predecessor and successor nodes. | ||||
dict_delitem(self, key) | ||||
link = self.__map.pop(key) | ||||
link_prev = link.prev | ||||
link_next = link.next | ||||
link_prev.next = link_next | ||||
link_next.prev = link_prev | ||||
def __iter__(self): | ||||
'od.__iter__() <==> iter(od)' | ||||
# Traverse the linked list in order. | ||||
root = self.__root | ||||
curr = root.next | ||||
while curr is not root: | ||||
yield curr.key | ||||
curr = curr.next | ||||
def __reversed__(self): | ||||
'od.__reversed__() <==> reversed(od)' | ||||
# Traverse the linked list in reverse order. | ||||
root = self.__root | ||||
curr = root.prev | ||||
while curr is not root: | ||||
yield curr.key | ||||
curr = curr.prev | ||||
def clear(self): | ||||
'od.clear() -> None. Remove all items from od.' | ||||
root = self.__root | ||||
root.prev = root.next = root | ||||
self.__map.clear() | ||||
dict.clear(self) | ||||
def popitem(self, last=True): | ||||
'''od.popitem() -> (k, v), return and remove a (key, value) pair. | ||||
Pairs are returned in LIFO order if last is true or FIFO order if false. | ||||
''' | ||||
if not self: | ||||
raise KeyError('dictionary is empty') | ||||
root = self.__root | ||||
if last: | ||||
link = root.prev | ||||
link_prev = link.prev | ||||
link_prev.next = root | ||||
root.prev = link_prev | ||||
else: | ||||
link = root.next | ||||
link_next = link.next | ||||
root.next = link_next | ||||
link_next.prev = root | ||||
key = link.key | ||||
del self.__map[key] | ||||
value = dict.pop(self, key) | ||||
return key, value | ||||
def move_to_end(self, key, last=True): | ||||
'''Move an existing element to the end (or beginning if last==False). | ||||
Raises KeyError if the element does not exist. | ||||
When last=True, acts like a fast version of self[key]=self.pop(key). | ||||
''' | ||||
link = self.__map[key] | ||||
link_prev = link.prev | ||||
link_next = link.next | ||||
link_prev.next = link_next | ||||
link_next.prev = link_prev | ||||
root = self.__root | ||||
if last: | ||||
last = root.prev | ||||
link.prev = last | ||||
link.next = root | ||||
last.next = root.prev = link | ||||
else: | ||||
first = root.next | ||||
link.prev = root | ||||
link.next = first | ||||
root.next = first.prev = link | ||||
def __sizeof__(self): | ||||
sizeof = _sys.getsizeof | ||||
n = len(self) + 1 # number of links including root | ||||
size = sizeof(self.__dict__) # instance dictionary | ||||
size += sizeof(self.__map) * 2 # internal dict and inherited dict | ||||
size += sizeof(self.__hardroot) * n # link objects | ||||
size += sizeof(self.__root) * n # proxy objects | ||||
return size | ||||
#fixme brython.. Issue with _abcoll, which contains MutableMapping | ||||
update = __update = MutableMapping.update | ||||
keys = MutableMapping.keys | ||||
values = MutableMapping.values | ||||
items = MutableMapping.items | ||||
__ne__ = MutableMapping.__ne__ | ||||
__marker = object() | ||||
def pop(self, key, default=__marker): | ||||
'''od.pop(k[,d]) -> v, remove specified key and return the corresponding | ||||
value. If key is not found, d is returned if given, otherwise KeyError | ||||
is raised. | ||||
''' | ||||
if key in self: | ||||
result = self[key] | ||||
del self[key] | ||||
return result | ||||
if default is self.__marker: | ||||
raise KeyError(key) | ||||
return default | ||||
def setdefault(self, key, default=None): | ||||
'od.setdefault(k[,d]) -> od.get(k,d), also set od[k]=d if k not in od' | ||||
if key in self: | ||||
return self[key] | ||||
self[key] = default | ||||
return default | ||||
#fixme, brython issue | ||||
#@_recursive_repr() | ||||
def __repr__(self): | ||||
'od.__repr__() <==> repr(od)' | ||||
if not self: | ||||
return '%s()' % (self.__class__.__name__,) | ||||
return '%s(%r)' % (self.__class__.__name__, list(self.items())) | ||||
def __reduce__(self): | ||||
'Return state information for pickling' | ||||
items = [[k, self[k]] for k in self] | ||||
inst_dict = vars(self).copy() | ||||
for k in vars(OrderedDict()): | ||||
inst_dict.pop(k, None) | ||||
if inst_dict: | ||||
return (self.__class__, (items,), inst_dict) | ||||
return self.__class__, (items,) | ||||
def copy(self): | ||||
'od.copy() -> a shallow copy of od' | ||||
return self.__class__(self) | ||||
@classmethod | ||||
def fromkeys(cls, iterable, value=None): | ||||
'''OD.fromkeys(S[, v]) -> New ordered dictionary with keys from S. | ||||
If not specified, the value defaults to None. | ||||
''' | ||||
self = cls() | ||||
for key in iterable: | ||||
self[key] = value | ||||
return self | ||||
def __eq__(self, other): | ||||
'''od.__eq__(y) <==> od==y. Comparison to another OD is order-sensitive | ||||
while comparison to a regular mapping is order-insensitive. | ||||
''' | ||||
if isinstance(other, OrderedDict): | ||||
return len(self)==len(other) and \ | ||||
all(p==q for p, q in zip(self.items(), other.items())) | ||||
return dict.__eq__(self, other) | ||||
######################################################################## | ||||
### Counter | ||||
######################################################################## | ||||
def _count_elements(mapping, iterable): | ||||
'Tally elements from the iterable.' | ||||
mapping_get = mapping.get | ||||
for elem in iterable: | ||||
mapping[elem] = mapping_get(elem, 0) + 1 | ||||
#try: # Load C helper function if available | ||||
# from _collections import _count_elements | ||||
#except ImportError: | ||||
# pass | ||||
class Counter(dict): | ||||
'''Dict subclass for counting hashable items. Sometimes called a bag | ||||
or multiset. Elements are stored as dictionary keys and their counts | ||||
are stored as dictionary values. | ||||
>>> c = Counter('abcdeabcdabcaba') # count elements from a string | ||||
>>> c.most_common(3) # three most common elements | ||||
[('a', 5), ('b', 4), ('c', 3)] | ||||
>>> sorted(c) # list all unique elements | ||||
['a', 'b', 'c', 'd', 'e'] | ||||
>>> ''.join(sorted(c.elements())) # list elements with repetitions | ||||
'aaaaabbbbcccdde' | ||||
>>> sum(c.values()) # total of all counts | ||||
15 | ||||
>>> c['a'] # count of letter 'a' | ||||
5 | ||||
>>> for elem in 'shazam': # update counts from an iterable | ||||
... c[elem] += 1 # by adding 1 to each element's count | ||||
>>> c['a'] # now there are seven 'a' | ||||
7 | ||||
>>> del c['b'] # remove all 'b' | ||||
>>> c['b'] # now there are zero 'b' | ||||
0 | ||||
>>> d = Counter('simsalabim') # make another counter | ||||
>>> c.update(d) # add in the second counter | ||||
>>> c['a'] # now there are nine 'a' | ||||
9 | ||||
>>> c.clear() # empty the counter | ||||
>>> c | ||||
Counter() | ||||
Note: If a count is set to zero or reduced to zero, it will remain | ||||
in the counter until the entry is deleted or the counter is cleared: | ||||
>>> c = Counter('aaabbc') | ||||
>>> c['b'] -= 2 # reduce the count of 'b' by two | ||||
>>> c.most_common() # 'b' is still in, but its count is zero | ||||
[('a', 3), ('c', 1), ('b', 0)] | ||||
''' | ||||
# References: | ||||
# http://en.wikipedia.org/wiki/Multiset | ||||
# http://www.gnu.org/software/smalltalk/manual-base/html_node/Bag.html | ||||
# http://www.demo2s.com/Tutorial/Cpp/0380__set-multiset/Catalog0380__set-multiset.htm | ||||
# http://code.activestate.com/recipes/259174/ | ||||
# Knuth, TAOCP Vol. II section 4.6.3 | ||||
def __init__(self, iterable=None, **kwds): | ||||
'''Create a new, empty Counter object. And if given, count elements | ||||
from an input iterable. Or, initialize the count from another mapping | ||||
of elements to their counts. | ||||
>>> c = Counter() # a new, empty counter | ||||
>>> c = Counter('gallahad') # a new counter from an iterable | ||||
>>> c = Counter({'a': 4, 'b': 2}) # a new counter from a mapping | ||||
>>> c = Counter(a=4, b=2) # a new counter from keyword args | ||||
''' | ||||
#super().__init__() #BE modified since super not supported | ||||
dict.__init__(self) | ||||
self.update(iterable, **kwds) | ||||
def __missing__(self, key): | ||||
'The count of elements not in the Counter is zero.' | ||||
# Needed so that self[missing_item] does not raise KeyError | ||||
return 0 | ||||
def most_common(self, n=None): | ||||
'''List the n most common elements and their counts from the most | ||||
common to the least. If n is None, then list all element counts. | ||||
>>> Counter('abcdeabcdabcaba').most_common(3) | ||||
[('a', 5), ('b', 4), ('c', 3)] | ||||
''' | ||||
# Emulate Bag.sortedByCount from Smalltalk | ||||
if n is None: | ||||
return sorted(self.items(), key=_itemgetter(1), reverse=True) | ||||
return _heapq.nlargest(n, self.items(), key=_itemgetter(1)) | ||||
def elements(self): | ||||
'''Iterator over elements repeating each as many times as its count. | ||||
>>> c = Counter('ABCABC') | ||||
>>> sorted(c.elements()) | ||||
['A', 'A', 'B', 'B', 'C', 'C'] | ||||
# Knuth's example for prime factors of 1836: 2**2 * 3**3 * 17**1 | ||||
>>> prime_factors = Counter({2: 2, 3: 3, 17: 1}) | ||||
>>> product = 1 | ||||
>>> for factor in prime_factors.elements(): # loop over factors | ||||
... product *= factor # and multiply them | ||||
>>> product | ||||
1836 | ||||
Note, if an element's count has been set to zero or is a negative | ||||
number, elements() will ignore it. | ||||
''' | ||||
# Emulate Bag.do from Smalltalk and Multiset.begin from C++. | ||||
return _chain.from_iterable(_starmap(_repeat, self.items())) | ||||
# Override dict methods where necessary | ||||
@classmethod | ||||
def fromkeys(cls, iterable, v=None): | ||||
# There is no equivalent method for counters because setting v=1 | ||||
# means that no element can have a count greater than one. | ||||
raise NotImplementedError( | ||||
'Counter.fromkeys() is undefined. Use Counter(iterable) instead.') | ||||
def update(self, iterable=None, **kwds): | ||||
'''Like dict.update() but add counts instead of replacing them. | ||||
Source can be an iterable, a dictionary, or another Counter instance. | ||||
>>> c = Counter('which') | ||||
>>> c.update('witch') # add elements from another iterable | ||||
>>> d = Counter('watch') | ||||
>>> c.update(d) # add elements from another counter | ||||
>>> c['h'] # four 'h' in which, witch, and watch | ||||
4 | ||||
''' | ||||
# The regular dict.update() operation makes no sense here because the | ||||
# replace behavior results in the some of original untouched counts | ||||
# being mixed-in with all of the other counts for a mismash that | ||||
# doesn't have a straight-forward interpretation in most counting | ||||
# contexts. Instead, we implement straight-addition. Both the inputs | ||||
# and outputs are allowed to contain zero and negative counts. | ||||
if iterable is not None: | ||||
if isinstance(iterable, Mapping): | ||||
if self: | ||||
self_get = self.get | ||||
for elem, count in iterable.items(): | ||||
self[elem] = count + self_get(elem, 0) | ||||
else: | ||||
super().update(iterable) # fast path when counter is empty | ||||
else: | ||||
_count_elements(self, iterable) | ||||
if kwds: | ||||
self.update(kwds) | ||||
def subtract(self, iterable=None, **kwds): | ||||
'''Like dict.update() but subtracts counts instead of replacing them. | ||||
Counts can be reduced below zero. Both the inputs and outputs are | ||||
allowed to contain zero and negative counts. | ||||
Source can be an iterable, a dictionary, or another Counter instance. | ||||
>>> c = Counter('which') | ||||
>>> c.subtract('witch') # subtract elements from another iterable | ||||
>>> c.subtract(Counter('watch')) # subtract elements from another counter | ||||
>>> c['h'] # 2 in which, minus 1 in witch, minus 1 in watch | ||||
0 | ||||
>>> c['w'] # 1 in which, minus 1 in witch, minus 1 in watch | ||||
-1 | ||||
''' | ||||
if iterable is not None: | ||||
self_get = self.get | ||||
if isinstance(iterable, Mapping): | ||||
for elem, count in iterable.items(): | ||||
self[elem] = self_get(elem, 0) - count | ||||
else: | ||||
for elem in iterable: | ||||
self[elem] = self_get(elem, 0) - 1 | ||||
if kwds: | ||||
self.subtract(kwds) | ||||
def copy(self): | ||||
'Return a shallow copy.' | ||||
return self.__class__(self) | ||||
def __reduce__(self): | ||||
return self.__class__, (dict(self),) | ||||
def __delitem__(self, elem): | ||||
'Like dict.__delitem__() but does not raise KeyError for missing values.' | ||||
if elem in self: | ||||
super().__delitem__(elem) | ||||
def __repr__(self): | ||||
if not self: | ||||
return '%s()' % self.__class__.__name__ | ||||
try: | ||||
items = ', '.join(map('%r: %r'.__mod__, self.most_common())) | ||||
return '%s({%s})' % (self.__class__.__name__, items) | ||||
except TypeError: | ||||
# handle case where values are not orderable | ||||
return '{0}({1!r})'.format(self.__class__.__name__, dict(self)) | ||||
# Multiset-style mathematical operations discussed in: | ||||
# Knuth TAOCP Volume II section 4.6.3 exercise 19 | ||||
# and at http://en.wikipedia.org/wiki/Multiset | ||||
# | ||||
# Outputs guaranteed to only include positive counts. | ||||
# | ||||
# To strip negative and zero counts, add-in an empty counter: | ||||
# c += Counter() | ||||
def __add__(self, other): | ||||
'''Add counts from two counters. | ||||
>>> Counter('abbb') + Counter('bcc') | ||||
Counter({'b': 4, 'c': 2, 'a': 1}) | ||||
''' | ||||
if not isinstance(other, Counter): | ||||
return NotImplemented | ||||
result = Counter() | ||||
for elem, count in self.items(): | ||||
newcount = count + other[elem] | ||||
if newcount > 0: | ||||
result[elem] = newcount | ||||
for elem, count in other.items(): | ||||
if elem not in self and count > 0: | ||||
result[elem] = count | ||||
return result | ||||
def __sub__(self, other): | ||||
''' Subtract count, but keep only results with positive counts. | ||||
>>> Counter('abbbc') - Counter('bccd') | ||||
Counter({'b': 2, 'a': 1}) | ||||
''' | ||||
if not isinstance(other, Counter): | ||||
return NotImplemented | ||||
result = Counter() | ||||
for elem, count in self.items(): | ||||
newcount = count - other[elem] | ||||
if newcount > 0: | ||||
result[elem] = newcount | ||||
for elem, count in other.items(): | ||||
if elem not in self and count < 0: | ||||
result[elem] = 0 - count | ||||
return result | ||||
def __or__(self, other): | ||||
'''Union is the maximum of value in either of the input counters. | ||||
>>> Counter('abbb') | Counter('bcc') | ||||
Counter({'b': 3, 'c': 2, 'a': 1}) | ||||
''' | ||||
if not isinstance(other, Counter): | ||||
return NotImplemented | ||||
result = Counter() | ||||
for elem, count in self.items(): | ||||
other_count = other[elem] | ||||
newcount = other_count if count < other_count else count | ||||
if newcount > 0: | ||||
result[elem] = newcount | ||||
for elem, count in other.items(): | ||||
if elem not in self and count > 0: | ||||
result[elem] = count | ||||
return result | ||||
def __and__(self, other): | ||||
''' Intersection is the minimum of corresponding counts. | ||||
>>> Counter('abbb') & Counter('bcc') | ||||
Counter({'b': 1}) | ||||
''' | ||||
if not isinstance(other, Counter): | ||||
return NotImplemented | ||||
result = Counter() | ||||
for elem, count in self.items(): | ||||
other_count = other[elem] | ||||
newcount = count if count < other_count else other_count | ||||
if newcount > 0: | ||||
result[elem] = newcount | ||||
return result | ||||
######################################################################## | ||||
### ChainMap (helper for configparser) | ||||
######################################################################## | ||||
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) | ||||
def __bool__(self): | ||||
return any(self.maps) | ||||
#fixme, brython | ||||
#@_recursive_repr() | ||||
def __repr__(self): | ||||
return '{0.__class__.__name__}({1})'.format( | ||||
self, ', '.join(map(repr, self.maps))) | ||||
def __repr__(self): | ||||
return ','.join(str(_map) for _map in 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)) | ||||
raise KeyError('Key not found in the first mapping: %s' % key) | ||||
def clear(self): | ||||
'Clear maps[0], leaving maps[1:] intact.' | ||||
self.maps[0].clear() | ||||
################################################################################ | ||||
### UserDict | ||||
################################################################################ | ||||
class UserDict(MutableMapping): | ||||
# Start by filling-out the abstract methods | ||||
def __init__(self, dict=None, **kwargs): | ||||
self.data = {} | ||||
if dict is not None: | ||||
self.update(dict) | ||||
if len(kwargs): | ||||
self.update(kwargs) | ||||
def __len__(self): return len(self.data) | ||||
def __getitem__(self, key): | ||||
if key in self.data: | ||||
return self.data[key] | ||||
if hasattr(self.__class__, "__missing__"): | ||||
return self.__class__.__missing__(self, key) | ||||
raise KeyError(key) | ||||
def __setitem__(self, key, item): self.data[key] = item | ||||
def __delitem__(self, key): del self.data[key] | ||||
def __iter__(self): | ||||
return iter(self.data) | ||||
# Modify __contains__ to work correctly when __missing__ is present | ||||
def __contains__(self, key): | ||||
return key in self.data | ||||
# Now, add the methods in dicts but not in MutableMapping | ||||
def __repr__(self): return repr(self.data) | ||||
def copy(self): | ||||
if self.__class__ is UserDict: | ||||
return UserDict(self.data.copy()) | ||||
import copy | ||||
data = self.data | ||||
try: | ||||
self.data = {} | ||||
c = copy.copy(self) | ||||
finally: | ||||
self.data = data | ||||
c.update(self) | ||||
return c | ||||
@classmethod | ||||
def fromkeys(cls, iterable, value=None): | ||||
d = cls() | ||||
for key in iterable: | ||||
d[key] = value | ||||
return d | ||||
################################################################################ | ||||
### UserList | ||||
################################################################################ | ||||
class UserList(MutableSequence): | ||||
"""A more or less complete user-defined wrapper around list objects.""" | ||||
def __init__(self, initlist=None): | ||||
self.data = [] | ||||
if initlist is not None: | ||||
# XXX should this accept an arbitrary sequence? | ||||
if type(initlist) == type(self.data): | ||||
self.data[:] = initlist | ||||
elif isinstance(initlist, UserList): | ||||
self.data[:] = initlist.data[:] | ||||
else: | ||||
self.data = list(initlist) | ||||
def __repr__(self): return repr(self.data) | ||||
def __lt__(self, other): return self.data < self.__cast(other) | ||||
def __le__(self, other): return self.data <= self.__cast(other) | ||||
def __eq__(self, other): return self.data == self.__cast(other) | ||||
def __ne__(self, other): return self.data != self.__cast(other) | ||||
def __gt__(self, other): return self.data > self.__cast(other) | ||||
def __ge__(self, other): return self.data >= self.__cast(other) | ||||
def __cast(self, other): | ||||
return other.data if isinstance(other, UserList) else other | ||||
def __contains__(self, item): return item in self.data | ||||
def __len__(self): return len(self.data) | ||||
def __getitem__(self, i): return self.data[i] | ||||
def __setitem__(self, i, item): self.data[i] = item | ||||
def __delitem__(self, i): del self.data[i] | ||||
def __add__(self, other): | ||||
if isinstance(other, UserList): | ||||
return self.__class__(self.data + other.data) | ||||
elif isinstance(other, type(self.data)): | ||||
return self.__class__(self.data + other) | ||||
return self.__class__(self.data + list(other)) | ||||
def __radd__(self, other): | ||||
if isinstance(other, UserList): | ||||
return self.__class__(other.data + self.data) | ||||
elif isinstance(other, type(self.data)): | ||||
return self.__class__(other + self.data) | ||||
return self.__class__(list(other) + self.data) | ||||
def __iadd__(self, other): | ||||
if isinstance(other, UserList): | ||||
self.data += other.data | ||||
elif isinstance(other, type(self.data)): | ||||
self.data += other | ||||
else: | ||||
self.data += list(other) | ||||
return self | ||||
def __mul__(self, n): | ||||
return self.__class__(self.data*n) | ||||
__rmul__ = __mul__ | ||||
def __imul__(self, n): | ||||
self.data *= n | ||||
return self | ||||
def append(self, item): self.data.append(item) | ||||
def insert(self, i, item): self.data.insert(i, item) | ||||
def pop(self, i=-1): return self.data.pop(i) | ||||
def remove(self, item): self.data.remove(item) | ||||
def clear(self): self.data.clear() | ||||
def copy(self): return self.__class__(self) | ||||
def count(self, item): return self.data.count(item) | ||||
def index(self, item, *args): return self.data.index(item, *args) | ||||
def reverse(self): self.data.reverse() | ||||
def sort(self, *args, **kwds): self.data.sort(*args, **kwds) | ||||
def extend(self, other): | ||||
if isinstance(other, UserList): | ||||
self.data.extend(other.data) | ||||
else: | ||||
self.data.extend(other) | ||||
################################################################################ | ||||
### UserString | ||||
################################################################################ | ||||
class UserString(Sequence): | ||||
def __init__(self, seq): | ||||
if isinstance(seq, str): | ||||
self.data = seq | ||||
elif isinstance(seq, UserString): | ||||
self.data = seq.data[:] | ||||
else: | ||||
self.data = str(seq) | ||||
def __str__(self): return str(self.data) | ||||
def __repr__(self): return repr(self.data) | ||||
def __int__(self): return int(self.data) | ||||
def __float__(self): return float(self.data) | ||||
def __complex__(self): return complex(self.data) | ||||
def __hash__(self): return hash(self.data) | ||||
def __eq__(self, string): | ||||
if isinstance(string, UserString): | ||||
return self.data == string.data | ||||
return self.data == string | ||||
def __ne__(self, string): | ||||
if isinstance(string, UserString): | ||||
return self.data != string.data | ||||
return self.data != string | ||||
def __lt__(self, string): | ||||
if isinstance(string, UserString): | ||||
return self.data < string.data | ||||
return self.data < string | ||||
def __le__(self, string): | ||||
if isinstance(string, UserString): | ||||
return self.data <= string.data | ||||
return self.data <= string | ||||
def __gt__(self, string): | ||||
if isinstance(string, UserString): | ||||
return self.data > string.data | ||||
return self.data > string | ||||
def __ge__(self, string): | ||||
if isinstance(string, UserString): | ||||
return self.data >= string.data | ||||
return self.data >= string | ||||
def __contains__(self, char): | ||||
if isinstance(char, UserString): | ||||
char = char.data | ||||
return char in self.data | ||||
def __len__(self): return len(self.data) | ||||
def __getitem__(self, index): return self.__class__(self.data[index]) | ||||
def __add__(self, other): | ||||
if isinstance(other, UserString): | ||||
return self.__class__(self.data + other.data) | ||||
elif isinstance(other, str): | ||||
return self.__class__(self.data + other) | ||||
return self.__class__(self.data + str(other)) | ||||
def __radd__(self, other): | ||||
if isinstance(other, str): | ||||
return self.__class__(other + self.data) | ||||
return self.__class__(str(other) + self.data) | ||||
def __mul__(self, n): | ||||
return self.__class__(self.data*n) | ||||
__rmul__ = __mul__ | ||||
def __mod__(self, args): | ||||
return self.__class__(self.data % args) | ||||
# the following methods are defined in alphabetical order: | ||||
def capitalize(self): return self.__class__(self.data.capitalize()) | ||||
def center(self, width, *args): | ||||
return self.__class__(self.data.center(width, *args)) | ||||
def count(self, sub, start=0, end=_sys.maxsize): | ||||
if isinstance(sub, UserString): | ||||
sub = sub.data | ||||
return self.data.count(sub, start, end) | ||||
def encode(self, encoding=None, errors=None): # XXX improve this? | ||||
if encoding: | ||||
if errors: | ||||
return self.__class__(self.data.encode(encoding, errors)) | ||||
return self.__class__(self.data.encode(encoding)) | ||||
return self.__class__(self.data.encode()) | ||||
def endswith(self, suffix, start=0, end=_sys.maxsize): | ||||
return self.data.endswith(suffix, start, end) | ||||
def expandtabs(self, tabsize=8): | ||||
return self.__class__(self.data.expandtabs(tabsize)) | ||||
def find(self, sub, start=0, end=_sys.maxsize): | ||||
if isinstance(sub, UserString): | ||||
sub = sub.data | ||||
return self.data.find(sub, start, end) | ||||
def format(self, *args, **kwds): | ||||
return self.data.format(*args, **kwds) | ||||
def index(self, sub, start=0, end=_sys.maxsize): | ||||
return self.data.index(sub, start, end) | ||||
def isalpha(self): return self.data.isalpha() | ||||
def isalnum(self): return self.data.isalnum() | ||||
def isdecimal(self): return self.data.isdecimal() | ||||
def isdigit(self): return self.data.isdigit() | ||||
def isidentifier(self): return self.data.isidentifier() | ||||
def islower(self): return self.data.islower() | ||||
def isnumeric(self): return self.data.isnumeric() | ||||
def isspace(self): return self.data.isspace() | ||||
def istitle(self): return self.data.istitle() | ||||
def isupper(self): return self.data.isupper() | ||||
def join(self, seq): return self.data.join(seq) | ||||
def ljust(self, width, *args): | ||||
return self.__class__(self.data.ljust(width, *args)) | ||||
def lower(self): return self.__class__(self.data.lower()) | ||||
def lstrip(self, chars=None): return self.__class__(self.data.lstrip(chars)) | ||||
def partition(self, sep): | ||||
return self.data.partition(sep) | ||||
def replace(self, old, new, maxsplit=-1): | ||||
if isinstance(old, UserString): | ||||
old = old.data | ||||
if isinstance(new, UserString): | ||||
new = new.data | ||||
return self.__class__(self.data.replace(old, new, maxsplit)) | ||||
def rfind(self, sub, start=0, end=_sys.maxsize): | ||||
if isinstance(sub, UserString): | ||||
sub = sub.data | ||||
return self.data.rfind(sub, start, end) | ||||
def rindex(self, sub, start=0, end=_sys.maxsize): | ||||
return self.data.rindex(sub, start, end) | ||||
def rjust(self, width, *args): | ||||
return self.__class__(self.data.rjust(width, *args)) | ||||
def rpartition(self, sep): | ||||
return self.data.rpartition(sep) | ||||
def rstrip(self, chars=None): | ||||
return self.__class__(self.data.rstrip(chars)) | ||||
def split(self, sep=None, maxsplit=-1): | ||||
return self.data.split(sep, maxsplit) | ||||
def rsplit(self, sep=None, maxsplit=-1): | ||||
return self.data.rsplit(sep, maxsplit) | ||||
def splitlines(self, keepends=False): return self.data.splitlines(keepends) | ||||
def startswith(self, prefix, start=0, end=_sys.maxsize): | ||||
return self.data.startswith(prefix, start, end) | ||||
def strip(self, chars=None): return self.__class__(self.data.strip(chars)) | ||||
def swapcase(self): return self.__class__(self.data.swapcase()) | ||||
def title(self): return self.__class__(self.data.title()) | ||||
def translate(self, *args): | ||||
return self.__class__(self.data.translate(*args)) | ||||
def upper(self): return self.__class__(self.data.upper()) | ||||
def zfill(self, width): return self.__class__(self.data.zfill(width)) | ||||