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

Side by Side Diff: third_party/twisted_8_1/twisted/python/failure.py

Issue 12261012: Remove third_party/twisted_8_1 (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/build
Patch Set: Created 7 years, 10 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 | Annotate | Revision Log
OLDNEW
(Empty)
1 # -*- test-case-name: twisted.test.test_failure -*-
2 # See also test suite twisted.test.test_pbfailure
3
4 # Copyright (c) 2001-2008 Twisted Matrix Laboratories.
5 # See LICENSE for details.
6
7
8 """
9 Asynchronous-friendly error mechanism.
10
11 See L{Failure}.
12 """
13
14 # System Imports
15 import sys
16 import linecache
17 import inspect
18 import opcode
19 from cStringIO import StringIO
20
21 from twisted.python import reflect
22
23 count = 0
24 traceupLength = 4
25
26 class DefaultException(Exception):
27 pass
28
29 def format_frames(frames, write, detail="default"):
30 """Format and write frames.
31
32 @param frames: is a list of frames as used by Failure.frames, with
33 each frame being a list of
34 (funcName, fileName, lineNumber, locals.items(), globals.items())
35 @type frames: list
36 @param write: this will be called with formatted strings.
37 @type write: callable
38 @param detail: Three detail levels are available:
39 default, brief, and verbose.
40 @type detail: string
41 """
42 if detail not in ('default', 'brief', 'verbose'):
43 raise ValueError, "Detail must be default, brief, or verbose. (not %r)" % (detail,)
44 w = write
45 if detail == "brief":
46 for method, filename, lineno, localVars, globalVars in frames:
47 w('%s:%s:%s\n' % (filename, lineno, method))
48 elif detail == "default":
49 for method, filename, lineno, localVars, globalVars in frames:
50 w( ' File "%s", line %s, in %s\n' % (filename, lineno, method))
51 w( ' %s\n' % linecache.getline(filename, lineno).strip())
52 elif detail == "verbose":
53 for method, filename, lineno, localVars, globalVars in frames:
54 w("%s:%d: %s(...)\n" % (filename, lineno, method))
55 w(' [ Locals ]\n')
56 # Note: the repr(val) was (self.pickled and val) or repr(val)))
57 for name, val in localVars:
58 w(" %s : %s\n" % (name, repr(val)))
59 w(' ( Globals )\n')
60 for name, val in globalVars:
61 w(" %s : %s\n" % (name, repr(val)))
62
63 # slyphon: i have a need to check for this value in trial
64 # so I made it a module-level constant
65 EXCEPTION_CAUGHT_HERE = "--- <exception caught here> ---"
66
67
68
69 class NoCurrentExceptionError(Exception):
70 """
71 Raised when trying to create a Failure from the current interpreter
72 exception state and there is no current exception state.
73 """
74
75
76 class _Traceback(object):
77 """
78 Fake traceback object which can be passed to functions in the standard
79 library L{traceback} module.
80 """
81
82 def __init__(self, frames):
83 """
84 Construct a fake traceback object using a list of frames. Note that
85 although frames generally include locals and globals, this information
86 is not kept by this object, since locals and globals are not used in
87 standard tracebacks.
88
89 @param frames: [(methodname, filename, lineno, locals, globals), ...]
90 """
91 assert len(frames) > 0, "Must pass some frames"
92 head, frames = frames[0], frames[1:]
93 name, filename, lineno, localz, globalz = head
94 self.tb_frame = _Frame(name, filename)
95 self.tb_lineno = lineno
96 if len(frames) == 0:
97 self.tb_next = None
98 else:
99 self.tb_next = _Traceback(frames)
100
101
102 class _Frame(object):
103 """
104 A fake frame object, used by L{_Traceback}.
105 """
106
107 def __init__(self, name, filename):
108 self.f_code = _Code(name, filename)
109 self.f_globals = {}
110
111
112 class _Code(object):
113 """
114 A fake code object, used by L{_Traceback} via L{_Frame}.
115 """
116 def __init__(self, name, filename):
117 self.co_name = name
118 self.co_filename = filename
119
120
121 class Failure:
122 """A basic abstraction for an error that has occurred.
123
124 This is necessary because Python's built-in error mechanisms are
125 inconvenient for asynchronous communication.
126
127 @ivar value: The exception instance responsible for this failure.
128 @ivar type: The exception's class.
129 """
130
131 pickled = 0
132 stack = None
133
134 # The opcode of "yield" in Python bytecode. We need this in _findFailure in
135 # order to identify whether an exception was thrown by a
136 # throwExceptionIntoGenerator.
137 _yieldOpcode = chr(opcode.opmap["YIELD_VALUE"])
138
139 def __init__(self, exc_value=None, exc_type=None, exc_tb=None):
140 """Initialize me with an explanation of the error.
141
142 By default, this will use the current X{exception}
143 (L{sys.exc_info}()). However, if you want to specify a
144 particular kind of failure, you can pass an exception as an
145 argument.
146
147 If no C{exc_value} is passed, then an "original" Failure will
148 be searched for. If the current exception handler that this
149 Failure is being constructed in is handling an exception
150 raised by L{raiseException}, then this Failure will act like
151 the original Failure.
152 """
153 global count
154 count = count + 1
155 self.count = count
156 self.type = self.value = tb = None
157
158 #strings Exceptions/Failures are bad, mmkay?
159 if isinstance(exc_value, (str, unicode)) and exc_type is None:
160 import warnings
161 warnings.warn(
162 "Don't pass strings (like %r) to failure.Failure (replacing with a DefaultException)." %
163 exc_value, DeprecationWarning, stacklevel=2)
164 exc_value = DefaultException(exc_value)
165
166 stackOffset = 0
167
168 if exc_value is None:
169 exc_value = self._findFailure()
170
171 if exc_value is None:
172 self.type, self.value, tb = sys.exc_info()
173 if self.type is None:
174 raise NoCurrentExceptionError()
175 stackOffset = 1
176 elif exc_type is None:
177 if isinstance(exc_value, Exception):
178 self.type = exc_value.__class__
179 else: #allow arbitrary objects.
180 self.type = type(exc_value)
181 self.value = exc_value
182 else:
183 self.type = exc_type
184 self.value = exc_value
185 if isinstance(self.value, Failure):
186 self.__dict__ = self.value.__dict__
187 return
188 if tb is None:
189 if exc_tb:
190 tb = exc_tb
191 # else:
192 # log.msg("Erf, %r created with no traceback, %s %s." % (
193 # repr(self), repr(exc_value), repr(exc_type)))
194 # for s in traceback.format_stack():
195 # log.msg(s)
196
197 frames = self.frames = []
198 stack = self.stack = []
199
200 # added 2003-06-23 by Chris Armstrong. Yes, I actually have a
201 # use case where I need this traceback object, and I've made
202 # sure that it'll be cleaned up.
203 self.tb = tb
204
205 if tb:
206 f = tb.tb_frame
207 elif not isinstance(self.value, Failure):
208 # we don't do frame introspection since it's expensive,
209 # and if we were passed a plain exception with no
210 # traceback, it's not useful anyway
211 f = stackOffset = None
212
213 while stackOffset and f:
214 # This excludes this Failure.__init__ frame from the
215 # stack, leaving it to start with our caller instead.
216 f = f.f_back
217 stackOffset -= 1
218
219 # Keeps the *full* stack. Formerly in spread.pb.print_excFullStack:
220 #
221 # The need for this function arises from the fact that several
222 # PB classes have the peculiar habit of discarding exceptions
223 # with bareword "except:"s. This premature exception
224 # catching means tracebacks generated here don't tend to show
225 # what called upon the PB object.
226
227 while f:
228 localz = f.f_locals.copy()
229 if f.f_locals is f.f_globals:
230 globalz = {}
231 else:
232 globalz = f.f_globals.copy()
233 for d in globalz, localz:
234 if d.has_key("__builtins__"):
235 del d["__builtins__"]
236 stack.insert(0, [
237 f.f_code.co_name,
238 f.f_code.co_filename,
239 f.f_lineno,
240 localz.items(),
241 globalz.items(),
242 ])
243 f = f.f_back
244
245 while tb is not None:
246 f = tb.tb_frame
247 localz = f.f_locals.copy()
248 if f.f_locals is f.f_globals:
249 globalz = {}
250 else:
251 globalz = f.f_globals.copy()
252 for d in globalz, localz:
253 if d.has_key("__builtins__"):
254 del d["__builtins__"]
255
256 frames.append([
257 f.f_code.co_name,
258 f.f_code.co_filename,
259 tb.tb_lineno,
260 localz.items(),
261 globalz.items(),
262 ])
263 tb = tb.tb_next
264 if inspect.isclass(self.type) and issubclass(self.type, Exception):
265 parentCs = reflect.allYourBase(self.type)
266 self.parents = map(reflect.qual, parentCs)
267 self.parents.append(reflect.qual(self.type))
268 else:
269 self.parents = [self.type]
270
271 def trap(self, *errorTypes):
272 """Trap this failure if its type is in a predetermined list.
273
274 This allows you to trap a Failure in an error callback. It will be
275 automatically re-raised if it is not a type that you expect.
276
277 The reason for having this particular API is because it's very useful
278 in Deferred errback chains:
279
280 | def _ebFoo(self, failure):
281 | r = failure.trap(Spam, Eggs)
282 | print 'The Failure is due to either Spam or Eggs!'
283 | if r == Spam:
284 | print 'Spam did it!'
285 | elif r == Eggs:
286 | print 'Eggs did it!'
287
288 If the failure is not a Spam or an Eggs, then the Failure
289 will be 'passed on' to the next errback.
290
291 @type errorTypes: L{Exception}
292 """
293 error = self.check(*errorTypes)
294 if not error:
295 raise self
296 return error
297
298 def check(self, *errorTypes):
299 """Check if this failure's type is in a predetermined list.
300
301 @type errorTypes: list of L{Exception} classes or
302 fully-qualified class names.
303 @returns: the matching L{Exception} type, or None if no match.
304 """
305 for error in errorTypes:
306 err = error
307 if inspect.isclass(error) and issubclass(error, Exception):
308 err = reflect.qual(error)
309 if err in self.parents:
310 return error
311 return None
312
313
314 def raiseException(self):
315 """
316 raise the original exception, preserving traceback
317 information if available.
318 """
319 raise self.type, self.value, self.tb
320
321
322 def throwExceptionIntoGenerator(self, g):
323 """
324 Throw the original exception into the given generator,
325 preserving traceback information if available.
326
327 @return: The next value yielded from the generator.
328 @raise StopIteration: If there are no more values in the generator.
329 @raise anything else: Anything that the generator raises.
330 """
331 return g.throw(self.type, self.value, self.tb)
332
333
334 def _findFailure(cls):
335 """
336 Find the failure that represents the exception currently in context.
337 """
338 tb = sys.exc_info()[-1]
339 if not tb:
340 return
341
342 secondLastTb = None
343 lastTb = tb
344 while lastTb.tb_next:
345 secondLastTb = lastTb
346 lastTb = lastTb.tb_next
347
348 lastFrame = lastTb.tb_frame
349
350 # NOTE: f_locals.get('self') is used rather than
351 # f_locals['self'] because psyco frames do not contain
352 # anything in their locals() dicts. psyco makes debugging
353 # difficult anyhow, so losing the Failure objects (and thus
354 # the tracebacks) here when it is used is not that big a deal.
355
356 # handle raiseException-originated exceptions
357 if lastFrame.f_code is cls.raiseException.func_code:
358 return lastFrame.f_locals.get('self')
359
360 # handle throwExceptionIntoGenerator-originated exceptions
361 # this is tricky, and differs if the exception was caught
362 # inside the generator, or above it:
363
364 # it is only really originating from
365 # throwExceptionIntoGenerator if the bottom of the traceback
366 # is a yield.
367 # Pyrex and Cython extensions create traceback frames
368 # with no co_code, but they can't yield so we know it's okay to just ret urn here.
369 if ((not lastFrame.f_code.co_code) or
370 lastFrame.f_code.co_code[lastTb.tb_lasti] != cls._yieldOpcode):
371 return
372
373 # if the exception was caught above the generator.throw
374 # (outside the generator), it will appear in the tb (as the
375 # second last item):
376 if secondLastTb:
377 frame = secondLastTb.tb_frame
378 if frame.f_code is cls.throwExceptionIntoGenerator.func_code:
379 return frame.f_locals.get('self')
380
381 # if the exception was caught below the generator.throw
382 # (inside the generator), it will appear in the frames' linked
383 # list, above the top-level traceback item (which must be the
384 # generator frame itself, thus its caller is
385 # throwExceptionIntoGenerator).
386 frame = tb.tb_frame.f_back
387 if frame and frame.f_code is cls.throwExceptionIntoGenerator.func_code:
388 return frame.f_locals.get('self')
389
390 _findFailure = classmethod(_findFailure)
391
392 def __repr__(self):
393 return "<%s %s>" % (self.__class__, self.type)
394
395 def __str__(self):
396 return "[Failure instance: %s]" % self.getBriefTraceback()
397
398 def __getstate__(self):
399 """Avoid pickling objects in the traceback.
400 """
401 if self.pickled:
402 return self.__dict__
403 c = self.__dict__.copy()
404
405 c['frames'] = [
406 [
407 v[0], v[1], v[2],
408 [(j[0], reflect.safe_repr(j[1])) for j in v[3]],
409 [(j[0], reflect.safe_repr(j[1])) for j in v[4]]
410 ] for v in self.frames
411 ]
412
413 # added 2003-06-23. See comment above in __init__
414 c['tb'] = None
415
416 if self.stack is not None:
417 # XXX: This is a band-aid. I can't figure out where these
418 # (failure.stack is None) instances are coming from.
419 c['stack'] = [
420 [
421 v[0], v[1], v[2],
422 [(j[0], reflect.safe_repr(j[1])) for j in v[3]],
423 [(j[0], reflect.safe_repr(j[1])) for j in v[4]]
424 ] for v in self.stack
425 ]
426
427 c['pickled'] = 1
428 return c
429
430 def cleanFailure(self):
431 """Remove references to other objects, replacing them with strings.
432 """
433 self.__dict__ = self.__getstate__()
434
435 def getTracebackObject(self):
436 """
437 Get an object that represents this Failure's stack that can be passed
438 to traceback.extract_tb.
439
440 If the original traceback object is still present, return that. If this
441 traceback object has been lost but we still have the information,
442 return a fake traceback object (see L{_Traceback}). If there is no
443 traceback information at all, return None.
444 """
445 if self.tb is not None:
446 return self.tb
447 elif len(self.frames) > 0:
448 return _Traceback(self.frames)
449 else:
450 return None
451
452 def getErrorMessage(self):
453 """Get a string of the exception which caused this Failure."""
454 if isinstance(self.value, Failure):
455 return self.value.getErrorMessage()
456 return reflect.safe_str(self.value)
457
458 def getBriefTraceback(self):
459 io = StringIO()
460 self.printBriefTraceback(file=io)
461 return io.getvalue()
462
463 def getTraceback(self, elideFrameworkCode=0, detail='default'):
464 io = StringIO()
465 self.printTraceback(file=io, elideFrameworkCode=elideFrameworkCode, deta il=detail)
466 return io.getvalue()
467
468 def printTraceback(self, file=None, elideFrameworkCode=0, detail='default'):
469 """Emulate Python's standard error reporting mechanism.
470 """
471 if file is None:
472 file = log.logerr
473 w = file.write
474
475 # Preamble
476 if detail == 'verbose':
477 w( '*--- Failure #%d%s---\n' %
478 (self.count,
479 (self.pickled and ' (pickled) ') or ' '))
480 elif detail == 'brief':
481 if self.frames:
482 hasFrames = 'Traceback'
483 else:
484 hasFrames = 'Traceback (failure with no frames)'
485 w("%s: %s: %s\n" % (hasFrames, self.type, self.value))
486 else:
487 w( 'Traceback (most recent call last):\n')
488
489 # Frames, formatted in appropriate style
490 if self.frames:
491 if not elideFrameworkCode:
492 format_frames(self.stack[-traceupLength:], w, detail)
493 w("%s\n" % (EXCEPTION_CAUGHT_HERE,))
494 format_frames(self.frames, w, detail)
495 elif not detail == 'brief':
496 # Yeah, it's not really a traceback, despite looking like one...
497 w("Failure: ")
498
499 # postamble, if any
500 if not detail == 'brief':
501 # Unfortunately, self.type will not be a class object if this
502 # Failure was created implicitly from a string exception.
503 # qual() doesn't make any sense on a string, so check for this
504 # case here and just write out the string if that's what we
505 # have.
506 if isinstance(self.type, (str, unicode)):
507 w(self.type + "\n")
508 else:
509 w("%s: %s\n" % (reflect.qual(self.type),
510 reflect.safe_str(self.value)))
511 # chaining
512 if isinstance(self.value, Failure):
513 # TODO: indentation for chained failures?
514 file.write(" (chained Failure)\n")
515 self.value.printTraceback(file, elideFrameworkCode, detail)
516 if detail == 'verbose':
517 w('*--- End of Failure #%d ---\n' % self.count)
518
519 def printBriefTraceback(self, file=None, elideFrameworkCode=0):
520 """Print a traceback as densely as possible.
521 """
522 self.printTraceback(file, elideFrameworkCode, detail='brief')
523
524 def printDetailedTraceback(self, file=None, elideFrameworkCode=0):
525 """Print a traceback with detailed locals and globals information.
526 """
527 self.printTraceback(file, elideFrameworkCode, detail='verbose')
528
529 # slyphon: make post-morteming exceptions tweakable
530
531 DO_POST_MORTEM = True
532
533 def _debuginit(self, exc_value=None, exc_type=None, exc_tb=None,
534 Failure__init__=Failure.__init__.im_func):
535 if (exc_value, exc_type, exc_tb) == (None, None, None):
536 exc = sys.exc_info()
537 if not exc[0] == self.__class__ and DO_POST_MORTEM:
538 print "Jumping into debugger for post-mortem of exception '%s':" % e xc[1]
539 import pdb
540 pdb.post_mortem(exc[2])
541 Failure__init__(self, exc_value, exc_type, exc_tb)
542
543 def startDebugMode():
544 """Enable debug hooks for Failures."""
545 Failure.__init__ = _debuginit
546
547
548 # Sibling imports - at the bottom and unqualified to avoid unresolvable
549 # circularity
550 import log
OLDNEW
« no previous file with comments | « third_party/twisted_8_1/twisted/python/dxprofile.py ('k') | third_party/twisted_8_1/twisted/python/filepath.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698