From 8c7be0acdfdf46274748507c1a53d6680b1a8de9 Mon Sep 17 00:00:00 2001 From: "Trevor Joynson (trevorj)" Date: Fri, 28 Dec 2018 17:18:27 -0800 Subject: [PATCH] Tests --- .coveragerc | 2 +- pytutils/lazy/README.md | 1 + pytutils/mappings.py | 104 +++++++++++++++++++++++++++++++++------- 3 files changed, 88 insertions(+), 19 deletions(-) create mode 100644 pytutils/lazy/README.md diff --git a/.coveragerc b/.coveragerc index 37c39f4..0a43efc 100644 --- a/.coveragerc +++ b/.coveragerc @@ -2,4 +2,4 @@ omit = */tests/* */test_*.py - + pytutils/lazy/*.py diff --git a/pytutils/lazy/README.md b/pytutils/lazy/README.md new file mode 100644 index 0000000..7e9bbef --- /dev/null +++ b/pytutils/lazy/README.md @@ -0,0 +1 @@ +What's here is not mine, I have lost track of where it's from, but it would be a GPL'd library on github. diff --git a/pytutils/mappings.py b/pytutils/mappings.py index 73c1b84..10e7eda 100644 --- a/pytutils/mappings.py +++ b/pytutils/mappings.py @@ -1,9 +1,11 @@ import collections -import re import os +import re import six +from .props import classproperty + class AttrDict(dict): """ @@ -19,7 +21,30 @@ def __init__(self, *args, **kwargs): class ProxyMutableMapping(collections.MutableMapping): - """Proxies access to an existing dict-like object.""" + """ + Proxies access to an existing dict-like object. + + >>> a = dict(whoa=True, hello=[1,2,3], why='always') + >>> b = ProxyMutableAttrDict(a) + + Nice reprs: + + >>> b + + + Setting works as you'd expect: + + >>> b['nice'] = False + >>> b['whoa'] = 'yeee' + >>> b + + + Checking that the changes are in fact being performed on the proxied object: + + >>> a + {'whoa': 'yeee', 'hello': [1, 2, 3], 'why': 'always', 'nice': False} + + """ def __init__(self, mapping, fancy_repr=True, dictify_repr=False): """ @@ -65,6 +90,11 @@ def __len__(self): class HookableProxyMutableMapping(ProxyMutableMapping): + def __init__(self, mapping, fancy_repr=True, dictify_repr=False): + self.__mapping = mapping + + super(HookableProxyMutableMapping, self).__init__(mapping, fancy_repr=fancy_repr, dictify_repr=dictify_repr) + def __key_trans__(self, key, store=False, get=False, contains=False, delete=False): return key @@ -227,10 +257,58 @@ def format_dict_recursively( return ret -class ProxyMutableAttrDict(dict): - @property - def _wrap_as(self): - return self.__class__ +class ProxyMutableAttrDict(ProxyMutableMapping): + """ + Proxies mutable access to another mapping and allows for attribute-style access. + + >>> a = dict(whoa=True, hello=[1,2,3], why='always') + >>> b = ProxyMutableAttrDict(a) + + Nice reprs: + + >>> b + + + Setting works as you'd expect: + + >>> b['nice'] = False + >>> b['whoa'] = 'yeee' + >>> b + + + Checking that the changes are in fact being performed on the proxied object: + + >>> a + {'whoa': 'yeee', 'hello': [1, 2, 3], 'why': 'always', 'nice': False} + + Attribute style access: + + >>> b.whoa + 'yeee' + >>> b.state = 'new' + >>> b + + + Recursion is handled: + + >>> b.subdict = dict(test=True) + >>> b.subdict.test + True + >>> b + }> + + """ + + def __init__(self, mapping, fancy_repr=True, dictify_repr=False, recursion=True): + self.__recursion = recursion + self.__mapping = mapping + + super(ProxyMutableAttrDict, self).__init__(mapping, fancy_repr=fancy_repr, dictify_repr=dictify_repr) + + @classproperty + def _wrap_as(cls): + return cls def __getattr__(self, key): if not key.startswith('_'): @@ -243,7 +321,7 @@ def __getattr__(self, key): def __setattr__(self, key, value): if not key.startswith('_'): - if isinstance(value, collections.Mapping) and not isinstance(value, self._wrap_as): + if self.__recursion and isinstance(value, collections.Mapping) and not isinstance(value, self._wrap_as): value = self.__class__(value) try: @@ -255,17 +333,7 @@ def __setattr__(self, key, value): return super(ProxyMutableAttrDict, self).__setattr__(key, value) -class RecursiveProxyAttrDict(ProxyMutableMapping): - __getattr__ = ProxyMutableMapping.__getitem__ - __setattr__ = ProxyMutableMapping.__setitem__ - - def __getitem__(self, name): - val = self.__getitem__(name) - - if isinstance(val, collections.Mapping) and not isinstance(val, self.__class__): - val = self.__class__(val) - - raise AttributeError(name) +RecursiveProxyAttrDict = ProxyMutableAttrDict class ProcessLocal(HookableProxyMutableMapping):