ebenders | 198538a | 2011-09-07 11:12:47 +0300 | [diff] [blame] | 1 | def recursion_lock(retval, lock_name = "__recursion_lock__"):
|
| 2 | def decorator(func):
|
| 3 | def wrapper(self, *args, **kw):
|
| 4 | if getattr(self, lock_name, False):
|
| 5 | return retval
|
| 6 | setattr(self, lock_name, True)
|
| 7 | try:
|
| 8 | return func(self, *args, **kw)
|
| 9 | finally:
|
| 10 | setattr(self, lock_name, False)
|
| 11 | wrapper.__name__ = func.__name__
|
| 12 | return wrapper
|
| 13 | return decorator
|
| 14 |
|
| 15 | class Container(object):
|
| 16 | """
|
| 17 | A generic container of attributes
|
| 18 | """
|
| 19 | __slots__ = ["__dict__", "__attrs__"]
|
| 20 | def __init__(self, **kw):
|
| 21 | self.__dict__.update(kw)
|
| 22 | object.__setattr__(self, "__attrs__", kw.keys())
|
| 23 |
|
| 24 | def __eq__(self, other):
|
| 25 | try:
|
| 26 | return self.__dict__ == other.__dict__
|
| 27 | except AttributeError:
|
| 28 | return False
|
| 29 | def __ne__(self, other):
|
| 30 | return not (self == other)
|
| 31 |
|
| 32 | def __delattr__(self, name):
|
| 33 | object.__delattr__(self, name)
|
| 34 | self.__attrs__.remove(name)
|
| 35 | def __setattr__(self, name, value):
|
| 36 | d = self.__dict__
|
| 37 | if name not in d:
|
| 38 | self.__attrs__.append(name)
|
| 39 | d[name] = value
|
| 40 | def __getitem__(self, name):
|
| 41 | return self.__dict__[name]
|
| 42 | def __delitem__(self, name):
|
| 43 | self.__delattr__(name)
|
| 44 | def __setitem__(self, name, value):
|
| 45 | self.__setattr__(name, value)
|
| 46 | def __update__(self, obj):
|
| 47 | for name in obj.__attrs__:
|
| 48 | self[name] = obj[name]
|
| 49 | def __copy__(self):
|
| 50 | new = self.__class__()
|
| 51 | new.__attrs__ = self.__attrs__[:]
|
| 52 | new.__dict__ = self.__dict__.copy()
|
| 53 | return new
|
| 54 |
|
| 55 | @recursion_lock("<...>")
|
| 56 | def __repr__(self):
|
| 57 | attrs = sorted("%s = %r" % (k, v)
|
| 58 | for k, v in self.__dict__.iteritems()
|
| 59 | if not k.startswith("_"))
|
| 60 | return "%s(%s)" % (self.__class__.__name__, ", ".join(attrs))
|
| 61 | def __str__(self):
|
| 62 | return self.__pretty_str__()
|
| 63 | @recursion_lock("<...>")
|
| 64 | def __pretty_str__(self, nesting = 1, indentation = " "):
|
| 65 | attrs = []
|
| 66 | ind = indentation * nesting
|
| 67 | for k in self.__attrs__:
|
| 68 | v = self.__dict__[k]
|
| 69 | if not k.startswith("_"):
|
| 70 | text = [ind, k, " = "]
|
| 71 | if hasattr(v, "__pretty_str__"):
|
| 72 | text.append(v.__pretty_str__(nesting + 1, indentation))
|
| 73 | else:
|
| 74 | text.append(repr(v))
|
| 75 | attrs.append("".join(text))
|
| 76 | if not attrs:
|
| 77 | return "%s()" % (self.__class__.__name__,)
|
| 78 | attrs.insert(0, self.__class__.__name__ + ":")
|
| 79 | return "\n".join(attrs)
|
| 80 |
|
| 81 | class FlagsContainer(Container):
|
| 82 | """
|
| 83 | A container providing pretty-printing for flags. Only set flags are
|
| 84 | displayed.
|
| 85 | """
|
| 86 | def __pretty_str__(self, nesting = 1, indentation = " "):
|
| 87 | attrs = []
|
| 88 | ind = indentation * nesting
|
| 89 | for k in self.__attrs__:
|
| 90 | v = self.__dict__[k]
|
| 91 | if not k.startswith("_") and v:
|
| 92 | attrs.append(ind + k)
|
| 93 | if not attrs:
|
| 94 | return "%s()" % (self.__class__.__name__,)
|
| 95 | attrs.insert(0, self.__class__.__name__+ ":")
|
| 96 | return "\n".join(attrs)
|
| 97 |
|
| 98 | class ListContainer(list):
|
| 99 | """
|
| 100 | A container for lists
|
| 101 | """
|
| 102 | __slots__ = ["__recursion_lock__"]
|
| 103 | def __str__(self):
|
| 104 | return self.__pretty_str__()
|
| 105 | @recursion_lock("[...]")
|
| 106 | def __pretty_str__(self, nesting = 1, indentation = " "):
|
| 107 | if not self:
|
| 108 | return "[]"
|
| 109 | ind = indentation * nesting
|
| 110 | lines = ["["]
|
| 111 | for elem in self:
|
| 112 | lines.append("\n")
|
| 113 | lines.append(ind)
|
| 114 | if hasattr(elem, "__pretty_str__"):
|
| 115 | lines.append(elem.__pretty_str__(nesting + 1, indentation))
|
| 116 | else:
|
| 117 | lines.append(repr(elem))
|
| 118 | lines.append("\n")
|
| 119 | lines.append(indentation * (nesting - 1))
|
| 120 | lines.append("]")
|
| 121 | return "".join(lines)
|
| 122 |
|
| 123 | class AttrDict(object):
|
| 124 | """
|
| 125 | A dictionary that can be accessed both using indexing and attributes,
|
| 126 | i.e.,
|
| 127 | x = AttrDict()
|
| 128 | x.foo = 5
|
| 129 | print x["foo"]
|
| 130 | """
|
| 131 | __slots__ = ["__dict__"]
|
| 132 | def __init__(self, **kw):
|
| 133 | self.__dict__ = kw
|
| 134 | def __contains__(self, key):
|
| 135 | return key in self.__dict__
|
| 136 | def __nonzero__(self):
|
| 137 | return bool(self.__dict__)
|
| 138 | def __repr__(self):
|
| 139 | return repr(self.__dict__)
|
| 140 | def __str__(self):
|
| 141 | return self.__pretty_str__()
|
| 142 | def __pretty_str__(self, nesting = 1, indentation = " "):
|
| 143 | if not self:
|
| 144 | return "{}"
|
| 145 | text = ["{\n"]
|
| 146 | ind = nesting * indentation
|
| 147 | for k in sorted(self.__dict__.keys()):
|
| 148 | v = self.__dict__[k]
|
| 149 | text.append(ind)
|
| 150 | text.append(repr(k))
|
| 151 | text.append(" : ")
|
| 152 | if hasattr(v, "__pretty_str__"):
|
| 153 | try:
|
| 154 | text.append(v.__pretty_str__(nesting+1, indentation))
|
| 155 | except Exception:
|
| 156 | text.append(repr(v))
|
| 157 | else:
|
| 158 | text.append(repr(v))
|
| 159 | text.append("\n")
|
| 160 | text.append((nesting-1) * indentation)
|
| 161 | text.append("}")
|
| 162 | return "".join(text)
|
| 163 | def __delitem__(self, key):
|
| 164 | del self.__dict__[key]
|
| 165 | def __getitem__(self, key):
|
| 166 | return self.__dict__[key]
|
| 167 | def __setitem__(self, key, value):
|
| 168 | self.__dict__[key] = value
|
| 169 | def __copy__(self):
|
| 170 | new = self.__class__()
|
| 171 | new.__dict__ = self.__dict__.copy()
|
| 172 | return new
|
| 173 | def __update__(self, other):
|
| 174 | if isinstance(other, dict):
|
| 175 | self.__dict__.update(other)
|
| 176 | else:
|
| 177 | self.__dict__.update(other.__dict__)
|
| 178 |
|
| 179 | class LazyContainer(object):
|
| 180 | __slots__ = ["subcon", "stream", "pos", "context", "_value"]
|
| 181 | def __init__(self, subcon, stream, pos, context):
|
| 182 | self.subcon = subcon
|
| 183 | self.stream = stream
|
| 184 | self.pos = pos
|
| 185 | self.context = context
|
| 186 | self._value = NotImplemented
|
| 187 | def __eq__(self, other):
|
| 188 | try:
|
| 189 | return self._value == other._value
|
| 190 | except AttributeError:
|
| 191 | return False
|
| 192 | def __ne__(self, other):
|
| 193 | return not (self == other)
|
| 194 | def __str__(self):
|
| 195 | return self.__pretty_str__()
|
| 196 | def __pretty_str__(self, nesting = 1, indentation = " "):
|
| 197 | if self._value is NotImplemented:
|
| 198 | text = "<unread>"
|
| 199 | elif hasattr(self._value, "__pretty_str__"):
|
| 200 | text = self._value.__pretty_str__(nesting, indentation)
|
| 201 | else:
|
| 202 | text = repr(self._value)
|
| 203 | return "%s: %s" % (self.__class__.__name__, text)
|
| 204 | def read(self):
|
| 205 | self.stream.seek(self.pos)
|
| 206 | return self.subcon._parse(self.stream, self.context)
|
| 207 | def dispose(self):
|
| 208 | self.subcon = None
|
| 209 | self.stream = None
|
| 210 | self.context = None
|
| 211 | self.pos = None
|
| 212 | def _get_value(self):
|
| 213 | if self._value is NotImplemented:
|
| 214 | self._value = self.read()
|
| 215 | return self._value
|
| 216 | value = property(_get_value)
|
| 217 | has_value = property(lambda self: self._value is not NotImplemented)
|
| 218 |
|
| 219 |
|
| 220 |
|
| 221 |
|
| 222 |
|
| 223 |
|
| 224 |
|
| 225 |
|
| 226 |
|
| 227 |
|
| 228 |
|
| 229 |
|
| 230 |
|
| 231 |
|
| 232 |
|
| 233 |
|
| 234 |
|
| 235 |
|
| 236 |
|
| 237 |
|
| 238 |
|
| 239 |
|
| 240 |
|
| 241 |
|
| 242 |
|
| 243 |
|
| 244 |
|
| 245 |
|
| 246 |
|
| 247 |
|
| 248 |
|
| 249 |
|
| 250 |
|
| 251 |
|
| 252 |
|
| 253 |
|
| 254 |
|
| 255 |
|
| 256 |
|
| 257 |
|
| 258 |
|