Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(181)

Side by Side Diff: recipe_engine/util.py

Issue 2265673002: Add LogDog / annotation protobuf support. (Closed) Base URL: https://github.com/luci/recipes-py@step-formal-struct
Patch Set: Updated with comments, added test, proto 3.0.2. Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 # Copyright 2013 The LUCI Authors. All rights reserved. 1 # Copyright 2013 The LUCI Authors. All rights reserved.
2 # Use of this source code is governed under the Apache License, Version 2.0 2 # Use of this source code is governed under the Apache License, Version 2.0
3 # that can be found in the LICENSE file. 3 # that can be found in the LICENSE file.
4 4
5 import contextlib 5 import contextlib
6 import functools 6 import functools
7 import os 7 import os
8 import sys 8 import sys
9 import traceback 9 import traceback
10 import urllib 10 import urllib
(...skipping 172 matching lines...) Expand 10 before | Expand all | Expand 10 after
183 self.lines[-1].write(s) 183 self.lines[-1].write(s)
184 break 184 break
185 self.lines[-1].write(s[:i]) 185 self.lines[-1].write(s[:i])
186 self.lines[-1] = self.lines[-1].getvalue() 186 self.lines[-1] = self.lines[-1].getvalue()
187 self.lines.append(StringIO()) 187 self.lines.append(StringIO())
188 s = s[i+1:] 188 s = s[i+1:]
189 189
190 def close(self): 190 def close(self):
191 if not isinstance(self.lines[-1], basestring): 191 if not isinstance(self.lines[-1], basestring):
192 self.lines[-1] = self.lines[-1].getvalue() 192 self.lines[-1] = self.lines[-1].getvalue()
193
194
195 class MultiException(Exception):
196 """An exception that aggregates multiple exceptions and summarizes them."""
197
198 def __init__(self):
199 self._inner = []
200
201 def __nonzero__(self):
202 return bool(self._inner)
203
204 def __len__(self):
205 return len(self._inner)
206
207 def __getitem__(self, key):
208 return self._inner[key]
209
210 def __iter__(self):
211 return iter(self._inner)
212
213 def __str__(self):
214 if len(self._inner) == 0:
215 text = 'No exceptions'
216 elif len(self._inner) == 1:
217 text = str(self._inner[0])
218 else:
219 text = str(self._inner[0]) + ', and %d more...' % (len(self._inner)-1)
220 return '%s(%s)' % (type(self).__name__, text)
221
222 def append(self, exc):
223 assert isinstance(exc, BaseException)
224 self._inner.append(exc)
225
226 def raise_if_any(self):
227 if self._inner:
228 raise self
229
230 @contextlib.contextmanager
231 def catch(self, *exc_types):
232 """ContextManager that catches any exception raised during its execution
233 and adds them to the MultiException.
234
235 Args:
236 exc_types (list): A list of exception classes to catch. If empty,
237 Exception will be used.
238 """
239 exc_types = exc_types or (Exception,)
240 try:
241 yield
242 except exc_types as e:
243 self.append(e)
244
245
246 @contextlib.contextmanager
247 def defer_exceptions_for(it, fn, *exc_types):
248 """Executes "fn" for each element in "it". Any exceptions thrown by "fn" will
249 be deferred until the end of "it", then raised as a single MultiException.
250
251 Args:
252 it (iterable): An iterable to traverse.
253 fn (callable): A function to call for each element in "it".
254 exc_types (list): An optional list of specific exception types to handle.
255 If empty, Exception will be used.
256 """
257 mexc = MultiException()
258 for e in it:
259 with mexc.catch(*exc_types):
260 fn(e)
261 mexc.raise_if_any()
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698