02019c7dc5
Redid some of the logic behind AttrDict. It now raises AttributeError when necessary, instead of giving the incorrect KeyError response. This has restored compatibility with copy.deepcopy().
68 lines
2.7 KiB
Python
68 lines
2.7 KiB
Python
# Modified version of the code featured at the given link
|
|
## {{{ http://code.activestate.com/recipes/473786/ (r1)
|
|
class AttrDict(dict):
|
|
"""A dictionary with attribute-style access. It maps attribute access to
|
|
the real dictionary."""
|
|
def __init__(self, init={}): super(AttrDict, self).__init__(init)
|
|
def __getstate__(self): return self.__dict__.items()
|
|
def __setstate__(self, items):
|
|
for key, val in items: self.__dict__[key] = val
|
|
def __repr__(self):
|
|
return "{}({})".format(
|
|
type(self).__name__,
|
|
super(AttrDict, self).__repr__()
|
|
)
|
|
def __setitem__(self, key, value):
|
|
return super(AttrDict, self).__setitem__(key, value)
|
|
def __getitem__(self, name):
|
|
return super(AttrDict, self).__getitem__(name)
|
|
def __delitem__(self, name):
|
|
return super(AttrDict, self).__delitem__(name)
|
|
def __getattr__(self, name):
|
|
# Basically, fall back on __getitem__ first
|
|
# Try to access ourselves as a dict. Failing that, check for attributes
|
|
# with the same name. Failing *that*, throw AttributeError to keep
|
|
# other code happy.
|
|
try: retval = self[name]
|
|
except KeyError as err:
|
|
try: retval = self.__dict__[name]
|
|
except KeyError:
|
|
# Raising KeyError here will confuse __deepcopy__, so don't do
|
|
# that.
|
|
raise AttributeError("No key/attr {!r}".format(name))
|
|
return retval
|
|
__setattr__ = __setitem__
|
|
def __delattr__(self, name):
|
|
try: del self[name]
|
|
except KeyError as err:
|
|
try: del self.__dict__[name]
|
|
except KeyError:
|
|
raise AttributeError(str(err))
|
|
def copy(self): return type(self)(self)
|
|
__copy__ = copy
|
|
## end of http://code.activestate.com/recipes/473786/ }}}
|
|
|
|
class DefAttrDict(AttrDict):
|
|
def __init__(self, default_factory=None, *args, **kwargs):
|
|
self.__dict__["default_factory"] = default_factory
|
|
super(DefAttrDict, self).__init__(*args, **kwargs)
|
|
def __repr__(self):
|
|
return "%s(%r, %s)" % (
|
|
type(self).__name__,
|
|
self.default_factory,
|
|
super(AttrDict, self).__repr__()
|
|
)
|
|
def __getitem__(self, name):
|
|
try:
|
|
return super(DefAttrDict, self).__getitem__(name)
|
|
except KeyError:
|
|
##if self.default_factory is None: return None
|
|
##return self.default_factory()
|
|
result = None
|
|
if self.default_factory is not None:
|
|
result = self.default_factory()
|
|
self[name] = result
|
|
return result
|
|
__getattr__ = __getitem__
|
|
def copy(self): return type(self)(self.default_factory, self)
|