diff options
Diffstat (limited to 'external/construct/lib/container.py')
-rw-r--r-- | external/construct/lib/container.py | 224 |
1 files changed, 224 insertions, 0 deletions
diff --git a/external/construct/lib/container.py b/external/construct/lib/container.py new file mode 100644 index 0000000..f04d037 --- /dev/null +++ b/external/construct/lib/container.py @@ -0,0 +1,224 @@ +""" +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) + + |