diff env/lib/python3.7/site-packages/boltons/tbutils.py @ 5:9b1c78e6ba9c draft default tip

"planemo upload commit 6c0a8142489327ece472c84e558c47da711a9142"
author shellac
date Mon, 01 Jun 2020 08:59:25 -0400 (2020-06-01)
parents 79f47841a781
children
line wrap: on
line diff
--- a/env/lib/python3.7/site-packages/boltons/tbutils.py	Thu May 14 16:47:39 2020 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,796 +0,0 @@
-# -*- coding: utf-8 -*-
-"""One of the oft-cited tenets of Python is that it is better to ask
-forgiveness than permission. That is, there are many cases where it is
-more inclusive and correct to handle exceptions than spend extra lines
-and execution time checking for conditions. This philosophy makes good
-exception handling features all the more important. Unfortunately
-Python's :mod:`traceback` module is woefully behind the times.
-
-The ``tbutils`` module provides two disparate but complementary featuresets:
-
-  1. With :class:`ExceptionInfo` and :class:`TracebackInfo`, the
-     ability to extract, construct, manipulate, format, and serialize
-     exceptions, tracebacks, and callstacks.
-  2. With :class:`ParsedException`, the ability to find and parse tracebacks
-     from captured output such as logs and stdout.
-
-There is also the :class:`ContextualTracebackInfo` variant of
-:class:`TracebackInfo`, which includes much more information from each
-frame of the callstack, including values of locals and neighboring
-lines of code.
-"""
-
-from __future__ import print_function
-
-import re
-import sys
-import linecache
-
-
-try:
-    text = unicode  # Python 2
-except NameError:
-    text = str      # Python 3
-
-
-# TODO: chaining primitives?  what are real use cases where these help?
-
-# TODO: print_* for backwards compatibility
-# __all__ = ['extract_stack', 'extract_tb', 'format_exception',
-#            'format_exception_only', 'format_list', 'format_stack',
-#            'format_tb', 'print_exc', 'format_exc', 'print_exception',
-#            'print_last', 'print_stack', 'print_tb']
-
-
-__all__ = ['ExceptionInfo', 'TracebackInfo', 'Callpoint',
-           'ContextualExceptionInfo', 'ContextualTracebackInfo',
-           'ContextualCallpoint', 'print_exception', 'ParsedException']
-
-
-class Callpoint(object):
-    """The Callpoint is a lightweight object used to represent a single
-    entry in the code of a call stack. It stores the code-related
-    metadata of a given frame. Available attributes are the same as
-    the parameters below.
-
-    Args:
-        func_name (str): the function name
-        lineno (int): the line number
-        module_name (str): the module name
-        module_path (str): the filesystem path of the module
-        lasti (int): the index of bytecode execution
-        line (str): the single-line code content (if available)
-
-    """
-    __slots__ = ('func_name', 'lineno', 'module_name', 'module_path', 'lasti',
-                 'line')
-
-    def __init__(self, module_name, module_path, func_name,
-                 lineno, lasti, line=None):
-        self.func_name = func_name
-        self.lineno = lineno
-        self.module_name = module_name
-        self.module_path = module_path
-        self.lasti = lasti
-        self.line = line
-
-    def to_dict(self):
-        "Get a :class:`dict` copy of the Callpoint. Useful for serialization."
-        ret = {}
-        for slot in self.__slots__:
-            try:
-                val = getattr(self, slot)
-            except AttributeError:
-                pass
-            else:
-                ret[slot] = str(val) if isinstance(val, _DeferredLine) else val
-        return ret
-
-    @classmethod
-    def from_current(cls, level=1):
-        "Creates a Callpoint from the location of the calling function."
-        frame = sys._getframe(level)
-        return cls.from_frame(frame)
-
-    @classmethod
-    def from_frame(cls, frame):
-        "Create a Callpoint object from data extracted from the given frame."
-        func_name = frame.f_code.co_name
-        lineno = frame.f_lineno
-        module_name = frame.f_globals.get('__name__', '')
-        module_path = frame.f_code.co_filename
-        lasti = frame.f_lasti
-        line = _DeferredLine(module_path, lineno, frame.f_globals)
-        return cls(module_name, module_path, func_name,
-                   lineno, lasti, line=line)
-
-    @classmethod
-    def from_tb(cls, tb):
-        """Create a Callpoint from the traceback of the current
-        exception. Main difference with :meth:`from_frame` is that
-        ``lineno`` and ``lasti`` come from the traceback, which is to
-        say the line that failed in the try block, not the line
-        currently being executed (in the except block).
-        """
-        func_name = tb.tb_frame.f_code.co_name
-        lineno = tb.tb_lineno
-        lasti = tb.tb_lasti
-        module_name = tb.tb_frame.f_globals.get('__name__', '')
-        module_path = tb.tb_frame.f_code.co_filename
-        line = _DeferredLine(module_path, lineno, tb.tb_frame.f_globals)
-        return cls(module_name, module_path, func_name,
-                   lineno, lasti, line=line)
-
-    def __repr__(self):
-        cn = self.__class__.__name__
-        args = [getattr(self, s, None) for s in self.__slots__]
-        if not any(args):
-            return super(Callpoint, self).__repr__()
-        else:
-            return '%s(%s)' % (cn, ', '.join([repr(a) for a in args]))
-
-    def tb_frame_str(self):
-        """Render the Callpoint as it would appear in a standard printed
-        Python traceback. Returns a string with filename, line number,
-        function name, and the actual code line of the error on up to
-        two lines.
-        """
-        ret = '  File "%s", line %s, in %s\n' % (self.module_path,
-                                                 self.lineno,
-                                                 self.func_name)
-        if self.line:
-            ret += '    %s\n' % (str(self.line).strip(),)
-        return ret
-
-
-class _DeferredLine(object):
-    """The _DeferredLine type allows Callpoints and TracebackInfos to be
-    constructed without potentially hitting the filesystem, as is the
-    normal behavior of the standard Python :mod:`traceback` and
-    :mod:`linecache` modules. Calling :func:`str` fetches and caches
-    the line.
-
-    Args:
-        filename (str): the path of the file containing the line
-        lineno (int): the number of the line in question
-        module_globals (dict): an optional dict of module globals,
-            used to handle advanced use cases using custom module loaders.
-
-    """
-    __slots__ = ('filename', 'lineno', '_line', '_mod_name', '_mod_loader')
-
-    def __init__(self, filename, lineno, module_globals=None):
-        self.filename = filename
-        self.lineno = lineno
-        # TODO: this is going away when we fix linecache
-        # TODO: (mark) read about loader
-        if module_globals is None:
-            self._mod_name = None
-            self._mod_loader = None
-        else:
-            self._mod_name = module_globals.get('__name__')
-            self._mod_loader = module_globals.get('__loader__')
-
-    def __eq__(self, other):
-        return (self.lineno, self.filename) == (other.lineno, other.filename)
-
-    def __ne__(self, other):
-        return not self == other
-
-    def __str__(self):
-        ret = getattr(self, '_line', None)
-        if ret is not None:
-            return ret
-        try:
-            linecache.checkcache(self.filename)
-            mod_globals = {'__name__': self._mod_name,
-                           '__loader__': self._mod_loader}
-            line = linecache.getline(self.filename,
-                                     self.lineno,
-                                     mod_globals)
-            line = line.rstrip()
-        except KeyError:
-            line = ''
-        self._line = line
-        return line
-
-    def __repr__(self):
-        return repr(str(self))
-
-    def __len__(self):
-        return len(str(self))
-
-
-# TODO: dedup frames, look at __eq__ on _DeferredLine
-class TracebackInfo(object):
-    """The TracebackInfo class provides a basic representation of a stack
-    trace, be it from an exception being handled or just part of
-    normal execution. It is basically a wrapper around a list of
-    :class:`Callpoint` objects representing frames.
-
-    Args:
-        frames (list): A list of frame objects in the stack.
-
-    .. note ::
-
-      ``TracebackInfo`` can represent both exception tracebacks and
-      non-exception tracebacks (aka stack traces). As a result, there
-      is no ``TracebackInfo.from_current()``, as that would be
-      ambiguous. Instead, call :meth:`TracebackInfo.from_frame`
-      without the *frame* argument for a stack trace, or
-      :meth:`TracebackInfo.from_traceback` without the *tb* argument
-      for an exception traceback.
-    """
-    callpoint_type = Callpoint
-
-    def __init__(self, frames):
-        self.frames = frames
-
-    @classmethod
-    def from_frame(cls, frame=None, level=1, limit=None):
-        """Create a new TracebackInfo *frame* by recurring up in the stack a
-        max of *limit* times. If *frame* is unset, get the frame from
-        :func:`sys._getframe` using *level*.
-
-        Args:
-            frame (types.FrameType): frame object from
-                :func:`sys._getframe` or elsewhere. Defaults to result
-                of :func:`sys.get_frame`.
-            level (int): If *frame* is unset, the desired frame is
-                this many levels up the stack from the invocation of
-                this method. Default ``1`` (i.e., caller of this method).
-            limit (int): max number of parent frames to extract
-                (defaults to :data:`sys.tracebacklimit`)
-
-        """
-        ret = []
-        if frame is None:
-            frame = sys._getframe(level)
-        if limit is None:
-            limit = getattr(sys, 'tracebacklimit', 1000)
-        n = 0
-        while frame is not None and n < limit:
-            item = cls.callpoint_type.from_frame(frame)
-            ret.append(item)
-            frame = frame.f_back
-            n += 1
-        ret.reverse()
-        return cls(ret)
-
-    @classmethod
-    def from_traceback(cls, tb=None, limit=None):
-        """Create a new TracebackInfo from the traceback *tb* by recurring
-        up in the stack a max of *limit* times. If *tb* is unset, get
-        the traceback from the currently handled exception. If no
-        exception is being handled, raise a :exc:`ValueError`.
-
-        Args:
-
-            frame (types.TracebackType): traceback object from
-                :func:`sys.exc_info` or elsewhere. If absent or set to
-                ``None``, defaults to ``sys.exc_info()[2]``, and
-                raises a :exc:`ValueError` if no exception is
-                currently being handled.
-            limit (int): max number of parent frames to extract
-                (defaults to :data:`sys.tracebacklimit`)
-
-        """
-        ret = []
-        if tb is None:
-            tb = sys.exc_info()[2]
-            if tb is None:
-                raise ValueError('no tb set and no exception being handled')
-        if limit is None:
-            limit = getattr(sys, 'tracebacklimit', 1000)
-        n = 0
-        while tb is not None and n < limit:
-            item = cls.callpoint_type.from_tb(tb)
-            ret.append(item)
-            tb = tb.tb_next
-            n += 1
-        return cls(ret)
-
-    @classmethod
-    def from_dict(cls, d):
-        "Complements :meth:`TracebackInfo.to_dict`."
-        # TODO: check this.
-        return cls(d['frames'])
-
-    def to_dict(self):
-        """Returns a dict with a list of :class:`Callpoint` frames converted
-        to dicts.
-        """
-        return {'frames': [f.to_dict() for f in self.frames]}
-
-    def __len__(self):
-        return len(self.frames)
-
-    def __iter__(self):
-        return iter(self.frames)
-
-    def __repr__(self):
-        cn = self.__class__.__name__
-
-        if self.frames:
-            frame_part = ' last=%r' % (self.frames[-1],)
-        else:
-            frame_part = ''
-
-        return '<%s frames=%s%s>' % (cn, len(self.frames), frame_part)
-
-    def __str__(self):
-        return self.get_formatted()
-
-    def get_formatted(self):
-        """Returns a string as formatted in the traditional Python
-        built-in style observable when an exception is not caught. In
-        other words, mimics :func:`traceback.format_tb` and
-        :func:`traceback.format_stack`.
-        """
-        ret = 'Traceback (most recent call last):\n'
-        ret += ''.join([f.tb_frame_str() for f in self.frames])
-        return ret
-
-
-class ExceptionInfo(object):
-    """An ExceptionInfo object ties together three main fields suitable
-    for representing an instance of an exception: The exception type
-    name, a string representation of the exception itself (the
-    exception message), and information about the traceback (stored as
-    a :class:`TracebackInfo` object).
-
-    These fields line up with :func:`sys.exc_info`, but unlike the
-    values returned by that function, ExceptionInfo does not hold any
-    references to the real exception or traceback. This property makes
-    it suitable for serialization or long-term retention, without
-    worrying about formatting pitfalls, circular references, or leaking memory.
-
-    Args:
-
-        exc_type (str): The exception type name.
-        exc_msg (str): String representation of the exception value.
-        tb_info (TracebackInfo): Information about the stack trace of the
-            exception.
-
-    Like the :class:`TracebackInfo`, ExceptionInfo is most commonly
-    instantiated from one of its classmethods: :meth:`from_exc_info`
-    or :meth:`from_current`.
-    """
-
-    #: Override this in inherited types to control the TracebackInfo type used
-    tb_info_type = TracebackInfo
-
-    def __init__(self, exc_type, exc_msg, tb_info):
-        # TODO: additional fields for SyntaxErrors
-        self.exc_type = exc_type
-        self.exc_msg = exc_msg
-        self.tb_info = tb_info
-
-    @classmethod
-    def from_exc_info(cls, exc_type, exc_value, traceback):
-        """Create an :class:`ExceptionInfo` object from the exception's type,
-        value, and traceback, as returned by :func:`sys.exc_info`. See
-        also :meth:`from_current`.
-        """
-        type_str = exc_type.__name__
-        type_mod = exc_type.__module__
-        if type_mod not in ("__main__", "__builtin__", "exceptions", "builtins"):
-            type_str = '%s.%s' % (type_mod, type_str)
-        val_str = _some_str(exc_value)
-        tb_info = cls.tb_info_type.from_traceback(traceback)
-        return cls(type_str, val_str, tb_info)
-
-    @classmethod
-    def from_current(cls):
-        """Create an :class:`ExceptionInfo` object from the current exception
-        being handled, by way of :func:`sys.exc_info`. Will raise an
-        exception if no exception is currently being handled.
-        """
-        return cls.from_exc_info(*sys.exc_info())
-
-    def to_dict(self):
-        """Get a :class:`dict` representation of the ExceptionInfo, suitable
-        for JSON serialization.
-        """
-        return {'exc_type': self.exc_type,
-                'exc_msg': self.exc_msg,
-                'exc_tb': self.tb_info.to_dict()}
-
-    def __repr__(self):
-        cn = self.__class__.__name__
-        try:
-            len_frames = len(self.tb_info.frames)
-            last_frame = ', last=%r' % (self.tb_info.frames[-1],)
-        except Exception:
-            len_frames = 0
-            last_frame = ''
-        args = (cn, self.exc_type, self.exc_msg, len_frames, last_frame)
-        return '<%s [%s: %s] (%s frames%s)>' % args
-
-    def get_formatted(self):
-        """Returns a string formatted in the traditional Python
-        built-in style observable when an exception is not caught. In
-        other words, mimics :func:`traceback.format_exception`.
-        """
-        # TODO: add SyntaxError formatting
-        tb_str = self.tb_info.get_formatted()
-        return ''.join([tb_str, '%s: %s' % (self.exc_type, self.exc_msg)])
-
-    def get_formatted_exception_only(self):
-        return '%s: %s' % (self.exc_type, self.exc_msg)
-
-
-class ContextualCallpoint(Callpoint):
-    """The ContextualCallpoint is a :class:`Callpoint` subtype with the
-    exact same API and storing two additional values:
-
-      1. :func:`repr` outputs for local variables from the Callpoint's scope
-      2. A number of lines before and after the Callpoint's line of code
-
-    The ContextualCallpoint is used by the :class:`ContextualTracebackInfo`.
-    """
-    def __init__(self, *a, **kw):
-        self.local_reprs = kw.pop('local_reprs', {})
-        self.pre_lines = kw.pop('pre_lines', [])
-        self.post_lines = kw.pop('post_lines', [])
-        super(ContextualCallpoint, self).__init__(*a, **kw)
-
-    @classmethod
-    def from_frame(cls, frame):
-        "Identical to :meth:`Callpoint.from_frame`"
-        ret = super(ContextualCallpoint, cls).from_frame(frame)
-        ret._populate_local_reprs(frame.f_locals)
-        ret._populate_context_lines()
-        return ret
-
-    @classmethod
-    def from_tb(cls, tb):
-        "Identical to :meth:`Callpoint.from_tb`"
-        ret = super(ContextualCallpoint, cls).from_tb(tb)
-        ret._populate_local_reprs(tb.tb_frame.f_locals)
-        ret._populate_context_lines()
-        return ret
-
-    def _populate_context_lines(self, pivot=8):
-        DL, lineno = _DeferredLine, self.lineno
-        try:
-            module_globals = self.line.module_globals
-        except Exception:
-            module_globals = None
-        start_line = max(0, lineno - pivot)
-        pre_lines = [DL(self.module_path, ln, module_globals)
-                     for ln in range(start_line, lineno)]
-        self.pre_lines[:] = pre_lines
-        post_lines = [DL(self.module_path, ln, module_globals)
-                      for ln in range(lineno + 1, lineno + 1 + pivot)]
-        self.post_lines[:] = post_lines
-        return
-
-    def _populate_local_reprs(self, f_locals):
-        local_reprs = self.local_reprs
-        for k, v in f_locals.items():
-            try:
-                local_reprs[k] = repr(v)
-            except Exception:
-                surrogate = '<unprintable %s object>' % type(v).__name__
-                local_reprs[k] = surrogate
-        return
-
-    def to_dict(self):
-        """
-        Same principle as :meth:`Callpoint.to_dict`, but with the added
-        contextual values. With ``ContextualCallpoint.to_dict()``,
-        each frame will now be represented like::
-
-          {'func_name': 'print_example',
-           'lineno': 0,
-           'module_name': 'example_module',
-           'module_path': '/home/example/example_module.pyc',
-           'lasti': 0,
-           'line': 'print "example"',
-           'locals': {'variable': '"value"'},
-           'pre_lines': ['variable = "value"'],
-           'post_lines': []}
-
-        The locals dictionary and line lists are copies and can be mutated
-        freely.
-        """
-        ret = super(ContextualCallpoint, self).to_dict()
-        ret['locals'] = dict(self.local_reprs)
-
-        # get the line numbers and textual lines
-        # without assuming DeferredLines
-        start_line = self.lineno - len(self.pre_lines)
-        pre_lines = [{'lineno': start_line + i, 'line': str(l)}
-                     for i, l in enumerate(self.pre_lines)]
-        # trim off leading empty lines
-        for i, item in enumerate(pre_lines):
-            if item['line']:
-                break
-        if i:
-            pre_lines = pre_lines[i:]
-        ret['pre_lines'] = pre_lines
-
-        # now post_lines
-        post_lines = [{'lineno': self.lineno + i, 'line': str(l)}
-                      for i, l in enumerate(self.post_lines)]
-        _last = 0
-        for i, item in enumerate(post_lines):
-            if item['line']:
-                _last = i
-        post_lines = post_lines[:_last + 1]
-        ret['post_lines'] = post_lines
-        return ret
-
-
-class ContextualTracebackInfo(TracebackInfo):
-    """The ContextualTracebackInfo type is a :class:`TracebackInfo`
-    subtype that is used by :class:`ContextualExceptionInfo` and uses
-    the :class:`ContextualCallpoint` as its frame-representing
-    primitive.
-    """
-    callpoint_type = ContextualCallpoint
-
-
-class ContextualExceptionInfo(ExceptionInfo):
-    """The ContextualTracebackInfo type is a :class:`TracebackInfo`
-    subtype that uses the :class:`ContextualCallpoint` as its
-    frame-representing primitive.
-
-    It carries with it most of the exception information required to
-    recreate the widely recognizable "500" page for debugging Django
-    applications.
-    """
-    tb_info_type = ContextualTracebackInfo
-
-
-# TODO: clean up & reimplement -- specifically for syntax errors
-def format_exception_only(etype, value):
-    """Format the exception part of a traceback.
-
-    The arguments are the exception type and value such as given by
-    sys.last_type and sys.last_value. The return value is a list of
-    strings, each ending in a newline.
-
-    Normally, the list contains a single string; however, for
-    SyntaxError exceptions, it contains several lines that (when
-    printed) display detailed information about where the syntax
-    error occurred.
-
-    The message indicating which exception occurred is always the last
-    string in the list.
-
-    """
-    # Gracefully handle (the way Python 2.4 and earlier did) the case of
-    # being called with (None, None).
-    if etype is None:
-        return [_format_final_exc_line(etype, value)]
-
-    stype = etype.__name__
-    smod = etype.__module__
-    if smod not in ("__main__", "builtins", "exceptions"):
-        stype = smod + '.' + stype
-
-    if not issubclass(etype, SyntaxError):
-        return [_format_final_exc_line(stype, value)]
-
-    # It was a syntax error; show exactly where the problem was found.
-    lines = []
-    filename = value.filename or "<string>"
-    lineno = str(value.lineno) or '?'
-    lines.append('  File "%s", line %s\n' % (filename, lineno))
-    badline = value.text
-    offset = value.offset
-    if badline is not None:
-        lines.append('    %s\n' % badline.strip())
-        if offset is not None:
-            caretspace = badline.rstrip('\n')[:offset].lstrip()
-            # non-space whitespace (likes tabs) must be kept for alignment
-            caretspace = ((c.isspace() and c or ' ') for c in caretspace)
-            # only three spaces to account for offset1 == pos 0
-            lines.append('   %s^\n' % ''.join(caretspace))
-    msg = value.msg or "<no detail available>"
-    lines.append("%s: %s\n" % (stype, msg))
-    return lines
-
-
-# TODO: use asciify, improved if necessary
-def _some_str(value):
-    try:
-        return str(value)
-    except Exception:
-        pass
-    try:
-        value = text(value)
-        return value.encode("ascii", "backslashreplace")
-    except Exception:
-        pass
-    return '<unprintable %s object>' % type(value).__name__
-
-
-def _format_final_exc_line(etype, value):
-    valuestr = _some_str(value)
-    if value is None or not valuestr:
-        line = "%s\n" % etype
-    else:
-        line = "%s: %s\n" % (etype, valuestr)
-    return line
-
-
-def print_exception(etype, value, tb, limit=None, file=None):
-    """Print exception up to 'limit' stack trace entries from 'tb' to 'file'.
-
-    This differs from print_tb() in the following ways: (1) if
-    traceback is not None, it prints a header "Traceback (most recent
-    call last):"; (2) it prints the exception type and value after the
-    stack trace; (3) if type is SyntaxError and value has the
-    appropriate format, it prints the line where the syntax error
-    occurred with a caret on the next line indicating the approximate
-    position of the error.
-    """
-
-    if file is None:
-        file = sys.stderr
-    if tb:
-        tbi = TracebackInfo.from_traceback(tb, limit)
-        print(str(tbi), end='', file=file)
-
-    for line in format_exception_only(etype, value):
-        print(line, end='', file=file)
-
-
-def fix_print_exception():
-    """
-    Sets the default exception hook :func:`sys.excepthook` to the
-    :func:`tbutils.print_exception` that uses all the ``tbutils``
-    facilities to provide slightly more correct output behavior.
-    """
-    sys.excepthook = print_exception
-
-
-_frame_re = re.compile(r'^File "(?P<filepath>.+)", line (?P<lineno>\d+)'
-                       r', in (?P<funcname>.+)$')
-_se_frame_re = re.compile(r'^File "(?P<filepath>.+)", line (?P<lineno>\d+)')
-
-
-# TODO: ParsedException generator over large bodies of text
-
-class ParsedException(object):
-    """Stores a parsed traceback and exception as would be typically
-    output by :func:`sys.excepthook` or
-    :func:`traceback.print_exception`.
-
-    .. note:
-
-       Does not currently store SyntaxError details such as column.
-
-    """
-    def __init__(self, exc_type_name, exc_msg, frames=None):
-        self.exc_type = exc_type_name
-        self.exc_msg = exc_msg
-        self.frames = list(frames or [])
-
-    @property
-    def source_file(self):
-        """
-        The file path of module containing the function that raised the
-        exception, or None if not available.
-        """
-        try:
-            return self.frames[-1]['filepath']
-        except IndexError:
-            return None
-
-    def to_dict(self):
-        "Get a copy as a JSON-serializable :class:`dict`."
-        return {'exc_type': self.exc_type,
-                'exc_msg': self.exc_msg,
-                'frames': list(self.frames)}
-
-    def __repr__(self):
-        cn = self.__class__.__name__
-        return ('%s(%r, %r, frames=%r)'
-                % (cn, self.exc_type, self.exc_msg, self.frames))
-
-    def to_string(self):
-        """Formats the exception and its traceback into the standard format,
-        as returned by the traceback module.
-
-        ``ParsedException.from_string(text).to_string()`` should yield
-        ``text``.
-        """
-        lines = [u'Traceback (most recent call last):']
-
-        for frame in self.frames:
-            lines.append(u'  File "%s", line %s, in %s' % (frame['filepath'],
-                                                           frame['lineno'],
-                                                           frame['funcname']))
-            source_line = frame.get('source_line')
-            if source_line:
-                lines.append(u'    %s' % (source_line,))
-        if self.exc_msg:
-            lines.append(u'%s: %s' % (self.exc_type, self.exc_msg))
-        else:
-            lines.append(u'%s' % (self.exc_type,))
-        return u'\n'.join(lines)
-
-    @classmethod
-    def from_string(cls, tb_str):
-        """Parse a traceback and exception from the text *tb_str*. This text
-        is expected to have been decoded, otherwise it will be
-        interpreted as UTF-8.
-
-        This method does not search a larger body of text for
-        tracebacks. If the first line of the text passed does not
-        match one of the known patterns, a :exc:`ValueError` will be
-        raised. This method will ignore trailing text after the end of
-        the first traceback.
-
-        Args:
-            tb_str (str): The traceback text (:class:`unicode` or UTF-8 bytes)
-        """
-        if not isinstance(tb_str, text):
-            tb_str = tb_str.decode('utf-8')
-        tb_lines = tb_str.lstrip().splitlines()
-
-        # First off, handle some ignored exceptions. These can be the
-        # result of exceptions raised by __del__ during garbage
-        # collection
-        while tb_lines:
-            cl = tb_lines[-1]
-            if cl.startswith('Exception ') and cl.endswith('ignored'):
-                tb_lines.pop()
-            else:
-                break
-        if tb_lines and tb_lines[0].strip() == 'Traceback (most recent call last):':
-            start_line = 1
-            frame_re = _frame_re
-        elif len(tb_lines) > 1 and tb_lines[-2].lstrip().startswith('^'):
-            # This is to handle the slight formatting difference
-            # associated with SyntaxErrors, which also don't really
-            # have tracebacks
-            start_line = 0
-            frame_re = _se_frame_re
-        else:
-            raise ValueError('unrecognized traceback string format')
-
-        frames = []
-        line_no = start_line
-        while True:
-            frame_line = tb_lines[line_no].strip()
-            frame_match = frame_re.match(frame_line)
-            if frame_match:
-                frame_dict = frame_match.groupdict()
-                try:
-                    next_line = tb_lines[line_no + 1]
-                except IndexError:
-                    # We read what we could
-                    next_line = ''
-                next_line_stripped = next_line.strip()
-                if (
-                        frame_re.match(next_line_stripped) or
-                        # The exception message will not be indented
-                        # This check is to avoid overrunning on eval-like
-                        # tracebacks where the last frame doesn't have source
-                        # code in the traceback
-                        not next_line.startswith(' ')
-                ):
-                    frame_dict['source_line'] = ''
-                else:
-                    frame_dict['source_line'] = next_line_stripped
-                    line_no += 1
-            else:
-                break
-            line_no += 1
-            frames.append(frame_dict)
-
-        try:
-            exc_line = '\n'.join(tb_lines[line_no:])
-            exc_type, _, exc_msg = exc_line.partition(': ')
-        except Exception:
-            exc_type, exc_msg = '', ''
-
-        return cls(exc_type, exc_msg, frames)
-
-
-ParsedTB = ParsedException  # legacy alias