"""
This module contains implmentations of proxy-list and proxy-dictionary objects.
"""
# flake8: noqa
import collections.abc as abc
def cmp(a, b):
return (a > b) - (a < b)
[docs]
class ListProxy(abc.MutableSequence):
"""
Proxies all methods for a list instance. This is useful when you want to
modify a list's behavior without copying the list.
Methods which do not mutate a list, and instead return a new list will
return a `list` instance rather than a `ListProxy` instance.
:param data: A list or list-like object (implements all the \
:class:`collections.MutableSequence` methods)
.. versionadded:: 2.2
:note: If you intend to use a subclass which modifies the apparent indices
or values of this class with :func:`pytool.json.as_json`, remember
to override :meth:`for_json` to produce the data you desire.
Example::
from pytool.proxy import ListProxy
class SquaredList(ListProxy):
def __setitem__(self, index, value):
if isinstance(value, int):
value *= value
super(SquaredList, self).__setitem__(index, value)
my_list = range(5)
my_proxy = SquaredList(my_list)
my_proxy[3] = 5
my_proxy[3] # 25
my_list[3] # 25
"""
def __init__(self, data):
self._data = data
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):
if isinstance(other, ListProxy):
return other._data
else:
return other
def __cmp__(self, other):
return cmp(self._data, self.__cast(other))
__hash__ = None # Mutable sequence, so not hashable
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 __getslice__(self, i, j):
i = max(i, 0)
j = max(j, 0)
return self._data[i:j]
def __setslice__(self, i, j, other):
i = max(i, 0)
j = max(j, 0)
if isinstance(other, ListProxy):
self._data[i:j] = other._data
elif isinstance(other, type(self._data)):
self._data[i:j] = other
else:
self._data[i:j] = list(other)
def __delslice__(self, i, j):
i = max(i, 0)
j = max(j, 0)
del self._data[i:j]
def __add__(self, other):
if isinstance(other, ListProxy):
return self._data + other._data
elif isinstance(other, type(self._data)):
return self._data + other
else:
return self._data + list(other)
def __radd__(self, other):
if isinstance(other, ListProxy):
return other._data + self._data
elif isinstance(other, type(self._data)):
return other + self._data
else:
return list(other) + self._data
def __iadd__(self, other):
if isinstance(other, ListProxy):
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._data * n
__rmul__ = __mul__
def __imul__(self, n):
self._data *= n
return self
[docs]
def append(self, item):
self._data.append(item)
[docs]
def insert(self, i, item):
self._data.insert(i, item)
[docs]
def pop(self, i=-1):
return self._data.pop(i)
[docs]
def remove(self, item):
self._data.remove(item)
[docs]
def count(self, item):
return self._data.count(item)
[docs]
def index(self, item, *args):
return self._data.index(item, *args)
[docs]
def reverse(self):
self._data.reverse()
def sort(self, *args, **kwds):
self._data.sort(*args, **kwds)
[docs]
def extend(self, other):
if isinstance(other, ListProxy):
self._data.extend(other._data)
else:
self._data.extend(other)
def for_json(self):
return self._data
[docs]
class DictProxy(abc.MutableMapping):
"""
Proxies all methods for a dict instance.
This is useful when you want to modify a dictionary's behavior through
subclassing without copying the dictionary or if you want to be able to
modify the original dictionary.
:param data: A dict or dict-like object (implements all the \
:class:`collections.MutableMapping` methods)
.. versionadded:: 2.2
:note: If you intend to use a subclass which modifies the apparent keys
or values of this class with :func:`pytool.json.as_json`, remember
to override :meth:`for_json` to produce the data you desire.
Example::
from pytool.proxy import DictProxy
class SquaredDict(DictProxy):
def __getitem__(self, key):
value = super(SquaredDict, self).__getitem__(key)
if isinstance(value, int):
value *= value
return value
my_dict = {}
my_proxy = SquaredDict(my_dict)
my_proxy['val'] = 5
my_proxy['val'] # 25
my_dict['val'] # 5
"""
def __init__(self, data):
self._data = data
def __repr__(self):
return repr(self._data)
def __cmp__(self, other):
if isinstance(other, DictProxy):
return cmp(self._data, other._data)
else:
return cmp(self._data, other)
__hash__ = None # Avoid Py3k warning
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]
[docs]
def clear(self):
self._data.clear()
def copy(self):
if self.__class__ is DictProxy:
return self._data.copy()
import copy
data = self._data
try:
self._data = {}
c = copy.copy(self)
finally:
self._data = data
c.update(self)
return c
[docs]
def keys(self):
return self._data.keys()
[docs]
def items(self):
return self._data.items()
def iteritems(self):
return self._data.iteritems()
def iterkeys(self):
return self._data.iterkeys()
def itervalues(self):
return self._data.itervalues()
[docs]
def values(self):
return self._data.values()
def has_key(self, key):
return key in self._data
[docs]
def update(self, other=None, **kwargs):
if other is None:
pass
elif isinstance(other, DictProxy):
self._data.update(other._data)
elif isinstance(other, type({})) or not hasattr(other, "items"):
self._data.update(other)
else:
for k, v in other.items():
self[k] = v
if len(kwargs):
self._data.update(kwargs)
[docs]
def get(self, key, failobj=None):
if key not in self:
return failobj
return self[key]
[docs]
def setdefault(self, key, failobj=None):
if key not in self:
self[key] = failobj
return self[key]
[docs]
def pop(self, key, *args):
return self._data.pop(key, *args)
[docs]
def popitem(self):
return self._data.popitem()
def __contains__(self, key):
return key in self._data
def __iter__(self):
return iter(self._data)
def for_json(self):
return self._data