blob: eb4b738f3a27f23854a399f89e40f7629ad4660d [file] [log] [blame]
Eli Benderskye0735d52011-09-08 20:12:44 +03001def 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
15class 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
Eli Benderskyddeedc42011-11-18 05:55:06 +020040 def __contains__(self, name):
41 return name in self.__dict__
Eli Benderskye0735d52011-09-08 20:12:44 +030042 def __getitem__(self, name):
43 return self.__dict__[name]
44 def __delitem__(self, name):
45 self.__delattr__(name)
46 def __setitem__(self, name, value):
47 self.__setattr__(name, value)
48 def __update__(self, obj):
49 for name in obj.__attrs__:
50 self[name] = obj[name]
51 def __copy__(self):
52 new = self.__class__()
53 new.__attrs__ = self.__attrs__[:]
54 new.__dict__ = self.__dict__.copy()
55 return new
56
57 @recursion_lock("<...>")
58 def __repr__(self):
59 attrs = sorted("%s = %r" % (k, v)
60 for k, v in self.__dict__.iteritems()
61 if not k.startswith("_"))
62 return "%s(%s)" % (self.__class__.__name__, ", ".join(attrs))
63 def __str__(self):
64 return self.__pretty_str__()
65 @recursion_lock("<...>")
66 def __pretty_str__(self, nesting = 1, indentation = " "):
67 attrs = []
68 ind = indentation * nesting
69 for k in self.__attrs__:
70 v = self.__dict__[k]
71 if not k.startswith("_"):
72 text = [ind, k, " = "]
73 if hasattr(v, "__pretty_str__"):
74 text.append(v.__pretty_str__(nesting + 1, indentation))
75 else:
Eli Bendersky74562122012-01-07 20:44:43 +020076 text.append(str(v))
Eli Benderskye0735d52011-09-08 20:12:44 +030077 attrs.append("".join(text))
78 if not attrs:
79 return "%s()" % (self.__class__.__name__,)
80 attrs.insert(0, self.__class__.__name__ + ":")
81 return "\n".join(attrs)
82
83class FlagsContainer(Container):
84 """
85 A container providing pretty-printing for flags. Only set flags are
86 displayed.
87 """
88 def __pretty_str__(self, nesting = 1, indentation = " "):
89 attrs = []
90 ind = indentation * nesting
91 for k in self.__attrs__:
92 v = self.__dict__[k]
93 if not k.startswith("_") and v:
94 attrs.append(ind + k)
95 if not attrs:
96 return "%s()" % (self.__class__.__name__,)
97 attrs.insert(0, self.__class__.__name__+ ":")
98 return "\n".join(attrs)
99
100class ListContainer(list):
101 """
102 A container for lists
103 """
104 __slots__ = ["__recursion_lock__"]
105 def __str__(self):
106 return self.__pretty_str__()
107 @recursion_lock("[...]")
108 def __pretty_str__(self, nesting = 1, indentation = " "):
109 if not self:
110 return "[]"
111 ind = indentation * nesting
112 lines = ["["]
113 for elem in self:
114 lines.append("\n")
115 lines.append(ind)
116 if hasattr(elem, "__pretty_str__"):
117 lines.append(elem.__pretty_str__(nesting + 1, indentation))
118 else:
119 lines.append(repr(elem))
120 lines.append("\n")
121 lines.append(indentation * (nesting - 1))
122 lines.append("]")
123 return "".join(lines)
124
125class AttrDict(object):
126 """
127 A dictionary that can be accessed both using indexing and attributes,
128 i.e.,
129 x = AttrDict()
130 x.foo = 5
131 print x["foo"]
132 """
133 __slots__ = ["__dict__"]
134 def __init__(self, **kw):
135 self.__dict__ = kw
136 def __contains__(self, key):
137 return key in self.__dict__
138 def __nonzero__(self):
139 return bool(self.__dict__)
140 def __repr__(self):
141 return repr(self.__dict__)
142 def __str__(self):
143 return self.__pretty_str__()
144 def __pretty_str__(self, nesting = 1, indentation = " "):
145 if not self:
146 return "{}"
147 text = ["{\n"]
148 ind = nesting * indentation
149 for k in sorted(self.__dict__.keys()):
150 v = self.__dict__[k]
151 text.append(ind)
152 text.append(repr(k))
153 text.append(" : ")
154 if hasattr(v, "__pretty_str__"):
155 try:
156 text.append(v.__pretty_str__(nesting+1, indentation))
157 except Exception:
158 text.append(repr(v))
159 else:
160 text.append(repr(v))
161 text.append("\n")
162 text.append((nesting-1) * indentation)
163 text.append("}")
164 return "".join(text)
165 def __delitem__(self, key):
166 del self.__dict__[key]
167 def __getitem__(self, key):
168 return self.__dict__[key]
169 def __setitem__(self, key, value):
170 self.__dict__[key] = value
171 def __copy__(self):
172 new = self.__class__()
173 new.__dict__ = self.__dict__.copy()
174 return new
175 def __update__(self, other):
176 if isinstance(other, dict):
177 self.__dict__.update(other)
178 else:
179 self.__dict__.update(other.__dict__)
180
181class LazyContainer(object):
182 __slots__ = ["subcon", "stream", "pos", "context", "_value"]
183 def __init__(self, subcon, stream, pos, context):
184 self.subcon = subcon
185 self.stream = stream
186 self.pos = pos
187 self.context = context
188 self._value = NotImplemented
189 def __eq__(self, other):
190 try:
191 return self._value == other._value
192 except AttributeError:
193 return False
194 def __ne__(self, other):
195 return not (self == other)
196 def __str__(self):
197 return self.__pretty_str__()
198 def __pretty_str__(self, nesting = 1, indentation = " "):
199 if self._value is NotImplemented:
200 text = "<unread>"
201 elif hasattr(self._value, "__pretty_str__"):
202 text = self._value.__pretty_str__(nesting, indentation)
203 else:
204 text = repr(self._value)
205 return "%s: %s" % (self.__class__.__name__, text)
206 def read(self):
207 self.stream.seek(self.pos)
208 return self.subcon._parse(self.stream, self.context)
209 def dispose(self):
210 self.subcon = None
211 self.stream = None
212 self.context = None
213 self.pos = None
214 def _get_value(self):
215 if self._value is NotImplemented:
216 self._value = self.read()
217 return self._value
218 value = property(_get_value)
219 has_value = property(lambda self: self._value is not NotImplemented)
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
259
260