Skip to content

Instantly share code, notes, and snippets.

@mmerickel
Last active November 8, 2022 11:33
Show Gist options
  • Star 12 You must be signed in to star a gist
  • Fork 5 You must be signed in to fork a gist
  • Save mmerickel/ff4c6faf867d72c1f19c to your computer and use it in GitHub Desktop.
Save mmerickel/ff4c6faf867d72c1f19c to your computer and use it in GitHub Desktop.
import collections
class DictProxy(collections.Mapping):
"""
A proxy for a dictionary that allows attribute access to underlying keys.
You may pass a custom ``wrapper`` to override the logic for wrapping
various custom types.
"""
def __init__(self, obj, wrapper=wrap):
self.obj = obj
self.wrapper = wrapper
def __getitem__(self, key):
return self.wrapper(self.obj[key])
def __len__(self):
return self.obj.__len__()
def __iter__(self):
return self.obj.__iter__()
def __getattr__(self, key):
try:
return self.wrapper(getattr(self.obj, key))
except AttributeError:
try:
return self[key]
except KeyError:
raise AttributeError(key)
class ListProxy(collections.Sequence):
"""
A proxy for a list that allows for wrapping items.
You may pass a custom ``wrapper`` to override the logic for wrapping
various custom types.
"""
def __init__(self, obj, wrapper=wrap):
self.obj = obj
self.wrapper = wrapper
def __getitem__(self, key):
return self.wrapper(self.obj[key])
def __len__(self):
return self.obj.__len__()
def wrap(value):
"""
The top-level API for wrapping an arbitrary object.
This only works for ``dict``, ``list`` and ``tuple`` types. If you want
to wrap other types you may write your own ``wrap`` and pass ``wrapper=``
to ``DictProxy`` and ``ListProxy``.
"""
if isinstance(value, dict):
return DictProxy(value)
if isinstance(value, (tuple, list)):
return ListProxy(value)
return value
import attrdict
obj = {
'foo': [
{
'a': 1,
'b': {
'c': 2,
}
],
'bar': 5
}
attrobj = attrdict.wrap(obj)
assert attrobj.foo.a == 1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment