OLD | NEW |
| (Empty) |
1 # Copyright 2014 The Chromium Authors. All rights reserved. | |
2 # Use of this source code is governed by a BSD-style license that can be | |
3 # found in the LICENSE file. | |
4 import collections | |
5 import operator | |
6 | |
7 from cStringIO import StringIO | |
8 | |
9 | |
10 class CalledProcessError(Exception): | |
11 """Almost like subprocess.CalledProcessError, but also captures stderr, | |
12 and gives prettier error messages. | |
13 """ | |
14 def __init__(self, returncode, cmd, stdout, stderr): | |
15 super(CalledProcessError, self).__init__() | |
16 self.returncode = returncode | |
17 self.cmd = cmd | |
18 self.stdout = stdout | |
19 self.stderr = stderr | |
20 | |
21 def __str__(self): | |
22 msg = StringIO() | |
23 | |
24 suffix = ':' if self.stderr or self.stdout else '.' | |
25 print >> msg, ( | |
26 "Command %r returned non-zero exit status %d%s" | |
27 % (self.cmd, self.returncode, suffix) | |
28 ) | |
29 | |
30 def indent_data(banner, data): | |
31 print >> msg, banner, '=' * 40 | |
32 msg.writelines(' ' + l for l in data.splitlines(True)) | |
33 | |
34 if self.stdout: | |
35 indent_data('STDOUT', self.stdout) | |
36 | |
37 if self.stderr: | |
38 if self.stdout: | |
39 print >> msg | |
40 indent_data('STDERR', self.stderr) | |
41 | |
42 r = msg.getvalue() | |
43 if r[-1] != '\n': | |
44 r += '\n' | |
45 return r | |
46 | |
47 | |
48 class cached_property(object): | |
49 """Like @property, except that the result of get is cached on | |
50 self.{'_' + fn.__name__}. | |
51 | |
52 >>> class Test(object): | |
53 ... @cached_property | |
54 ... def foo(self): | |
55 ... print "hello" | |
56 ... return 10 | |
57 ... | |
58 >>> t = Test() | |
59 >>> t.foo | |
60 hello | |
61 10 | |
62 >>> t.foo | |
63 10 | |
64 >>> t.foo = 20 | |
65 >>> t.foo | |
66 20 | |
67 >>> del t.foo | |
68 >>> t.foo | |
69 hello | |
70 10 | |
71 >>> | |
72 """ | |
73 def __init__(self, fn): | |
74 self.func = fn | |
75 self._iname = "_" + fn.__name__ | |
76 self.__name__ = fn.__name__ | |
77 self.__doc__ = fn.__doc__ | |
78 self.__module__ = fn.__module__ | |
79 | |
80 def __get__(self, inst, cls=None): | |
81 if inst is None: | |
82 return self | |
83 if not hasattr(inst, self._iname): | |
84 val = self.func(inst) | |
85 # Some methods call out to another layer to calculate the value. This | |
86 # higher layer will assign directly to the property, so we have to do | |
87 # the extra hasattr here to determine if the value has been set as a side | |
88 # effect of func() | |
89 if not hasattr(inst, self._iname): | |
90 setattr(inst, self._iname, val) | |
91 return getattr(inst, self._iname) | |
92 | |
93 def __delete__(self, inst): | |
94 assert inst is not None | |
95 if hasattr(inst, self._iname): | |
96 delattr(inst, self._iname) | |
97 | |
98 | |
99 def freeze(obj): | |
100 """Takes a jsonish object |obj|, and returns an immutable version of it.""" | |
101 if isinstance(obj, dict): | |
102 return FrozenDict((freeze(k), freeze(v)) for k, v in obj.iteritems()) | |
103 elif isinstance(obj, list): | |
104 return tuple(freeze(i) for i in obj) | |
105 elif isinstance(obj, set): | |
106 return frozenset(freeze(i) for i in obj) | |
107 else: | |
108 hash(obj) | |
109 return obj | |
110 | |
111 | |
112 def thaw(obj): | |
113 """Takes an object from freeze() and returns a mutable copy of it.""" | |
114 if isinstance(obj, FrozenDict): | |
115 return collections.OrderedDict( | |
116 (thaw(k), thaw(v)) for k, v in obj.iteritems()) | |
117 elif isinstance(obj, tuple): | |
118 return list(thaw(i) for i in obj) | |
119 elif isinstance(obj, frozenset): | |
120 return set(thaw(i) for i in obj) | |
121 else: | |
122 return obj | |
123 | |
124 | |
125 class FrozenDict(collections.Mapping): | |
126 """An immutable OrderedDict. | |
127 | |
128 Modified From: http://stackoverflow.com/a/2704866 | |
129 """ | |
130 def __init__(self, *args, **kwargs): | |
131 self._d = collections.OrderedDict(*args, **kwargs) | |
132 self._hash = reduce(operator.xor, | |
133 (hash(i) for i in enumerate(self._d.iteritems())), 0) | |
134 | |
135 def __eq__(self, other): | |
136 if not isinstance(other, collections.Mapping): | |
137 return NotImplemented | |
138 if self is other: | |
139 return True | |
140 if len(self) != len(other): | |
141 return False | |
142 for k, v in self.iteritems(): | |
143 if k not in other or other[k] != v: | |
144 return False | |
145 return True | |
146 | |
147 def __iter__(self): | |
148 return iter(self._d) | |
149 | |
150 def __len__(self): | |
151 return len(self._d) | |
152 | |
153 def __getitem__(self, key): | |
154 return self._d[key] | |
155 | |
156 def __hash__(self): | |
157 return self._hash | |
158 | |
159 def __repr__(self): | |
160 return 'FrozenDict(%r)' % (self._d.items(),) | |
OLD | NEW |