| | """ |
| | EasyDict |
| | Copy/pasted from https://github.com/makinacorpus/easydict |
| | Original author: Mathieu Leplatre <mathieu.leplatre@makina-corpus.com> |
| | """ |
| |
|
| | class EasyDict(dict): |
| | """ |
| | Get attributes |
| | |
| | >>> d = EasyDict({'foo':3}) |
| | >>> d['foo'] |
| | 3 |
| | >>> d.foo |
| | 3 |
| | >>> d.bar |
| | Traceback (most recent call last): |
| | ... |
| | AttributeError: 'EasyDict' object has no attribute 'bar' |
| | |
| | Works recursively |
| | |
| | >>> d = EasyDict({'foo':3, 'bar':{'x':1, 'y':2}}) |
| | >>> isinstance(d.bar, dict) |
| | True |
| | >>> d.bar.x |
| | 1 |
| | |
| | Bullet-proof |
| | |
| | >>> EasyDict({}) |
| | {} |
| | >>> EasyDict(d={}) |
| | {} |
| | >>> EasyDict(None) |
| | {} |
| | >>> d = {'a': 1} |
| | >>> EasyDict(**d) |
| | {'a': 1} |
| | >>> EasyDict((('a', 1), ('b', 2))) |
| | {'a': 1, 'b': 2} |
| | |
| | Set attributes |
| | |
| | >>> d = EasyDict() |
| | >>> d.foo = 3 |
| | >>> d.foo |
| | 3 |
| | >>> d.bar = {'prop': 'value'} |
| | >>> d.bar.prop |
| | 'value' |
| | >>> d |
| | {'foo': 3, 'bar': {'prop': 'value'}} |
| | >>> d.bar.prop = 'newer' |
| | >>> d.bar.prop |
| | 'newer' |
| | |
| | |
| | Values extraction |
| | |
| | >>> d = EasyDict({'foo':0, 'bar':[{'x':1, 'y':2}, {'x':3, 'y':4}]}) |
| | >>> isinstance(d.bar, list) |
| | True |
| | >>> from operator import attrgetter |
| | >>> list(map(attrgetter('x'), d.bar)) |
| | [1, 3] |
| | >>> list(map(attrgetter('y'), d.bar)) |
| | [2, 4] |
| | >>> d = EasyDict() |
| | >>> list(d.keys()) |
| | [] |
| | >>> d = EasyDict(foo=3, bar=dict(x=1, y=2)) |
| | >>> d.foo |
| | 3 |
| | >>> d.bar.x |
| | 1 |
| | |
| | Still like a dict though |
| | |
| | >>> o = EasyDict({'clean':True}) |
| | >>> list(o.items()) |
| | [('clean', True)] |
| | |
| | And like a class |
| | |
| | >>> class Flower(EasyDict): |
| | ... power = 1 |
| | ... |
| | >>> f = Flower() |
| | >>> f.power |
| | 1 |
| | >>> f = Flower({'height': 12}) |
| | >>> f.height |
| | 12 |
| | >>> f['power'] |
| | 1 |
| | >>> sorted(f.keys()) |
| | ['height', 'power'] |
| | |
| | update and pop items |
| | >>> d = EasyDict(a=1, b='2') |
| | >>> e = EasyDict(c=3.0, a=9.0) |
| | >>> d.update(e) |
| | >>> d.c |
| | 3.0 |
| | >>> d['c'] |
| | 3.0 |
| | >>> d.get('c') |
| | 3.0 |
| | >>> d.update(a=4, b=4) |
| | >>> d.b |
| | 4 |
| | >>> d.pop('a') |
| | 4 |
| | >>> d.a |
| | Traceback (most recent call last): |
| | ... |
| | AttributeError: 'EasyDict' object has no attribute 'a' |
| | """ |
| | def __init__(self, d=None, **kwargs): |
| | if d is None: |
| | d = {} |
| | else: |
| | d = dict(d) |
| | if kwargs: |
| | d.update(**kwargs) |
| | for k, v in d.items(): |
| | setattr(self, k, v) |
| | |
| | for k in self.__class__.__dict__.keys(): |
| | if not (k.startswith('__') and k.endswith('__')) and not k in ('update', 'pop'): |
| | setattr(self, k, getattr(self, k)) |
| |
|
| | def __setattr__(self, name, value): |
| | if isinstance(value, (list, tuple)): |
| | value = [self.__class__(x) |
| | if isinstance(x, dict) else x for x in value] |
| | elif isinstance(value, dict) and not isinstance(value, self.__class__): |
| | value = self.__class__(value) |
| | super(EasyDict, self).__setattr__(name, value) |
| | super(EasyDict, self).__setitem__(name, value) |
| |
|
| | __setitem__ = __setattr__ |
| |
|
| | def update(self, e=None, **f): |
| | d = e or dict() |
| | d.update(f) |
| | for k in d: |
| | setattr(self, k, d[k]) |
| |
|
| | def pop(self, k, d=None): |
| | delattr(self, k) |
| | return super(EasyDict, self).pop(k, d) |
| |
|
| |
|
| | if __name__ == "__main__": |
| | import doctest |
| | doctest.testmod() |