Skip to content

Instantly share code, notes, and snippets.

@wbolster
Created November 1, 2017 19:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save wbolster/4acde283870a96b642fad22336a12cef to your computer and use it in GitHub Desktop.
Save wbolster/4acde283870a96b642fad22336a12cef to your computer and use it in GitHub Desktop.
import collections
class attrify:
def __init__(self, d):
object.__setattr__(self, 'd', d)
def __getattribute__(self, name):
if name == '__dict__':
return object.__getattribute__(self, 'd')
try:
value = self[name]
except KeyError as exc:
raise AttributeError(exc.args[0]) from None
if isinstance(value, collections.Mapping):
value = attrify(value)
return value
def __getitem__(self, key):
d = object.__getattribute__(self, 'd')
return d[key]
def __setattr__(self, name, value):
d = object.__getattribute__(self, 'd')
d[name] = value
def __setitem__(self, name, value):
setattr(self, name, value)
def __delattr__(self, name):
try:
del self[name]
except KeyError as exc:
raise AttributeError(exc.args[0]) from None
def __delitem__(self, name):
d = object.__getattribute__(self, 'd')
del d[name]
def __contains__(self, name):
try:
self[name]
except KeyError:
return False
else:
return True
def __iter__(self):
d = object.__getattribute__(self, 'd')
yield from d.items()
def __repr__(self):
d = object.__getattribute__(self, 'd')
return '{}({!r})'.format(type(self).__name__, d)
def test_attrify():
import pytest
d = {
'a': 1,
'b': {'c': 2, 'd': 3},
}
ad = attrify(d)
assert ad.a == 1
assert ad.b
assert ad.b.c == 2
assert ad['a'] == 1
assert ad.b['d'] == 3
with pytest.raises(AttributeError):
ad.nonexistent
with pytest.raises(KeyError):
ad['nonexistent']
assert vars(ad) == d
assert vars(ad) is d
ad.foo = 123
assert ad.foo == 123
ad['foo'] = 456
assert ad.foo == 456
assert hasattr(ad, 'foo')
assert 'foo' in ad
del ad.foo
assert not hasattr(ad, 'foo')
assert 'foo' not in ad
ad.foo = 123
del ad['foo']
assert not hasattr(ad, 'foo')
assert 'foo' not in ad
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment