|
|
|
|
|
|
|
|
|
|
|
import rootpath |
|
|
|
rootpath.append() |
|
|
|
import collections |
|
|
|
import attributedict.compat as compat |
|
|
|
|
|
|
|
|
|
|
|
|
|
DEFAULT_RESERVED_KEY_PREFIX = '__' |
|
DEFAULT_RESERVED_KEY_SUFFIX = None |
|
|
|
|
|
|
|
|
|
|
|
|
|
class AttributeDict(dict): |
|
|
|
""" |
|
:class:`~attributedict.collections.AttributeDict` is a seamlessly extended dictionary object (subclass of `dict`), |
|
with access to additional attribute get/set/delete of key/values. |
|
|
|
@example: |
|
|
|
data = AttributeDict({'foo': {'bar': [1, 2, 3]}}) |
|
|
|
data.foo # => `{'bar': [1, 2, 3]}}` |
|
data.foo.bar # => `[1, 2, 3]` |
|
|
|
data.foo = {'baz': True} |
|
data.foo = # => `{'baz': True}` |
|
|
|
del data.foo |
|
|
|
""" |
|
|
|
def __init__(self, entries = {}): |
|
entries = entries or {} |
|
entries = self._reject_reserved_keys(entries) |
|
|
|
super(AttributeDict, self).__init__(entries) |
|
|
|
self.update(entries) |
|
|
|
def _refresh(self): |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
dict.__init__(self, self.__dict__) |
|
|
|
def _reject_reserved_keys(self, object = {}): |
|
|
|
|
|
|
|
reserved_key_prefix = DEFAULT_RESERVED_KEY_PREFIX |
|
reserved_key_suffix = DEFAULT_RESERVED_KEY_SUFFIX |
|
|
|
if isinstance(object, dict): |
|
for key, value in list(object.items()): |
|
is_reserved = False |
|
|
|
if len(reserved_key_prefix or ''): |
|
is_reserved = key.startswith(reserved_key_prefix) |
|
|
|
if len(reserved_key_suffix or ''): |
|
is_reserved = is_reserved or key.startswith(reserved_key_suffix) |
|
|
|
if is_reserved: |
|
del object[key] |
|
|
|
else: |
|
object[key] = self._reject_reserved_keys(object[key]) |
|
|
|
return object |
|
|
|
def update(self, entries = {}, *args, **kwargs): |
|
""" |
|
Update dictionary. |
|
|
|
@example: |
|
|
|
object.update({'foo': {'bar': 1}}) |
|
|
|
""" |
|
if isinstance(entries, dict): |
|
entries = self._reject_reserved_keys(entries) |
|
|
|
for key, value in dict(entries, *args, **kwargs).items(): |
|
if isinstance(value, dict): |
|
self.__dict__[key] = AttributeDict(value) |
|
else: |
|
self.__dict__[key] = value |
|
|
|
self._refresh() |
|
|
|
def keys(self): |
|
return self.__dict__.keys() |
|
|
|
def values(self): |
|
return self.__dict__.values() |
|
|
|
def items(self, *args, **kwargs): |
|
return self.__dict__.items(*args, **kwargs) |
|
|
|
def iterkeys(self, *args, **kwargs): |
|
self.__dict__.iterkeys(*args, **kwargs) |
|
|
|
def itervalues(self, *args, **kwargs): |
|
self.__dict__.itervalues(*args, **kwargs) |
|
|
|
def iteritems(self, *args, **kwargs): |
|
self.__dict__.items(*args, **kwargs) |
|
|
|
def get(self, key, default = None): |
|
result = self.__dict__.get(key, default) |
|
|
|
return result |
|
|
|
def pop(self, key, value = None): |
|
result = self.__dict__.pop(key, value) |
|
|
|
self._refresh() |
|
|
|
return result |
|
|
|
def copy(self): |
|
return type(self)(self) |
|
|
|
def setdefault(self, key, default = None): |
|
result = self.__dict__.setdefault(key, default) |
|
|
|
self._refresh() |
|
|
|
return result |
|
|
|
def __getitem__(self, key): |
|
""" |
|
Provides `dict` style property access to dictionary key-values. |
|
|
|
@example: |
|
|
|
value = object['key'] |
|
|
|
# ignored |
|
object['__key__'] |
|
|
|
""" |
|
result = self.__dict__.__getitem__(key) |
|
|
|
self._refresh() |
|
|
|
return result |
|
|
|
def __setitem__(self, key, value): |
|
""" |
|
Provides `dict` style property assignment to dictionary key-values. |
|
|
|
@example: |
|
|
|
object['key'] = value |
|
|
|
# ignored |
|
object['__key__'] = value |
|
|
|
""" |
|
if isinstance(value, dict): |
|
value = AttributeDict(value) |
|
|
|
result = self.__dict__.__setitem__(key, value) |
|
|
|
self._refresh() |
|
|
|
return result |
|
|
|
def __delitem__(self, key): |
|
""" |
|
Provides `dict` style property deletion to dictionary key-values. |
|
|
|
@example: |
|
|
|
del object['key'] |
|
|
|
# ignored |
|
del object['__key__'] |
|
|
|
""" |
|
result = self.__dict__.__delitem__(key) |
|
|
|
self._refresh() |
|
|
|
return result |
|
|
|
def __getattr__(self, key): |
|
""" |
|
Provides `object` style attribute access to dictionary key-values. |
|
|
|
@example: |
|
|
|
value = object.key |
|
|
|
# ignored |
|
object.__key__ |
|
|
|
""" |
|
try: |
|
return self.__getitem__(key) |
|
|
|
except Exception as error: |
|
raise AttributeError(error) |
|
|
|
def __setattr__(self, key, value): |
|
""" |
|
Provides `object` style attribute assignment to dictionary key-values. |
|
|
|
@example: |
|
|
|
object.key = value |
|
|
|
# ignored |
|
object.__key__ = value |
|
|
|
""" |
|
try: |
|
return self.__setitem__(key, value) |
|
|
|
except Exception as error: |
|
raise AttributeError(error) |
|
|
|
def __delattr__(self, key): |
|
""" |
|
Provides `object` style attribute deletion to dictionary key-values. |
|
|
|
@example: |
|
|
|
del object.key |
|
|
|
# ignored |
|
del object.__key__ |
|
|
|
""" |
|
try: |
|
return self.__delitem__(key) |
|
|
|
except Exception as error: |
|
raise AttributeError(error) |
|
|
|
def __str__(self): |
|
""" |
|
String value of the dictionary instance. |
|
""" |
|
return str(self.__dict__) |
|
|
|
def __repr__(self): |
|
""" |
|
String representation of the dictionary instance. |
|
""" |
|
return repr(self.__dict__) |
|
|
|
def __dir__(self): |
|
return dir(type(self)) + list(self.__dict__.keys()) |
|
|
|
def __iter__(self): |
|
""" |
|
Iterate over dictionary key/values. |
|
""" |
|
return iter(self.__dict__.keys()) |
|
|
|
def __len__(self): |
|
""" |
|
Get number of items. |
|
""" |
|
return len(self.__dict__.keys()) |
|
|
|
def __contains__(self, key): |
|
""" |
|
Check if key exists. |
|
""" |
|
return self.__dict__.__contains__(key) |
|
|
|
def __reduce__(self): |
|
""" |
|
Return state information for pickling. |
|
""" |
|
return self.__dict__.__reduce__() |
|
|
|
def __eq__(self, other): |
|
""" |
|
Check dictionary is equal to another provided dictionary. |
|
""" |
|
return self.__dict__.__eq__(other) |
|
|
|
def __ne__(self, other): |
|
""" |
|
Check dictionary is inequal to another provided dictionary. |
|
""" |
|
return self.__dict__.__ne__(other) |
|
|
|
def to_dict(self): |
|
return self.__class__.dict(self.__dict__) |
|
|
|
@classmethod |
|
def fromkeys(klass, keys, value = None): |
|
return AttributeDict(dict.fromkeys((key for key in keys), value)) |
|
|
|
@classmethod |
|
def dict(klass, _dict = {}): |
|
if _dict is None: |
|
return None |
|
|
|
new_dict = {} |
|
|
|
for key, value in _dict.items(): |
|
if isinstance(value, AttributeDict): |
|
new_dict[key] = AttributeDict.to_dict(value) |
|
else: |
|
new_dict[key] = value |
|
|
|
return new_dict |
|
|
|
|
|
|
|
|
|
|
|
|
|
attributedict = AttributeDict |
|
attrdict = AttributeDict |
|
|
|
__all__ = [ |
|
'AttributeDict', |
|
|
|
'attributedict', |
|
'attrdict', |
|
] |
|
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == '__main__': |
|
|
|
data = { |
|
'a': { |
|
'b': { |
|
'c': [1, 2, 3] |
|
} |
|
} |
|
} |
|
|
|
object = AttributeDict(data) |
|
|
|
print('object = AttributeDict({0})\n'.format(data)) |
|
|
|
print('object\n\n\t{0}\n'.format(object)) |
|
print('object.a\n\n\t{0}\n'.format(object.a)) |
|
print('object.a.b\n\n\t{0}\n'.format(object.a.b)) |
|
print('object.a.b.c\n\n\t{0}\n'.format(object.a.b.c)) |
|
|