Mini Shell
"""
Various containers.
"""
def recursion_lock(retval, lock_name = "__recursion_lock__"):
def decorator(func):
def wrapper(self, *args, **kw):
if getattr(self, lock_name, False):
return retval
setattr(self, lock_name, True)
try:
return func(self, *args, **kw)
finally:
setattr(self, lock_name, False)
wrapper.__name__ = func.__name__
return wrapper
return decorator
class Container(dict):
"""
A generic container of attributes.
Containers are the common way to express parsed data.
"""
__slots__ = ["__keys_order__"]
def __init__(self, **kw):
object.__setattr__(self, "__keys_order__", [])
for k, v in kw.items():
self[k] = v
def __getattr__(self, name):
try:
return self[name]
except KeyError:
raise AttributeError(name)
def __setitem__(self, key, val):
if key not in self:
self.__keys_order__.append(key)
dict.__setitem__(self, key, val)
def __delitem__(self, key):
dict.__delitem__(self, key)
self.__keys_order__.remove(key)
__delattr__ = __delitem__
__setattr__ = __setitem__
def clear(self):
dict.clear(self)
del self.__keys_order__[:]
def pop(self, key, *default):
val = dict.pop(self, key, *default)
self.__keys_order__.remove(key)
return val
def popitem(self):
k, v = dict.popitem(self)
self.__keys_order__.remove(k)
return k, v
def update(self, seq, **kw):
if hasattr(seq, "keys"):
for k in seq.keys():
self[k] = seq[k]
else:
for k, v in seq:
self[k] = v
dict.update(self, kw)
def copy(self):
inst = self.__class__()
inst.update(self.iteritems())
return inst
__update__ = update
__copy__ = copy
def __iter__(self):
return iter(self.__keys_order__)
iterkeys = __iter__
def itervalues(self):
return (self[k] for k in self.__keys_order__)
def iteritems(self):
return ((k, self[k]) for k in self.__keys_order__)
def keys(self):
return self.__keys_order__
def values(self):
return list(self.itervalues())
def items(self):
return list(self.iteritems())
def __repr__(self):
return "%s(%s)" % (self.__class__.__name__, dict.__repr__(self))
@recursion_lock("<...>")
def __pretty_str__(self, nesting = 1, indentation = " "):
attrs = []
ind = indentation * nesting
for k, v in self.iteritems():
if not k.startswith("_"):
text = [ind, k, " = "]
if hasattr(v, "__pretty_str__"):
text.append(v.__pretty_str__(nesting + 1, indentation))
else:
text.append(repr(v))
attrs.append("".join(text))
if not attrs:
return "%s()" % (self.__class__.__name__,)
attrs.insert(0, self.__class__.__name__ + ":")
return "\n".join(attrs)
__str__ = __pretty_str__
class FlagsContainer(Container):
"""
A container providing pretty-printing for flags.
Only set flags are displayed.
"""
@recursion_lock("<...>")
def __pretty_str__(self, nesting = 1, indentation = " "):
attrs = []
ind = indentation * nesting
for k in self.keys():
v = self[k]
if not k.startswith("_") and v:
attrs.append(ind + k)
if not attrs:
return "%s()" % (self.__class__.__name__,)
attrs.insert(0, self.__class__.__name__+ ":")
return "\n".join(attrs)
class ListContainer(list):
"""
A container for lists.
"""
__slots__ = ["__recursion_lock__"]
def __str__(self):
return self.__pretty_str__()
@recursion_lock("[...]")
def __pretty_str__(self, nesting = 1, indentation = " "):
if not self:
return "[]"
ind = indentation * nesting
lines = ["["]
for elem in self:
lines.append("\n")
lines.append(ind)
if hasattr(elem, "__pretty_str__"):
lines.append(elem.__pretty_str__(nesting + 1, indentation))
else:
lines.append(repr(elem))
lines.append("\n")
lines.append(indentation * (nesting - 1))
lines.append("]")
return "".join(lines)
class LazyContainer(object):
__slots__ = ["subcon", "stream", "pos", "context", "_value"]
def __init__(self, subcon, stream, pos, context):
self.subcon = subcon
self.stream = stream
self.pos = pos
self.context = context
self._value = NotImplemented
def __eq__(self, other):
try:
return self._value == other._value
except AttributeError:
return False
def __ne__(self, other):
return not (self == other)
def __str__(self):
return self.__pretty_str__()
def __pretty_str__(self, nesting = 1, indentation = " "):
if self._value is NotImplemented:
text = "<unread>"
elif hasattr(self._value, "__pretty_str__"):
text = self._value.__pretty_str__(nesting, indentation)
else:
text = str(self._value)
return "%s: %s" % (self.__class__.__name__, text)
def read(self):
self.stream.seek(self.pos)
return self.subcon._parse(self.stream, self.context)
def dispose(self):
self.subcon = None
self.stream = None
self.context = None
self.pos = None
def _get_value(self):
if self._value is NotImplemented:
self._value = self.read()
return self._value
value = property(_get_value)
has_value = property(lambda self: self._value is not NotImplemented)
if __name__ == "__main__":
c = Container(x=5)
c.y = 8
c.z = 9
c.w = 10
c.foo = 5
print (c)
Zerion Mini Shell 1.0