def _pull(self): """ A generator that calls C{resumeProducing} on the underlying producer forever. If C{resumeProducing} throws an exception, the producer is unregistered, which should result in streaming stopping. """ while True: try: self._producer.resumeProducing() except: log.err(None, "%s failed, producing will be stopped:" % (safe_str(self._producer),)) try: self._consumer.unregisterProducer() # The consumer should now call stopStreaming() on us, # thus stopping the streaming. except: # Since the consumer blew up, we may not have had # stopStreaming() called, so we just stop on our own: log.err(None, "%s failed to unregister producer:" % (safe_str(self._consumer),)) self._finished = True return yield None
def test_workingUtf8_2(self): """ L{safe_str} for C{str} with utf-8 encoded data should return the value unchanged. """ x = b't\xc3\xbcst' self.assertEqual(reflect.safe_str(x), x)
def test_workingUtf8_3(self): """ L{safe_str} for C{bytes} with utf-8 encoded data should return the value decoded into C{str}. """ x = b't\xc3\xbcst' self.assertEqual(reflect.safe_str(x), x.decode('utf-8'))
def test_brokenUtf8(self): """ Use str() for non-utf8 bytes: "b'non-utf8'" """ x = b'\xff' xStr = reflect.safe_str(x) self.assertEqual(xStr, str(x))
def test_workingAscii(self): """ L{safe_str} for C{str} with ascii-only data should return the value unchanged. """ x = 'a' self.assertEqual(reflect.safe_str(x), 'a')
def getErrorMessage(self): """ Get a string of the exception which caused this Failure. """ if isinstance(self.value, Failure): return self.value.getErrorMessage() return reflect.safe_str(self.value)
def error_page(request, resrc, value, tb=None): result = "Request: %s<br />\nResource: %s<br />\nValue: %s" % ( html.PRE(reflect.safe_repr(request)), html.PRE(reflect.safe_repr(resrc)), html.PRE(reflect.safe_repr(value)), ) if tb: result += '\n%s' % html.PRE(reflect.safe_str(tb)) return result
def write_error(failure): if failure.check(APIError): status = failure.value.status # Don't log the stack traces for 4xx responses. if status < 400 or status >= 500: log.err(failure) else: log.msg("status: %s message: %s" % ( status, safe_str(failure.value))) bytes = failure.value.response if bytes is None: bytes = self.dump_error(failure.value, request) else: log.err(failure) bytes = safe_str(failure.value) status = 500 request.setResponseCode(status) request.write(bytes) request.finish()
def augmentWithFailure(eventDict, failure, why=None): """ Augment a log event with exception information. """ eventDict['excText'] = failure.getTraceback() eventDict['excType'] = reflect.qual(failure.type) eventDict['excValue'] = reflect.safe_str(failure.value) eventDict.setdefault('logLevel', 'ERROR') eventDict['message'] = (why or eventDict['excValue'] or eventDict['excType'])
def test_brokenClassAttribute(self): """ If an object raises an exception when accessing its C{__class__} attribute, L{reflect.safe_str} uses C{type} to retrieve the class object. """ b = NoClassAttr() b.breakStr = True bStr = reflect.safe_str(b) self.assertIn("NoClassAttr instance at 0x", bStr) self.assertIn(os.path.splitext(__file__)[0], bStr) self.assertIn("RuntimeError: str!", bStr)
def test_brokenClassNameAttribute(self): """ If a class raises an exception when accessing its C{__name__} attribute B{and} when calling its C{__str__} implementation, L{reflect.safe_str} returns 'BROKEN CLASS' instead of the class name. """ class X(BTBase): breakName = True xStr = reflect.safe_str(X()) self.assertIn("<BROKEN CLASS AT 0x", xStr) self.assertIn(os.path.splitext(__file__)[0], xStr) self.assertIn("RuntimeError: str!", xStr)
def assertDefaultTraceback(self, captureVars=False): """ Assert that L{printTraceback} produces and prints a default traceback. The default traceback consists of a header:: Traceback (most recent call last): The body with traceback:: File "/twisted/trial/_synctest.py", line 1180, in _run runWithWarningsSuppressed(suppress, method) And the footer:: --- <exception caught here> --- File "twisted/test/test_failure.py", line 39, in getDivisionFailure 1 / 0 exceptions.ZeroDivisionError: float division @param captureVars: Enables L{Failure.captureVars}. @type captureVars: C{bool} """ if captureVars: exampleLocalVar = "xyzzy" # Silence the linter as this variable is checked via # the traceback. exampleLocalVar f = getDivisionFailure(captureVars=captureVars) out = StringIO() f.printTraceback(out) tb = out.getvalue() stack = "" for method, filename, lineno, localVars, globalVars in f.frames: stack += f' File "{filename}", line {lineno}, in {method}\n' stack += f" {linecache.getline(filename, lineno).strip()}\n" self.assertTracebackFormat( tb, "Traceback (most recent call last):", "%s\n%s%s: %s\n" % ( failure.EXCEPTION_CAUGHT_HERE, stack, reflect.qual(f.type), reflect.safe_str(f.value), ), ) if captureVars: self.assertIsNone(re.search("exampleLocalVar.*xyzzy", tb))
def printTraceback(self, file=None, elideFrameworkCode=0, detail='default'): """Emulate Python's standard error reporting mechanism. """ if file is None: file = log.logerr w = file.write # Preamble if detail == 'verbose': w( '*--- Failure #%d%s---\n' % (self.count, (self.pickled and ' (pickled) ') or ' ')) elif detail == 'brief': if self.frames: hasFrames = 'Traceback' else: hasFrames = 'Traceback (failure with no frames)' w("%s: %s: %s\n" % (hasFrames, self.type, self.value)) else: w( 'Traceback (most recent call last):\n') # Frames, formatted in appropriate style if self.frames: if not elideFrameworkCode: format_frames(self.stack[-traceupLength:], w, detail) w("%s\n" % (EXCEPTION_CAUGHT_HERE,)) format_frames(self.frames, w, detail) elif not detail == 'brief': # Yeah, it's not really a traceback, despite looking like one... w("Failure: ") # postamble, if any if not detail == 'brief': # Unfortunately, self.type will not be a class object if this # Failure was created implicitly from a string exception. # qual() doesn't make any sense on a string, so check for this # case here and just write out the string if that's what we # have. if isinstance(self.type, (str, unicode)): w(self.type + "\n") else: w("%s: %s\n" % (reflect.qual(self.type), reflect.safe_str(self.value))) # chaining if isinstance(self.value, Failure): # TODO: indentation for chained failures? file.write(" (chained Failure)\n") self.value.printTraceback(file, elideFrameworkCode, detail) if detail == 'verbose': w('*--- End of Failure #%d ---\n' % self.count)
def emit(self, record): """ Emit a record. """ try: eventDict = { 'category': self.category, 'logLevel': record.levelname, 'logName': record.name, 'filename': record.pathname, 'lineno': record.lineno, 'funcName': record.funcName, 'timestamp': record.created, } if isinstance(record.args, dict): eventDict.update(record.args) extra = { name: value for name, value in vars(record).iteritems() if name not in _DEFAULT_LOGGING_ATTRIBUTES } eventDict.update(extra) # Format the message for its side effects and extract the message # and exception information self.format(record) eventDict['message'] = record.message if record.exc_info: excType, excValue = record.exc_info[0:2] eventDict['excValue'] = reflect.safe_str(excValue) if excValue is None: eventDict['excText'] = None eventDict['excType'] = 'NoneType' else: eventDict['excText'] = record.exc_text eventDict['excType'] = reflect.qual(excType) # Extract the category, possibly overridden from record.args. category = eventDict['category'] del eventDict['category'] self.logger.log(category, eventDict) except (KeyboardInterrupt, SystemExit): raise except: self.handleError(record)
def assertDefaultTraceback(self, captureVars=False): """ Assert that L{printTraceback} produces and prints a default traceback. The default traceback consists of a header:: Traceback (most recent call last): The body with traceback:: File "/twisted/trial/_synctest.py", line 1180, in _run runWithWarningsSuppressed(suppress, method) And the footer:: --- <exception caught here> --- File "twisted/test/test_failure.py", line 39, in getDivisionFailure 1/0 exceptions.ZeroDivisionError: float division @param captureVars: Enables L{Failure.captureVars}. @type captureVars: C{bool} """ if captureVars: exampleLocalVar = 'xyzzy' # Silence the linter as this variable is checked via # the traceback. exampleLocalVar f = getDivisionFailure(captureVars=captureVars) out = NativeStringIO() f.printTraceback(out) tb = out.getvalue() stack = '' for method, filename, lineno, localVars, globalVars in f.frames: stack += ' File "%s", line %s, in %s\n' % (filename, lineno, method) stack += ' %s\n' % (linecache.getline( filename, lineno).strip(),) self.assertTracebackFormat(tb, "Traceback (most recent call last):", "%s\n%s%s: %s\n" % (failure.EXCEPTION_CAUGHT_HERE, stack, reflect.qual(f.type), reflect.safe_str(f.value))) if captureVars: self.assertEqual(None, re.search('exampleLocalVar.*xyzzy', tb))
def emit(self, record): """ Emit a record. """ try: eventDict = { 'category': self.category, 'logLevel': record.levelname, 'logName': record.name, 'filename': record.pathname, 'lineno': record.lineno, 'funcName': record.funcName, 'timestamp': record.created, } if isinstance(record.args, dict): eventDict.update(record.args) extra = {name: value for name, value in vars(record).iteritems() if name not in _DEFAULT_LOGGING_ATTRIBUTES} eventDict.update(extra) # Format the message for its side effects and extract the message # and exception information self.format(record) eventDict['message'] = record.message if record.exc_info: excType, excValue = record.exc_info[0:2] eventDict['excValue'] = reflect.safe_str(excValue) if excValue is None: eventDict['excText'] = None eventDict['excType'] = 'NoneType' else: eventDict['excText'] = record.exc_text eventDict['excType'] = reflect.qual(excType) # Extract the category, possibly overridden from record.args. category = eventDict['category'] del eventDict['category'] self.logger.log(category, eventDict) except (KeyboardInterrupt, SystemExit): raise except: self.handleError(record)
def eb_massage_error(error): if error.check(amp.RemoteAmpError): # Convert remote errors back into local errors using the # command's error map if possible. error_type = command.reverseErrors.get(error.value.errorCode, amp.UnknownRemoteError) return Failure(error_type(error.value.description)) else: # Exceptions raised in responders that aren't declared in that # responder's schema can get through to here without being wrapped # in RemoteAmpError. This is because call_responder() bypasses the # network marshall/unmarshall steps, where these exceptions would # ordinarily get squashed. return Failure( amp.UnknownRemoteError( "%s: %s" % (reflect.qual(error.type), reflect.safe_str(error.value))))
def err(self, _stuff=None, _why=None, **kwargs): """ This method is API-compatible with L{twisted.python.log.err} and exists for compatibility with that API. @param _stuff: Something that describes a problem. @type _stuff: L{Failure}, L{str}, or L{Exception} @param _why: A string describing what caused the failure. @type _why: L{str} @param kwargs: Additional fields. @type kwargs: L{dict} """ if _stuff is None: _stuff = Failure() elif isinstance(_stuff, Exception): _stuff = Failure(_stuff) if isinstance(_stuff, Failure): if _why: text = safe_str(_why) else: text = "Unhandled Error" text = "{why}\n{traceback}".format( why=text, traceback=_stuff.getTraceback(), ) self.newStyleLogger.emit(LogLevel.critical, text, failure=_stuff, why=_why, isError=1, **kwargs) else: # We got called with an invalid _stuff. self.newStyleLogger.emit(LogLevel.critical, repr(_stuff), why=_why, isError=1, **kwargs)
def textFromEventDict(eventDict: EventDict) -> Optional[str]: """ Extract text from an event dict passed to a log observer. If it cannot handle the dict, it returns None. The possible keys of eventDict are: - C{message}: by default, it holds the final text. It's required, but can be empty if either C{isError} or C{format} is provided (the first having the priority). - C{isError}: boolean indicating the nature of the event. - C{failure}: L{failure.Failure} instance, required if the event is an error. - C{why}: if defined, used as header of the traceback in case of errors. - C{format}: string format used in place of C{message} to customize the event. It uses all keys present in C{eventDict} to format the text. Other keys will be used when applying the C{format}, or ignored. """ edm = eventDict["message"] if not edm: if eventDict["isError"] and "failure" in eventDict: why = cast(str, eventDict.get("why")) if why: why = reflect.safe_str(why) else: why = "Unhandled Error" try: traceback = cast(failure.Failure, eventDict["failure"]).getTraceback() except Exception as e: traceback = "(unable to obtain traceback): " + str(e) text = why + "\n" + traceback elif "format" in eventDict: text = _safeFormat(eventDict["format"], eventDict) else: # We don't know how to log this return None else: text = " ".join(map(reflect.safe_str, edm)) return text
def textFromEventDict(eventDict): """ Extract text from an event dict passed to a log observer. If it cannot handle the dict, it returns None. The possible keys of eventDict are: - C{message}: by default, it holds the final text. It's required, but can be empty if either C{isError} or C{format} is provided (the first having the priority). - C{isError}: boolean indicating the nature of the event. - C{failure}: L{failure.Failure} instance, required if the event is an error. - C{why}: if defined, used as header of the traceback in case of errors. - C{format}: string format used in place of C{message} to customize the event. It uses all keys present in C{eventDict} to format the text. Other keys will be used when applying the C{format}, or ignored. """ edm = eventDict['message'] if not edm: if eventDict['isError'] and 'failure' in eventDict: why = eventDict.get('why') if why: why = reflect.safe_str(why) else: why = 'Unhandled Error' try: traceback = eventDict['failure'].getTraceback() except Exception as e: traceback = '(unable to obtain traceback): ' + str(e) text = (why + '\n' + traceback) elif 'format' in eventDict: text = _safeFormat(eventDict['format'], eventDict) else: # We don't know how to log this return None else: text = ' '.join(map(reflect.safe_str, edm)) return text
def write_error(failure): if failure.check(APIError): status = failure.value.status # Don't log the stack traces for 4xx responses. if status < 400 or status >= 500: log.err(failure) else: log.msg("status: %s message: %s" % (status, safe_str(failure.value))) body = failure.value.response if body is None: body = self.dump_error(failure.value, request) else: # If the error is a generic one (not an APIError), log the # message , but don't send it back to the client, as it could # contain sensitive information. Send a generic server error # message instead. log.err(failure) body = "Server error" status = 500 request.setResponseCode(status) write_response(body)
def testBrokenStr(self): b = Breakable() b.breakStr = True reflect.safe_str(b)
def getErrorMessage(self): """Get a string of the exception which caused this Failure.""" if isinstance(self.value, Failure): return self.value.getErrorMessage() return reflect.safe_str(self.value)
def testBrokenClassStr(self): class X(BTBase): breakStr = True reflect.safe_str(X) reflect.safe_str(X())
def testBroken__Class__Name__Attr(self): class X(BTBase): breakName = True reflect.safe_str(X())
def test_brokenRepr(self): b = Breakable() b.breakRepr = True reflect.safe_str(b)
def assertDetailedTraceback(self, captureVars=False, cleanFailure=False): """ Assert that L{printDetailedTraceback} produces and prints a detailed traceback. The detailed traceback consists of a header:: *--- Failure #20 --- The body contains the stacktrace:: /twisted/trial/_synctest.py:1180: _run(...) /twisted/python/util.py:1076: runWithWarningsSuppressed(...) --- <exception caught here> --- /twisted/test/test_failure.py:39: getDivisionFailure(...) If C{captureVars} is enabled the body also includes a list of globals and locals:: [ Locals ] exampleLocalVar : 'xyz' ... ( Globals ) ... Or when C{captureVars} is disabled:: [Capture of Locals and Globals disabled (use captureVars=True)] When C{cleanFailure} is enabled references to other objects are removed and replaced with strings. And finally the footer with the L{Failure}'s value:: exceptions.ZeroDivisionError: float division *--- End of Failure #20 --- @param captureVars: Enables L{Failure.captureVars}. @type captureVars: C{bool} @param cleanFailure: Enables L{Failure.cleanFailure}. @type cleanFailure: C{bool} """ if captureVars: exampleLocalVar = "xyz" # Silence the linter as this variable is checked via # the traceback. exampleLocalVar f = getDivisionFailure(captureVars=captureVars) out = StringIO() if cleanFailure: f.cleanFailure() f.printDetailedTraceback(out) tb = out.getvalue() start = "*--- Failure #%d%s---\n" % ( f.count, (f.pickled and " (pickled) ") or " ", ) end = "%s: %s\n*--- End of Failure #%s ---\n" % ( reflect.qual(f.type), reflect.safe_str(f.value), f.count, ) self.assertTracebackFormat(tb, start, end) # Variables are printed on lines with 2 leading spaces. linesWithVars = [ line for line in tb.splitlines() if line.startswith(" ") ] if captureVars: self.assertNotEqual([], linesWithVars) if cleanFailure: line = " exampleLocalVar : \"'xyz'\"" else: line = " exampleLocalVar : 'xyz'" self.assertIn(line, linesWithVars) else: self.assertEqual([], linesWithVars) self.assertIn( " [Capture of Locals and Globals disabled (use " "captureVars=True)]\n", tb, )
def testBroken__Class__Attr(self): reflect.safe_str(NoClassAttr())
def printTraceback(self, file=None, elideFrameworkCode=False, detail='default'): """ Emulate Python's standard error reporting mechanism. @param file: If specified, a file-like object to which to write the traceback. @param elideFrameworkCode: A flag indicating whether to attempt to remove uninteresting frames from within Twisted itself from the output. @param detail: A string indicating how much information to include in the traceback. Must be one of C{'brief'}, C{'default'}, or C{'verbose'}. """ if file is None: from twisted.python import log file = log.logerr w = file.write if detail == 'verbose' and not self.captureVars: # We don't have any locals or globals, so rather than show them as # empty make the output explicitly say that we don't have them at # all. formatDetail = 'verbose-vars-not-captured' else: formatDetail = detail # Preamble if detail == 'verbose': w('*--- Failure #%d%s---\n' % (self.count, (self.pickled and ' (pickled) ') or ' ')) elif detail == 'brief': if self.frames: hasFrames = 'Traceback' else: hasFrames = 'Traceback (failure with no frames)' w("%s: %s: %s\n" % (hasFrames, reflect.safe_str( self.type), reflect.safe_str(self.value))) else: w('Traceback (most recent call last):\n') # Frames, formatted in appropriate style if self.frames: if not elideFrameworkCode: format_frames(self.stack[-traceupLength:], w, formatDetail) w("%s\n" % (EXCEPTION_CAUGHT_HERE, )) format_frames(self.frames, w, formatDetail) elif not detail == 'brief': # Yeah, it's not really a traceback, despite looking like one... w("Failure: ") # Postamble, if any if not detail == 'brief': w("%s: %s\n" % (reflect.qual(self.type), reflect.safe_str(self.value))) # Chaining if isinstance(self.value, Failure): # TODO: indentation for chained failures? file.write(" (chained Failure)\n") self.value.printTraceback(file, elideFrameworkCode, detail) if detail == 'verbose': w('*--- End of Failure #%d ---\n' % self.count)
def printTraceback(self, file=None, elideFrameworkCode=False, detail='default'): """ Emulate Python's standard error reporting mechanism. @param file: If specified, a file-like object to which to write the traceback. @param elideFrameworkCode: A flag indicating whether to attempt to remove uninteresting frames from within Twisted itself from the output. @param detail: A string indicating how much information to include in the traceback. Must be one of C{'brief'}, C{'default'}, or C{'verbose'}. """ if file is None: from twisted.python import log file = log.logerr w = file.write if detail == 'verbose' and not self.captureVars: # We don't have any locals or globals, so rather than show them as # empty make the output explicitly say that we don't have them at # all. formatDetail = 'verbose-vars-not-captured' else: formatDetail = detail # Preamble if detail == 'verbose': w( '*--- Failure #%d%s---\n' % (self.count, (self.pickled and ' (pickled) ') or ' ')) elif detail == 'brief': if self.frames: hasFrames = 'Traceback' else: hasFrames = 'Traceback (failure with no frames)' w("%s: %s: %s\n" % ( hasFrames, reflect.safe_str(self.type), reflect.safe_str(self.value))) else: w( 'Traceback (most recent call last):\n') # Frames, formatted in appropriate style if self.frames: if not elideFrameworkCode: format_frames(self.stack[-traceupLength:], w, formatDetail) w("%s\n" % (EXCEPTION_CAUGHT_HERE,)) format_frames(self.frames, w, formatDetail) elif not detail == 'brief': # Yeah, it's not really a traceback, despite looking like one... w("Failure: ") # postamble, if any if not detail == 'brief': w("%s: %s\n" % (reflect.qual(self.type), reflect.safe_str(self.value))) # chaining if isinstance(self.value, Failure): # TODO: indentation for chained failures? file.write(" (chained Failure)\n") self.value.printTraceback(file, elideFrameworkCode, detail) if detail == 'verbose': w('*--- End of Failure #%d ---\n' % self.count)
def emit(self, eventDict): """ Log an event. This converts C{eventDict} so that it can be serialized to JSON and sent over UDP to the logging server. The key C{'time'} that is automatically provided by Twisted is renamed to C{'timestamp'} that is used in UDP log. When Twisted logs an error, the associated Failure is in the C{eventDict} with key C{'failure'}. For warnings, C{'warning'} holds the warning class and its arguments, and C{'filename'}, C{'lineno'} the location where the warning was reported from. See L{twisted.python.log.textFromEventDict} for how C{'format'} is used to render failures and warnings. See L{twisted.python.log.ILogObserver}. """ eventDict = eventDict.copy() eventDict['message'] = log.textFromEventDict(eventDict) eventDict['timestamp'] = eventDict['time'] if 'warning' in eventDict: # Twisted passes the warning category in 'category' and the # warning instance in 'warning'. Override message to only contain # actual warning message and put the category in 'warning'. eventDict['message'] = reflect.safe_str(eventDict['warning']) eventDict['warningCategory'] = eventDict['category'] eventDict.setdefault('logLevel', 'WARNING') del eventDict['category'] del eventDict['warning'] if 'isError' in eventDict: eventDict['isError'] = bool(eventDict['isError']) if eventDict.get('isError', False) and 'failure' in eventDict: # Twisted passed the failure instance in 'failure'. Add a field # 'excType' containing the exception type and remove 'failure'. # We always want to render the traceback in a separate field, so we # override the actual message that textFromEventDict created for # us. udplog.augmentWithFailure(eventDict, eventDict['failure'], eventDict['why'] ) del eventDict['why'] del eventDict['failure'] eventDict.setdefault('logLevel', 'INFO') # Clean up unneeded Twisted specific keys. # * time is replaced by timeformat # * format, if present, is used by textFromEventDict. for key in ('time', 'format'): if key in eventDict: del eventDict[key] category = eventDict.get('category', self.defaultCategory) self.logger.log(category, eventDict)
def dump_error(self, error, request): return str("%s - %s" % (error.code, safe_str(error.message)))
def test_workingStr(self): x = [1, 2, 3] self.assertEquals(reflect.safe_str(x), str(x))
def test_workingStr(self): x = [1, 2, 3] self.assertEqual(reflect.safe_str(x), str(x))
def test_brokenClassRepr(self): class X(BTBase): breakRepr = True reflect.safe_str(X) reflect.safe_str(X())
def assertDetailedTraceback(self, captureVars=False, cleanFailure=False): """ Assert that L{printDetailedTraceback} produces and prints a detailed traceback. The detailed traceback consists of a header:: *--- Failure #20 --- The body contains the stacktrace:: /twisted/trial/_synctest.py:1180: _run(...) /twisted/python/util.py:1076: runWithWarningsSuppressed(...) --- <exception caught here> --- /twisted/test/test_failure.py:39: getDivisionFailure(...) If C{captureVars} is enabled the body also includes a list of globals and locals:: [ Locals ] exampleLocalVar : 'xyz' ... ( Globals ) ... Or when C{captureVars} is disabled:: [Capture of Locals and Globals disabled (use captureVars=True)] When C{cleanFailure} is enabled references to other objects are removed and replaced with strings. And finally the footer with the L{Failure}'s value:: exceptions.ZeroDivisionError: float division *--- End of Failure #20 --- @param captureVars: Enables L{Failure.captureVars}. @type captureVars: C{bool} @param cleanFailure: Enables L{Failure.cleanFailure}. @type cleanFailure: C{bool} """ if captureVars: exampleLocalVar = 'xyz' # Silence the linter as this variable is checked via # the traceback. exampleLocalVar f = getDivisionFailure(captureVars=captureVars) out = NativeStringIO() if cleanFailure: f.cleanFailure() f.printDetailedTraceback(out) tb = out.getvalue() start = "*--- Failure #%d%s---\n" % (f.count, (f.pickled and ' (pickled) ') or ' ') end = "%s: %s\n*--- End of Failure #%s ---\n" % (reflect.qual(f.type), reflect.safe_str(f.value), f.count) self.assertTracebackFormat(tb, start, end) # Variables are printed on lines with 2 leading spaces. linesWithVars = [line for line in tb.splitlines() if line.startswith(' ')] if captureVars: self.assertNotEqual([], linesWithVars) if cleanFailure: line = ' exampleLocalVar : "\'xyz\'"' else: line = " exampleLocalVar : 'xyz'" self.assertIn(line, linesWithVars) else: self.assertEqual([], linesWithVars) self.assertIn(' [Capture of Locals and Globals disabled (use ' 'captureVars=True)]\n', tb)
def from_failure(cls, reason, text="Fatal error", code=400): text = "%s: %s: %s" % (text, reflect.qual(reason.type), reflect.safe_str(reason.value)) return cls(code, text, reason.getTraceback())