Adjustments/retabbing for attrdict.py
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().
This commit is contained in:
parent
d43220535f
commit
02019c7dc5
1 changed files with 67 additions and 49 deletions
|
@ -1,49 +1,67 @@
|
||||||
# Modified version of the code featured at the given link
|
# Modified version of the code featured at the given link
|
||||||
## {{{ http://code.activestate.com/recipes/473786/ (r1)
|
## {{{ http://code.activestate.com/recipes/473786/ (r1)
|
||||||
class AttrDict(dict):
|
class AttrDict(dict):
|
||||||
"""A dictionary with attribute-style access. It maps attribute access to
|
"""A dictionary with attribute-style access. It maps attribute access to
|
||||||
the real dictionary."""
|
the real dictionary."""
|
||||||
def __init__(self, init={}): super(AttrDict, self).__init__(init)
|
def __init__(self, init={}): super(AttrDict, self).__init__(init)
|
||||||
def __getstate__(self): return self.__dict__.items()
|
def __getstate__(self): return self.__dict__.items()
|
||||||
def __setstate__(self, items):
|
def __setstate__(self, items):
|
||||||
for key, val in items: self.__dict__[key] = val
|
for key, val in items: self.__dict__[key] = val
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "%s(%s)" % (
|
return "{}({})".format(
|
||||||
type(self).__name__,
|
type(self).__name__,
|
||||||
super(AttrDict, self).__repr__()
|
super(AttrDict, self).__repr__()
|
||||||
)
|
)
|
||||||
def __setitem__(self, key, value):
|
def __setitem__(self, key, value):
|
||||||
return super(AttrDict, self).__setitem__(key, value)
|
return super(AttrDict, self).__setitem__(key, value)
|
||||||
def __getitem__(self, name):
|
def __getitem__(self, name):
|
||||||
return super(AttrDict, self).__getitem__(name)
|
return super(AttrDict, self).__getitem__(name)
|
||||||
def __delitem__(self, name):
|
def __delitem__(self, name):
|
||||||
return super(AttrDict, self).__delitem__(name)
|
return super(AttrDict, self).__delitem__(name)
|
||||||
__getattr__ = __getitem__
|
def __getattr__(self, name):
|
||||||
__setattr__ = __setitem__
|
# Basically, fall back on __getitem__ first
|
||||||
__delattr__ = __delitem__
|
# Try to access ourselves as a dict. Failing that, check for attributes
|
||||||
def copy(self): return type(self)(self)
|
# with the same name. Failing *that*, throw AttributeError to keep
|
||||||
## end of http://code.activestate.com/recipes/473786/ }}}
|
# other code happy.
|
||||||
|
try: retval = self[name]
|
||||||
class DefAttrDict(AttrDict):
|
except KeyError as err:
|
||||||
def __init__(self, default_factory=None, *args, **kwargs):
|
try: retval = self.__dict__[name]
|
||||||
self.__dict__["default_factory"] = default_factory
|
except KeyError:
|
||||||
super(DefAttrDict, self).__init__(*args, **kwargs)
|
# Raising KeyError here will confuse __deepcopy__, so don't do
|
||||||
def __repr__(self):
|
# that.
|
||||||
return "%s(%r, %s)" % (
|
raise AttributeError("No key/attr {!r}".format(name))
|
||||||
type(self).__name__,
|
return retval
|
||||||
self.default_factory,
|
__setattr__ = __setitem__
|
||||||
super(AttrDict, self).__repr__()
|
def __delattr__(self, name):
|
||||||
)
|
try: del self[name]
|
||||||
def __getitem__(self, name):
|
except KeyError as err:
|
||||||
try:
|
try: del self.__dict__[name]
|
||||||
return super(DefAttrDict, self).__getitem__(name)
|
except KeyError:
|
||||||
except KeyError:
|
raise AttributeError(str(err))
|
||||||
##if self.default_factory is None: return None
|
def copy(self): return type(self)(self)
|
||||||
##return self.default_factory()
|
__copy__ = copy
|
||||||
result = None
|
## end of http://code.activestate.com/recipes/473786/ }}}
|
||||||
if self.default_factory is not None:
|
|
||||||
result = self.default_factory()
|
class DefAttrDict(AttrDict):
|
||||||
self[name] = result
|
def __init__(self, default_factory=None, *args, **kwargs):
|
||||||
return result
|
self.__dict__["default_factory"] = default_factory
|
||||||
__getattr__ = __getitem__
|
super(DefAttrDict, self).__init__(*args, **kwargs)
|
||||||
def copy(self): return type(self)(self.default_factory, self)
|
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)
|
||||||
|
|
Loading…
Reference in a new issue