kwcoco.util.dict_proxy2 module¶
- class kwcoco.util.dict_proxy2.DictInterface[source]¶
Bases:
object- An inherited class must specify the
getitem,setitem, and keysmethods.
A class is dictionary like if it has:
__iter__,__len__,__contains__,__getitem__,items,keys,values,get,and if it should be writable it should have:
__delitem__,__setitem__,update,And perhaps:
copy,__iter__,__len__,__contains__,__getitem__,items,keys,values,get,and if it should be writable it should have:
__delitem__,__setitem__,update,And perhaps:
copy,Example
from scriptconfig.dict_like import DictLike class DuckDict(DictLike):
- def __init__(self, _data=None):
- if _data is None:
_data = {}
self._data = _data
- def getitem(self, key):
return self._data[key]
- def keys(self):
return self._data.keys()
self = DuckDict({1: 2, 3: 4}) print(f’self._data={self._data}’) cast = dict(self) print(f’cast={cast}’) print(f’self={self}’)
- An inherited class must specify the
- class kwcoco.util.dict_proxy2.DictProxy2[source]¶
Bases:
DictInterfaceAllows an object to proxy the behavior of a _proxy dict attribute.
Inheriting classes must define a
self._proxyattribute as a dictionary. Given that, this class will give the inheriting class methods such that the user can treat it like a dictionary and all dictionary operations are simply forwarded to proxy. In other words, you can make a class that wraps a dictionary, still makes it behave like a dictionary, but you can do fancy things with other methods and attributes, while still maintaining the core underlying dictionary.Example
>>> from kwcoco.util.dict_proxy2 import * # NOQA >>> import math >>> class MyClass(DictProxy2): >>> def __init__(self): >>> self._proxy = {} >>> # The instance ``self`` now behaves like a dictionary. >>> self = MyClass() >>> self['a'] = 1 >>> self['b'] = 2 >>> self['cc'] = self['a'] ** 2 + self['b'] ** 2 >>> self['c'] = math.sqrt(self.pop('cc')) >>> assert dict(self) == self._proxy >>> assert 'cc' not in self >>> assert 'c' in self >>> # >>> # Check that the class provides the same API as the underlying >>> # dictionary. >>> self_attrs = set(dir(self)) >>> proxy_attrs = set(dir(self._proxy)) >>> proxy_only = proxy_attrs - self_attrs >>> self_only = self_attrs - proxy_attrs >>> print(f'proxy_only={proxy_only}') >>> print(f'self_only={self_only}') >>> # >>> # We dont quite do everything yet >>> CURRENTLY_UNSUPPORTED = { >>> '__class_getitem__', >>> '__ior__', >>> '__or__', >>> '__reversed__', >>> '__ror__', >>> 'clear', >>> 'copy', >>> 'fromkeys', >>> 'popitem', >>> 'setdefault'} >>> assert len(proxy_only - CURRENTLY_UNSUPPORTED) == 0
- class kwcoco.util.dict_proxy2._AliasMetaclass(name, bases, namespace, *args, **kwargs)[source]¶
Bases:
typePopulates the __alias_to_aliases__ field at class definition time to reduce the overhead of instance creation.
- class kwcoco.util.dict_proxy2.AliasedDictProxy[source]¶
Bases:
DictProxy2Can have a class attribute called ``__alias_to_primary__ `` which is a Dict[str, str] mapping alias-keys to primary-keys.
Need to handle cases:
- image dictionary contains no primary / aliased keys
primary keys used
- image dictionary only has aliased keys
aliased keys are updated
- image dictionary only has primary keys
primary keys are updated
- image dictionary only both primary and aliased keys
both keys are updated
Example
>>> from kwcoco.util.dict_proxy2 import * # NOQA >>> class MyAliasedObject(AliasedDictProxy): >>> __alias_to_primary__ = { >>> 'foo_alias1': 'foo_primary', >>> 'foo_alias2': 'foo_primary', >>> 'bar_alias1': 'bar_primary', >>> } >>> def __init__(self, obj): >>> self._proxy = obj >>> def __repr__(self): >>> return repr(self._proxy) >>> def __str__(self): >>> return str(self._proxy) >>> # Test starting from empty >>> obj = MyAliasedObject({}) >>> obj['regular_key'] = 'val0' >>> assert 'foo_primary' not in obj >>> assert 'foo_alias1' not in obj >>> assert 'foo_alias2' not in obj >>> obj['foo_primary'] = 'val1' >>> assert 'foo_primary' in obj >>> assert 'foo_alias1' in obj >>> assert 'foo_alias2' in obj >>> obj['foo_alias1'] = 'val2' >>> obj['foo_alias2'] = 'val3' >>> obj['bar_alias1'] = 'val4' >>> obj['bar_primary'] = 'val5' >>> assert obj._proxy == { >>> 'regular_key': 'val0', >>> 'foo_primary': 'val3', >>> 'bar_primary': 'val5'} >>> # Test starting with primary keys >>> obj = MyAliasedObject({ >>> 'foo_primary': 123, >>> 'bar_primary': 123, >>> }) >>> assert 'foo_alias1' in obj >>> assert 'bar_alias1' in obj >>> obj['bar_alias1'] = 456 >>> obj['foo_primary'] = 789 >>> assert obj._proxy == { >>> 'foo_primary': 789, >>> 'bar_primary': 456} >>> # Test that if aliases keys are existent we dont add primary keys >>> obj = MyAliasedObject({ >>> 'foo_alias1': 123, >>> }) >>> assert 'foo_alias1' in obj >>> assert 'foo_primary' in obj >>> obj['foo_alias1'] = 456 >>> obj['foo_primary'] = 789 >>> assert obj._proxy == { >>> 'foo_alias1': 789, >>> } >>> # Test that if primary and aliases keys exist, we update both >>> obj = MyAliasedObject({ >>> 'foo_primary': 3, >>> 'foo_alias2': 5, >>> }) >>> # We do not attempt to detect conflicts >>> assert obj['foo_primary'] == 3 >>> assert obj['foo_alias1'] == 3 >>> assert obj['foo_alias2'] == 5 >>> obj['foo_alias1'] = 23 >>> assert obj['foo_primary'] == 23 >>> assert obj['foo_alias1'] == 23 >>> assert obj['foo_alias2'] == 23 >>> obj['foo_primary'] = -12 >>> assert obj['foo_primary'] == -12 >>> assert obj['foo_alias1'] == -12 >>> assert obj['foo_alias2'] == -12 >>> assert obj._proxy == { >>> 'foo_primary': -12, >>> 'foo_alias2': -12}