Debugging-friendly exceptions for Python

Overview

Build Status

Better tracebacks

This is a more helpful version of Python's built-in exception message: It shows more code context and the current values of nearby variables. That answers many of the questions I'd ask an interactive debugger: Where in the code was the crash, what's in the relevant variables, and why was that function called with those arguments. It either prints to the console or gives you a string for logging.

pip3 install stackprinter

Before

Traceback (most recent call last):
  File "demo.py", line 12, in <module>
    dangerous_function(somelist + anotherlist)
  File "demo.py", line 6, in dangerous_function
    return sorted(blub, key=lambda xs: sum(xs))
  File "demo.py", line 6, in <lambda>
    return sorted(blub, key=lambda xs: sum(xs))
TypeError: unsupported operand type(s) for +: 'int' and 'str'

After

File demo.py, line 12, in <module>
    9        somelist = [[1,2], [3,4]]
    10       anotherlist = [['5', 6]]
    11       spam = numpy.zeros((3,3))
--> 12       dangerous_function(somelist + anotherlist)
    13   except:
    ..................................................
     somelist = [[1, 2, ], [3, 4, ], ]
     anotherlist = [['5', 6, ], ]
     spam = 3x3 array([[0. 0. 0.]
                       [0. 0. 0.]
                       [0. 0. 0.]])
    ..................................................

File demo.py, line 6, in dangerous_function
    5    def dangerous_function(blub):
--> 6        return sorted(blub, key=lambda xs: sum(xs))
    ..................................................
     blub = [[1, 2, ], [3, 4, ], ['5', 6, ], ]
    ..................................................

File demo.py, line 6, in <lambda>
    3
    4
    5    def dangerous_function(blub):
--> 6        return sorted(blub, key=lambda xs: sum(xs))
    7
    ..................................................
     xs = ['5', 6, ]
    ..................................................

TypeError: unsupported operand type(s) for +: 'int' and 'str'

I sometimes use this locally instead of a real debugger, but mostly it helps me sleep when my code runs somewhere where the only debug tool is a log file (though it's not a fully-grown error monitoring system).

By default, it tries to be somewhat polite about screen space (showing only a handful of source lines & the function header, and only the variables in those lines, and only (?) 500 characters per variable). You can configure exactly how verbose things should be.

It outputs plain text normally, which is good for log files. There's also a color mode for some reason 🌈 , with a few different color schemes for light and dark backgrounds. (The colors track different variables instead of the language syntax.)

Usage

Exception logging

To replace the default python crash printout, call set_excepthook() somewhere. This will print detailed stacktraces for any uncaught exception except KeyboardInterrupts (to stderr, by default). You could also make this permanent for your python installation.

import stackprinter
stackprinter.set_excepthook(style='darkbg2')  # for jupyter notebooks try style='lightbg'

For more control, call show() or format() inside an except block. show() prints to stderr by default, format() returns a string, for custom logging.

try:
    something()
except:
    # print the current exception to stderr:
    stackprinter.show()

    # ...or instead, get a string for logging:
    logger.error(stackprinter.format())

Or pass specific exceptions explicitly:

try:
    something()
except RuntimeError as exc:
    tb = stackprinter.format(exc)
    logger.error('The front fell off.\n' + tb)

It's also possible to integrate this neatly with standard logging calls through a bit of extra plumbing.

configure_logging() # adds a custom log formatter, see link above

try:
    something()
except:
    logger.exception('The front fell off.')  # Logs a rich traceback along with the given message

For all the config options see the docstring of format().

Printing the current call stack

To see your own thread's current call stack, call show or format anywhere outside of exception handling.

stackprinter.show() # or format()

Printing the stack of another thread

To inspect the call stack of any other running thread:

thread = threading.Thread(target=something)
thread.start()
# (...)
stackprinter.show(thread) # or format(thread)

Making it stick

To permanently replace the crash message for your python installation, you could put a file sitecustomize.py into the site-packages directory under one of the paths revealed by python -c "import site; print(site.PREFIXES)", with contents like this:

    # in e.g. some_virtualenv/lib/python3.x/site-packages/sitecustomize.py:
    import stackprinter
    stackprinter.set_excepthook(style='darkbg2')

That would give you colorful tracebacks automatically every time, even in the REPL.

(You could do a similar thing for IPython, but they have their own method, where the file goes into ~/.ipython/profile_default/startup instead, and also I don't want to talk about what this module does to set an excepthook under IPython.)

Docs

For now, the documentation consists only of some fairly detailed docstrings, e.g. those of format()

Caveats

This displays variable values as they are at the time of formatting. In multi-threaded programs, variables can change while we're busy walking the stack & printing them. So, if nothing seems to make sense, consider that your exception and the traceback messages are from slightly different times. Sadly, there is no responsible way to freeze all other threads as soon as we want to inspect some thread's call stack (...or is there?)

How it works

Basically, this is a frame formatter. For each frame on the call stack, it grabs the source code to find out which source lines reference which variables. Then it displays code and variables in the neighbourhood of the last executed line.

Since this already requires a map of where each variable occurs in the code, it was difficult not to also implement the whole semantic highlighting color thing seen in the screenshots. The colors are ANSI escape codes now, but it should be fairly straightforward™ to render the underlying data without any 1980ies terminal technology. Say, a foldable and clickable HTML page with downloadable pickled variables. For now you'll have to pipe the ANSI strings through ansi2html or something.

The format and everything is inspired by the excellent ultratb in IPython. One day I'd like to contribute the whole "find out which variables in locals and globals are nearby in the source and print only those" machine over there, after trimming its complexity a bit.

Tracing a piece of code

More for curiosity than anything else, you can watch a piece of code execute step-by-step, printing a trace of all calls & returns 'live' as they are happening. Slows everything down though, of course.

with stackprinter.TracePrinter(style='darkbg2'):
    dosomething()

or

tp = stackprinter.TracePrinter(style='darkbg2')
tp.enable()
dosomething()
# (...) +1 million lines
tp.disable()

Issues
  • Gracefully handle exception being

    Gracefully handle exception being "(None, None, None)"

    Hi!

    The built-in traceback module handles (None, None, None) tuple (returned if sys.exc_info() is called outside the context of an exception) without raising an error:

    import traceback
    
    traceback.print_exception(None, None, None)
    # 'NoneType: None'
    

    Using stackprinter, however:

    import stackprinter
    
    stackprinter.format((None, None, None))
    # ValueError: Can't format (None, None, None). Expected an exception instance, sys.exc_info() tuple,a frame or a thread object.
    

    You may argue that formatting such exception is pretty useless... You're right. :smile:

    Still, in my situation it happens that the exception tuple looks more like (TypeError, None, None) (I'll save you the details, but it happens if the error value can't be serialized, then it is replaced by None by default). In such case, it would be nice to format the error like TypeError: None for example instead of raising a ValueError. That would be useful so that user could format any exception-tuple without having to check for edge cases like that.

    opened by Delgan 7
  • No Colors in Windows (git-bash) / No option to enable colors

    No Colors in Windows (git-bash) / No option to enable colors

    I am new to this package , so i might not know something

    I was using this lib on windows and tried changing styles but this is not showing my err styles.

    image code:

    import numpy
    import stackprinter
    
    
    def dangerous_function(blub):
        return sorted(blub, key=lambda xs: sum(xs))
    
    try:
        somelist = [[1,2], [3,4]]
        anotherlist = [['5', 6]]
        spam = numpy.zeros((3,3))
        dangerous_function(somelist + anotherlist)
    except:
        stackprinter.show(style='darkbg', source_lines=4)
    
    

    is there anything is need in order to get colors working on windows.

    opened by divyanshu-parihar 5
  • 'where' attribute on exceptions?

    'where' attribute on exceptions?

    What is the purpose of this code?

    https://github.com/cknd/stackprinter/blob/fb51f4dbf42e23da80d1d333ceefdd05bb4b3183/stackprinter/frame_formatting.py#L129-L132

    opened by alexmojaki 5
  • error: bad escape \p at position 2

    error: bad escape \p at position 2

    When i try this tracing-a-piece-of-code i get "error: bad escape \p at position 2" Here is my code

    In [214]: a = 1
    
    In [215]: b = 2
    
    In [216]: with stackprinter.TracePrinter(style='darkbg2'):
         ...:     c = a- b
         ...:
    ---------------------------------------------------------------------------
    error                                     Traceback (most recent call last)
    <ipython-input-216-cd5f160fdc24> in <module>
          1 with stackprinter.TracePrinter(style='darkbg2'):
    ----> 2     c = a- b
          3
    
    c:\program files\python36\lib\site-packages\stackprinter\tracing.py in __exit__(self, etype, evalue, tb)
         97         return self
         98
    ---> 99     def __exit__(self, etype, evalue, tb):
        100         self.disable()
        101         if etype is None:
    
    c:\program files\python36\lib\site-packages\stackprinter\tracing.py in trace(self, frame, event, arg)
        127         if 'call' in event:
        128             callsite = frame.f_back
    --> 129             self.show(callsite)
        130             self.show(frame)
        131         elif 'return' in event:
    
    c:\program files\python36\lib\site-packages\stackprinter\tracing.py in show(self, frame, note)
        147
        148         filepath = inspect.getsourcefile(frame) or inspect.getfile(frame)
    --> 149         if match(filepath, __file__):
        150             return
        151         elif match(filepath, self.suppressed_paths):
    
    c:\program files\python36\lib\site-packages\stackprinter\utils.py in match(string, patterns)
         12     elif patterns is None:
         13         return False
    ---> 14     return any([bool(re.search(p, string)) for p in patterns])
         15
         16 def inspect_callable(f):
    
    c:\program files\python36\lib\site-packages\stackprinter\utils.py in <listcomp>(.0)
         12     elif patterns is None:
         13         return False
    ---> 14     return any([bool(re.search(p, string)) for p in patterns])
         15
         16 def inspect_callable(f):
    
    c:\program files\python36\lib\re.py in search(pattern, string, flags)
        180     """Scan through string looking for a match to the pattern, returning
        181     a match object, or None if no match was found."""
    --> 182     return _compile(pattern, flags).search(string)
        183
        184 def sub(pattern, repl, string, count=0, flags=0):
    
    c:\program files\python36\lib\re.py in _compile(pattern, flags)
        299     if not sre_compile.isstring(pattern):
        300         raise TypeError("first argument must be string or compiled pattern")
    --> 301     p = sre_compile.compile(pattern, flags)
        302     if not (flags & DEBUG):
        303         if len(_cache) >= _MAXCACHE:
    
    c:\program files\python36\lib\sre_compile.py in compile(p, flags)
        560     if isstring(p):
        561         pattern = p
    --> 562         p = sre_parse.parse(p, flags)
        563     else:
        564         pattern = None
    
    c:\program files\python36\lib\sre_parse.py in parse(str, flags, pattern)
        853
        854     try:
    --> 855         p = _parse_sub(source, pattern, flags & SRE_FLAG_VERBOSE, 0)
        856     except Verbose:
        857         # the VERBOSE flag was switched on inside the pattern.  to be
    
    c:\program files\python36\lib\sre_parse.py in _parse_sub(source, state, verbose, nested)
        414     while True:
        415         itemsappend(_parse(source, state, verbose, nested + 1,
    --> 416                            not nested and not items))
        417         if not sourcematch("|"):
        418             break
    
    c:\program files\python36\lib\sre_parse.py in _parse(source, state, verbose, nested, first)
        500
        501         if this[0] == "\\":
    --> 502             code = _escape(source, this, state)
        503             subpatternappend(code)
        504
    
    c:\program files\python36\lib\sre_parse.py in _escape(source, escape, state)
        399         if len(escape) == 2:
        400             if c in ASCIILETTERS:
    --> 401                 raise source.error("bad escape %s" % escape, len(escape))
        402             return LITERAL, ord(escape[1])
        403     except ValueError:
    
    error: bad escape \p at position 2
    
    windows 
    opened by mengyyy 5
  • Add support for KeyboardInterrupt in REPL

    Add support for KeyboardInterrupt in REPL

    On keyboard interrupt in REPL, it raises the following stacktrace:

    Error in sys.excepthook:
    Traceback (most recent call last):
      File "/datadrive/product_type_article/venv/lib/python3.7/site-packages/stackprinter/__init__.py", line 245, in hook
        show(args, **kwargs)
      File "/datadrive/product_type_article/venv/lib/python3.7/site-packages/stackprinter/__init__.py", line 23, in show_or_format
        return f(thing, *args, **kwargs)
      File "/datadrive/product_type_article/venv/lib/python3.7/site-packages/stackprinter/__init__.py", line 163, in show
        print(format(thing, **kwargs), file=file)
      File "/datadrive/product_type_article/venv/lib/python3.7/site-packages/stackprinter/__init__.py", line 23, in show_or_format
        return f(thing, *args, **kwargs)
      File "/datadrive/product_type_article/venv/lib/python3.7/site-packages/stackprinter/__init__.py", line 142, in format
        "a frame or a thread object." % repr(thing))
    ValueError: Can't format (<class 'KeyboardInterrupt'>, KeyboardInterrupt(), None). Expected an exception instance, sys.exc_info() tuple,a frame or a thread object.
    
    Original exception was:
    KeyboardInterrupt
    

    I would love to contribute to help out, but I am not sure what the behaviour should be in this case?

    Awesome project BTW.

    opened by YashSinha1996 5
  • Option to prevent line wrap of variable

    Option to prevent line wrap of variable

    Hi, thank you for creating stackprinter! It is really nice.

    I have a question: I'd like to prevent the the line wrap of the variables.

    e.g.

    30      p_mock.assert_called_once = <method 'NonCallableMock.assert_called_once' of <MagicMock i
    30                                   d='88760712'> mock.py:808>
    

    to

    30      p_mock.assert_called_once = <method 'NonCallableMock.assert_called_once' of <MagicMock id='88760712'> mock.py:808>
    

    would it be possible to add a parameter to stackprinter.format that prevents this?

    opened by spacemanspiff2007 4
  •  (Address boundary error)

    (Address boundary error)

    The following code

    import faulthandler
    import pandas as pd
    from pathlib import Path
    import stackprinter
    faulthandler.enable()
    stackprinter.set_excepthook(style='darkbg2')
    pd.read_feather(Path.home() / 'Downloads/job_desc_address_boundary_error.feather')
    

    yields

    Fatal Python error: Segmentation fault
    
    Current thread 0x00007f21755d6740 (most recent call first):
      File "/home/torstein/anaconda3/lib/python3.8/site-packages/stackprinter/extraction.py", line 167 in lookup
      File "/home/torstein/anaconda3/lib/python3.8/site-packages/stackprinter/extraction.py", line 146 in get_vars
      File "/home/torstein/anaconda3/lib/python3.8/site-packages/stackprinter/extraction.py", line 104 in get_info
      File "/home/torstein/anaconda3/lib/python3.8/site-packages/stackprinter/formatting.py", line 164 in <listcomp>
      File "/home/torstein/anaconda3/lib/python3.8/site-packages/stackprinter/formatting.py", line 164 in format_exc_info
      File "/home/torstein/anaconda3/lib/python3.8/site-packages/stackprinter/__init__.py", line 146 in format
      File "/home/torstein/anaconda3/lib/python3.8/site-packages/stackprinter/__init__.py", line 23 in show_or_format
      File "/home/torstein/anaconda3/lib/python3.8/site-packages/stackprinter/__init__.py", line 171 in show
      File "/home/torstein/anaconda3/lib/python3.8/site-packages/stackprinter/__init__.py", line 23 in show_or_format
      File "/home/torstein/anaconda3/lib/python3.8/site-packages/stackprinter/__init__.py", line 257 in hook
    fish: Job 2, 'python rf.py' terminated by signal SIGSEGV (Address boundary error)
    

    while the following code:

    import faulthandler
    import pandas as pd
    from pathlib import Path
    faulthandler.enable()
    pd.read_feather(Path.home() / 'Downloads/job_desc_address_boundary_error.feather')
    

    yields

    Traceback (most recent call last):
      File "rf.py", line 6, in <module>
        pd.read_feather(Path.home() / 'Downloads/job_desc_address_boundary_error.feather')
      File "/home/torstein/anaconda3/lib/python3.8/site-packages/pandas/io/feather_format.py", line 127, in read_feather
        return feather.read_feather(
      File "/home/torstein/anaconda3/lib/python3.8/site-packages/pyarrow/feather.py", line 216, in read_feather
        return (read_table(source, columns=columns, memory_map=memory_map)
      File "/home/torstein/anaconda3/lib/python3.8/site-packages/pyarrow/feather.py", line 238, in read_table
        reader.open(source, use_memory_map=memory_map)
      File "pyarrow/feather.pxi", line 67, in pyarrow.lib.FeatherReader.open
      File "pyarrow/error.pxi", line 141, in pyarrow.lib.pyarrow_internal_check_status
      File "pyarrow/error.pxi", line 97, in pyarrow.lib.check_status
    pyarrow.lib.ArrowInvalid: File is too small to be a well-formed file
    

    I.e. stackprinter causes an address boundary error. stackprinter 0.2.5

    opened by tsoernes 3
  • Stackprinter failed

    Stackprinter failed

    Sometimes, in my repl, stackprinter doesn't work. I found the issue though: in the file /usr/local/lib/python3.8/dist-packages/stackprinter/source_inspection.py, on line 64, sometimes max_line_relative is a float; and this error goes away when you make it an int.

    In other words (talking to the author here), in /usr/local/lib/python3.8/dist-packages/stackprinter/source_inspection.py, could you please change line 64 from:

    max_line_relative = min(len(source_lines), max_line-line_offset)
    

    to

    max_line_relative = int(min(len(source_lines), max_line-line_offset))
    

    Thank you!

    -Ryan

    Btw, here's the error I get:

    Stackprinter failed: File "/usr/local/lib/python3.8/dist-packages/stackprinter/source_inspection.py", line 65, in annotate tokens, head_s, head_e = _tokenize(source_lines[:max_line_relative]) TypeError: slice indices must be integers or None or have an index method

    So here is your original traceback at least:

    Traceback (most recent call last): File "", line 1, in vim(get_module_path('rp.help')) File "/home/ryan/.local/lib/python3.8/site-packages/rp/r.py", line 13146, in get_module_path return get_module_path_from_name(module) File "/home/ryan/.local/lib/python3.8/site-packages/rp/r.py", line 13141, in get_module_path_from_name return importlib.util.find_spec(module_name).origin AttributeError: 'NoneType' object has no attribute 'origin'

    opened by SqrtRyan 3
  • Configurable line wrap

    Configurable line wrap

    This is basically @spacemanspiff2007's PR https://github.com/cknd/stackprinter/pull/30, I just added one more docstring & rebased it

    opened by cknd 3
  • small optimize for util.match

    small optimize for util.match

    opened by spacemanspiff2007 3
  • Option to include the outer stack frames as well?

    Option to include the outer stack frames as well?

    Pythons seems to only include the inner stack frames when you handle an exception, the following article outlines a way to acquire the outer frames as well.

    http://blog.dscpl.com.au/2015/03/generating-full-stack-traces-for.html

    It would be a really great option feature to include in this lib.

    opened by kbirk 3
  • Ignore certain exceptions in `set_excepthook`

    Ignore certain exceptions in `set_excepthook`

    I'd like to make a feature request for passing a list of exceptions to set_excepthook that are either ignored and printed in the standard format or in a minimal style. Useful for KeyboardInterrupt because that's user-triggered and a detailed exception output is often not wanted.

    opened by tsoernes 3
  • Make file paths clickable in PyCharm

    Make file paths clickable in PyCharm

    This makes lines such as

    File "/Users/alexhall/git-repos/stackprinter/demo_chained_exceptions.py", line 7, in bomb

    look exactly the same as regular traceback lines, which makes PyCharm (and possibly other editors) recognise them and turn them into clickable links which jump to the file at the appropriate line in the editor. It looks like this:

    Screen Shot 2019-08-24 at 18 35 19

    The only difference is that the file paths have quotes around them.

    opened by alexmojaki 3
  • Stackprinter doesn't work with Django

    Stackprinter doesn't work with Django

    After installing stackprinter globally, as well as in the django project virtualenvironment And added sitecustomizations.py in the correct paths with the following code:

    import stackprinter
    stackprinter.set_excepthook(style='lightbg')
    

    Still django errors are shown in the conventional style. Any other standalone script shows the stackprinter style. Any help on how to make it work for django?

    opened by amir511 3
  • Stackprinter failed, KeyError: 168

    Stackprinter failed, KeyError: 168

    Stacktrace:

    Stackprinter failed:
      File "/datadrive/product_type_article/venv/lib/python3.7/site-packages/stackprinter/utils.py", line 52, in trim_source
        (snippet0, *meta0), *remaining_line = source_map[ln]
    KeyError: 168
    So here is the original traceback at least:
    
    Traceback (most recent call last):
      File "/usr/local/lib/python3.7/runpy.py", line 193, in _run_module_as_main
        "__main__", mod_spec)
      File "/usr/local/lib/python3.7/runpy.py", line 85, in _run_code
        exec(code, run_globals)
      File "/datadrive/product_type_article/QA/using_gscraper.py", line 204, in <module>
        # main()
      File "/datadrive/product_type_article/QA/using_gscraper.py", line 168, in demo
        except Exception as e:
      File "/datadrive/product_type_article/QA/using_gscraper.py", line 165, in demo
        try:
      File "/datadrive/product_type_article/QA/using_gscraper.py", line 118, in get_possible_answers
        q_processed = get_restriction(ques, suppress=False)
      File "/datadrive/product_type_article/QA/QA_utils.py", line 134, in get_restriction
        raise e
      File "/datadrive/product_type_article/QA/QA_utils.py", line 123, in get_restriction
        rests = parse_question(q)
      File "/datadrive/product_type_article/QA/QA_utils.py", line 119, in <lambda>
        parse_question = lambda q: get_type_rel_pre(get_scored_class_kp(q.lower(), filter_kpe=False, questions=True, only_phrase_rel=True))
      File "/datadrive/product_type_article/QA/QA_utils.py", line 83, in get_type_rel_pre
        raise ValueError("Not a properly parsed Phrase.")
    ValueError: Not a properly parsed Phrase.
    
    
    more info needed 
    opened by YashSinha1996 2
  • Simplify code relating to get_info

    Simplify code relating to get_info

    This essentially 'flattens' the code and makes it a bit easier to understand and reason about. get_info is only called in two places (one of which is hardly needed) and there's less need to check types.

    opened by alexmojaki 2
  • Error when using in sitecustomize.py

    Error when using in sitecustomize.py

    Error in sitecustomize; set PYTHONVERBOSE for traceback:
    AttributeError: module 'numpy' has no attribute '__version__'
    

    Seems like the following line is throwing this error:

      File "/usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/stackprinter/prettyprinting.py", line 13, in <module>
        is_modern_numpy = LooseVersion(np.__version__) >= LooseVersion('1.14')
    AttributeError: module 'numpy' has no attribute '__version__'
    

    My entry for sitecustomize is:

    import stackprinter
    if os.environ.get('VSCODE_PID'):
        stackprinter.set_excepthook()
    else:
        stackprinter.set_excepthook(style='darkbg2')
    
    opened by securisec 2
  • Added possibility to pass the line_wrap as an arg

    Added possibility to pass the line_wrap as an arg

    #28

    opened by spacemanspiff2007 2
  • Add .deepsource.toml and fix some major issues.

    Add .deepsource.toml and fix some major issues.

    DeepSource is free for open-source tool that helps developers and teams write good code. It continuously analyzes code changes on every PR and gives a central dashboard to see code health in terms of issues and important metrics. DeepSource is used by teams at Uber and Stripe, among others.

    I've added a customized .deepsource.toml file for this repo and made some fixes for issues existing in the code highlighted by DeepSource. To keep analyzing code on every change, integration is easy:

    • Merge this PR.
    • Sign up on DeepSource and grant access to this repository here.
    • Activate analysis for this repo here.
    • You can also take a look at the docs.

    Summary of changes

    • remove unnecessary lambda function use.

    • fix dangerous mutable argument.

    • fix statement has no effect.

    • raise NotImplementedError instead of NotImplemented

    opened by mohi7solanki 2
  • Add option to show the parent frames of the exception handling site

    Add option to show the parent frames of the exception handling site

    Following the suggestion by https://github.com/cknd/stackprinter/issues/26 , this adds an option to show caller frames of the frame where an exception is handled (& printerd). By default, Python tracebacks only show the frames below the exception handling site (i.e. you only only see what happened inside your try block, but you don't see which prior calls have led to that block). This option adds such parent frames to the printout.

    It seems to be helpful in this case and things like this Qt example

    opened by cknd 2
  • Use tb_or_frame instead of undefined tb

    Use tb_or_frame instead of undefined tb

    This code:

    from stackprinter.extraction import get_info
    
    get_info(None)
    

    raises:

    Traceback (most recent call last):
      File "/Users/alexhall/Library/Preferences/PyCharm2018.3/scratches/scratch_421.py", line 3, in <module>
        get_info(None)
      File "/Users/alexhall/git-repos/stackprinter/stackprinter/extraction.py", line 73, in get_info
        raise ValueError('Cant inspect this: ' + repr(tb))
    UnboundLocalError: local variable 'tb' referenced before assignment
    

    This PR changes it to the correct:

    ValueError: Cant inspect this: None
    
    opened by alexmojaki 1
  • Fix ValueError while formatting None-tuple exception

    Fix ValueError while formatting None-tuple exception

    It's a possible fix for #35.

    opened by Delgan 1
  • create bug reproducer

    create bug reproducer

    Is there any way to create a minimal reproducer for the exception using stackprinter. In addition to the variable values, printing a minimal reproducer would help to isolate the problem

    opened by rsudarson 1
  • Use attributes of FrameFormatter directly instead of passing around lots of arguments

    Use attributes of FrameFormatter directly instead of passing around lots of arguments

    This is less redundant and should make future refactoring easier.

    opened by alexmojaki 1
  • fixed explicitly

    fixed explicitly

    opened by 0xflotus 1
  • Slight refactoring of format_stack

    Slight refactoring of format_stack

    Just making things a little less repetitive. Mostly a matter of preference.

    opened by alexmojaki 1
  • Allow patching stderr

    Allow patching stderr

    People often 'redirect' stderr by replacing it with something else. This ensures that that works with the default settings. Here's a script to demonstrate the difference:

    import sys
    from io import StringIO
    import stackprinter
    
    sys.stderr = s = StringIO()
    
    try:
        1 / 0
    except:
        stackprinter.show()
    
    print(repr(s.getvalue()))
    
    opened by alexmojaki 1
  • Cleanup debug formatting

    Cleanup debug formatting

    define type-specific formatting logic down where it belongs, in the type definition

    opened by cknd 0
  • Add a way to redact some variables

    Add a way to redact some variables

    Hey there,

    I'm considering using stackprinter at my company to help with some debugging tasks. Its output would be in our logs, and thus be sent to DataDog. But we don't really want to do that unless we have more control over the output.

    More specifically: we want to redact some variables based on their name, because they can contain sensitive user data. For instance, content or *_token are replaced by "******" in our current system and in Sentry, and I'd like to do the same with stackprinter.

    Is there already a way to do that? If not, what would be a good way to add such a filter?

    Thanks!

    opened by Schnouki 2
  • Split exception formatting into two phases

    Split exception formatting into two phases

    ...one to format each frame and exception message, one to assemble the final string.

    perhaps a step towards a feature where it returns somewhat more structured data

    work-in-progress 
    opened by cknd 0
  • Catch wrong linenos

    Catch wrong linenos

    Catch an (crashing #45 ) edge case where the frame's current line numer is wrong, or the discoverd line number where the frame's code block starts is. This looks like a python bug or an inspect.getsource bug -- OR a getsource bug that is ultimately a python bug, because inspect just uses frame.f_code.co_firstlineno (= the frame's own reported beginning of its code block), and I can't imagine a situation where that can legitimately not contain frame.f_lineno.

    I deal with this here by showing a warning in-band that the line number can't be 100% trusted, while also moving the active line shown down to the first available source line.

    (Not completely happy with that solution, of course)

    opened by cknd 0
  • Fail when using taichi (Exception: Picked an invalid source context)

    Fail when using taichi (Exception: Picked an invalid source context)

    Your package is so useful that I stop using ipython anymore. Thank you!

    I start using taichi recently and I encounter an error, the minimal sample is list below.

    import stackprinter
    import taichi as ti
    
    stackprinter.set_excepthook(style="darkbg2")
    
    
    @ti.kernel
    def my_kernel() -> float:
        return "22"
    
    
    my_kernel()
    
    opened by WangWei90 10
  • use github actions for testing

    use github actions for testing

    This switches to github actions for testing since travis changed their free testing. It also adds a workflow which will automatically publish on pypi if you create a release on github. All you have to do is add a secret in your repo settings and add an api key you created in pypi.

    The secret has to be named "pypi_api_key" Here is the guide I used but I used a proper name for the secret.

    opened by spacemanspiff2007 1
  • Stackprinter shows full log for suppressed_paths

    Stackprinter shows full log for suppressed_paths

    In my application stackprinter ignores the passed in supressed_paths and I am not sure why (this has already worked and I am not sure what changed). I can't seem to create a short snippet which reproduces the error but in my application it fails every time.

    This is the function where I get the traceback. If I set a break point with the debugger I see that suppressed_paths is indeed properly populated. However if I inspect the returned lines I see the traceback with the included library files.

    grafik

    I have created a testcase for pytest which fails every time.

    Excerpt from github actions (just open the tox part in line 12)

      ERROR    WrapperTest:wrapper.py:179 File "/opt/hostedtoolcache/Python/3.9.0/x64/lib/python3.9/asyncio/base_events.py", line 1056, in create_connection
      ERROR    WrapperTest:wrapper.py:179     967  async def create_connection(
      ERROR    WrapperTest:wrapper.py:179     968          self, protocol_factory, host=None, port=None,
      ERROR    WrapperTest:wrapper.py:179     969          *, ssl=None, family=0,
      ERROR    WrapperTest:wrapper.py:179     970          proto=0, flags=0, sock=None,
    
    I tried to recreate the issue with a snipped but the library files are correctly ignored here, so I am confident that my regexes are correct and that I pass in the parameters correctly.
    from pathlib import Path
    
    import aiohttp, typing
    import asyncio
    import re
    import stackprinter
    
    SUPPRESSED_PATHS = (
        re.compile(f'[/\\\\]{Path(__file__).name}$'),   # this file
    
        # rule file loader
        re.compile(r'[/\\]rule_file.py$'),
        re.compile(r'[/\\]runpy.py$'),
    
        # Worker functions
        re.compile(r'[/\\]wrappedfunction.py$'),
    
        # Don't print stack for used libraries
        re.compile(r'[/\\](site-packages|lib)[/\\]asyncio[/\\]'),
        re.compile(r'[/\\]site-packages[/\\]aiohttp[/\\]'),
        re.compile(r'[/\\]site-packages[/\\]voluptuous[/\\]'),
        re.compile(r'[/\\]site-packages[/\\]pydantic[/\\]'),
    )
    SKIP_TB = tuple(re.compile(k.pattern.replace('$', ', ')) for k in SUPPRESSED_PATHS)
    
    
    def format_exception(e: typing.Union[Exception, typing.Tuple[typing.Any, typing.Any, typing.Any]]) -> typing.List[str]:
        tb = []
        skip = 0
    
        lines = stackprinter.format(e, line_wrap=0, truncate_vals=2000, suppressed_paths=SUPPRESSED_PATHS).splitlines()
        for i, line in enumerate(lines):
            if not skip:
                for s in SKIP_TB:
                    if s.search(line):
                        # if it's just a two line traceback we skip it
                        if lines[i + 1].startswith('    ') and lines[i + 2].startswith('File'):
                            skip = 2
                            continue
            if skip:
                skip -= 1
                continue
    
            tb.append(line)
    
        return tb
    
    
    class PrintException:
        def __enter__(self):
            pass
    
        def __exit__(self, exc_type, exc_val, exc_tb):
            # no exception -> we exit gracefully
            if exc_type is None and exc_val is None:
                return True
            for l in format_exception((exc_type, exc_val, exc_tb)):
                print(l)
            return True
    
    
    def test_run():
        async def test():
            async with aiohttp.ClientSession(timeout=aiohttp.ClientTimeout(0.01)) as session:
                async with session.get('http://localhost:12345') as resp:
                    pass
    
        with PrintException():
            asyncio.get_event_loop().run_until_complete(test())
    

    Do you have any idea what the issue might be? It would be really nice if you could check out the dev branch and run pytest on the test_wrapper.py file.

    The tests need the following libraries additionally to the ones in requirements.txt: pytest pytest-asyncio asynctest

    opened by spacemanspiff2007 18
  • Switch CI provider

    Switch CI provider

    travis-ci.org (as opposed to com) seems to use a deprecated api to talk to github, and so status reports don't always show up on PR pages (https://travis-ci.community/t/github-status-not-posted-on-commits-on-repositories-using-legacy-service-integration/7798). Migrating to .com (where they use the newer stuff) looks at least as painful as just using something else (like github)

    opened by cknd 1
  • Empty stacktrace

    Empty stacktrace

    Maybe I missed something when reading through your README, but I am getting an empty stack trace.

    image

    I followed your example in your README, but this is what I see. I tried previous versions (0.2.0, 0.1.1), but got an empty trace as well. I tried this on both Python 3.7.7 and Python 3.8.5 with no change.

    opened by JulianOrteil 15
  • Consider pprintpp

    Consider pprintpp

    I just learned about this package: https://github.com/wolever/pprintpp

    Seems like it could be useful here.

    opened by alexmojaki 0
  • Integration of stack_data

    Integration of stack_data

    As discussed in #22

    This is still very much a WIP, but you can run the demos and see output that looks right until you inspect it more closely. I'm putting some work out early so you can see what's coming and we can start some conversations. To try it out, clone https://github.com/alexmojaki/stack_data and pip install -e <path to folder> in your interpreter where you work on stackprinter.

    A couple of perks you can already observe:

    • The function name is replaced by its __qualname__ thanks to executing.
    • Source lines in classes show correctly. For example, try this script in master:
    try:
        class A:
            1 / 0
    except:
        stackprinter.show()
    

    It shows something like this:

    File "path.py", line 16, in A
    
    ZeroDivisionError: division by zero
    

    The source line 1 / 0 and its context are absent. This is now fixed.

    Things I plan on doing soon which should be quite quick and easy:

    1. Connect stackprinter configuration to stack_data configuration.
    2. Select variables to show
    3. Ordering variables
    4. Hide signature for non-function scopes.

    Changes we need to discuss:

    1. For displaying expressions other than variables, e.g. attributes, I want to make another package called pure_eval which accepts an AST node and returns a bunch of sub-expressions which can be safely evaluated without triggering any side effects and their corresponding values. This will include for example attributes which are simply present in __dict__ (no properties) or subscripts a[b] where a has a known type like a list or dict. I think it's dangerous to evaluate arbitrary attributes like you're doing now because this risks mutating the state of the program which could interfere with someone's debugging. better-exceptions has a similar view - they are currently trying to integrate the display of attributes but only using getattr_static. With this in mind there would no longer be such a thing as UnresolvedAttribute.
    2. The context lines included are slightly different. Files are divided into 'pieces' which are ranges of lines representing either a single simple statement or a part of a compound statement (loops, if, try/except, etc) that doesn't contain any other statements. Most pieces are a single line, but a multi-line statement or if condition is a single piece. Context is measured in numbers of pieces, e.g. the default is to include 3 pieces before and 1 piece after. This may be more than 5 lines total but the advantage is that tracebacks don't truncate statements or other groups of lines that should logically be together. However if you have a very long piece then it may be truncated in the middle to avoid arbitrarily long tracebacks.
    3. I'd like to add an indication of which node in a frame was executing where possible using the executing library. The simplest way is to add a line such as While calling: foo() to each frame. This is probably the only decent option when there's no color. With color, there's the possibility of highlighting the expression similar to what heartrate does. However given that the expression may contain multiple variables with random colors this will probably be hard to do in a way that's reliably readable.
    4. Normal bits of source code are not currently highlighted in the 'default' color of a color scheme. They're just not highlighted at all. Should I find a way to put that back?
    5. Line continuations using backslashes are not collapsed. You seemed unsure, and I don't think it was a good idea. Let people read their code the way they wrote it and are familiar with. I don't know how I would implement it in the current framework anyway.
    opened by alexmojaki 14
Releases(0.2.5)
  • 0.2.5(Oct 31, 2020)

    Fixed

    • Allows passing (None, None, None) to format_exception
    • Fixed a crashing type error that could occur in longer code scopes (e.g. in the repl)
    Source code(tar.gz)
    Source code(zip)
  • 0.2.4(Jun 17, 2020)

    Changed

    • Disabled verbose formatting for KeyboardInterrupts by default. Call format(..., suppressed_exceptions=None) to enforce verbose printing even on a keyboard interrupt.

    Added

    • New keyword arg suppressed_exceptions to disable verbose formatting for certain types of exceptions (generating a standard python-like traceback instead).
    • New keyword arg line_wrap to adjust or disable the line wrap on variable values.
    Source code(tar.gz)
    Source code(zip)
Owner
Clemens Korndörfer
CogSci, neurons, ML, robots
Clemens Korndörfer
Pretty-print tabular data in Python, a library and a command-line utility. Repository migrated from bitbucket.org/astanin/python-tabulate.

python-tabulate Pretty-print tabular data in Python, a library and a command-line utility. The main use cases of the library are: printing small table

Sergey Astanin 1.1k Feb 20, 2022
Progressbar 2 - A progress bar for Python 2 and Python 3 - "pip install progressbar2"

Text progress bar library for Python. Travis status: Coverage: Install The package can be installed through pip (this is the recommended method): pip

Rick van Hattem 757 Feb 21, 2022
Python logging made (stupidly) simple

Loguru is a library which aims to bring enjoyable logging in Python. Did you ever feel lazy about configuring a logger and used print() instead?... I

null 11.1k Feb 20, 2022
The new Python SDK for Sentry.io

sentry-python - Sentry SDK for Python This is the next line of the Python SDK for Sentry, intended to replace the raven package on PyPI. from sentry_s

Sentry 1.2k Feb 22, 2022
A Fast, Extensible Progress Bar for Python and CLI

tqdm tqdm derives from the Arabic word taqaddum (تقدّم) which can mean "progress," and is an abbreviation for "I love you so much" in Spanish (te quie

tqdm developers 21.2k Feb 21, 2022
Rich is a Python library for rich text and beautiful formatting in the terminal.

Rich 中文 readme • lengua española readme • Läs på svenska Rich is a Python library for rich text and beautiful formatting in the terminal. The Rich API

Will McGugan 35.2k Feb 21, 2022
Structured Logging for Python

structlog makes logging in Python faster, less painful, and more powerful by adding structure to your log entries. It's up to you whether you want str

Hynek Schlawack 1.9k Feb 22, 2022
Json Formatter for the standard python logger

Overview This library is provided to allow standard python logging to output log data as json objects. With JSON we can make our logs more readable by

Zakaria Zajac 1.2k Feb 20, 2022
A colored formatter for the python logging module

Log formatting with colors! colorlog.ColoredFormatter is a formatter for use with Python's logging module that outputs records using terminal colors.

Sam Clements 732 Feb 18, 2022
Colored terminal output for Python's logging module

coloredlogs: Colored terminal output for Python's logging module The coloredlogs package enables colored terminal output for Python's logging module.

Peter Odding 451 Feb 21, 2022
Prettify Python exception output to make it legible.

pretty-errors Prettifies Python exception output to make it legible. Install it with python -m pip install pretty_errors If you want pretty_errors to

Iain King 2.5k Feb 26, 2022
A small utility to pretty-print Python tracebacks. ⛺

TBVaccine TBVaccine is a utility that pretty-prints Python tracebacks. It automatically highlights lines you care about and deemphasizes lines you don

Stavros Korokithakis 365 Feb 10, 2022
A cool logging replacement for Python.

Welcome to Logbook Travis AppVeyor Supported Versions Latest Version Test Coverage Logbook is a nice logging replacement. It should be easy to setup,

null 1.4k Feb 20, 2022
ClusterMonitor - a very simple python script which monitors and records the CPU and RAM consumption of submitted cluster jobs

ClusterMonitor A very simple python script which monitors and records the CPU and RAM consumption of submitted cluster jobs. Usage To start recording

null 23 Oct 4, 2021
Json Formatter for the standard python logger

This library is provided to allow standard python logging to output log data as json objects. With JSON we can make our logs more readable by machines and we can stop writing custom parsers for syslog type records.

Zakaria Zajac 1k Jul 14, 2021
A simple, transparent, open-source key logger, written in Python, for tracking your own key-usage statistics.

A simple, transparent, open-source key logger, written in Python, for tracking your own key-usage statistics, originally intended for keyboard layout optimization.

Ga68 35 Feb 15, 2022
Robust and effective logging for Python 2 and 3.

Robust and effective logging for Python 2 and 3.

Chris Hager 1k Jan 22, 2022
Python logging package for easy reproducible experimenting in research

smilelogging Python logging package for easy reproducible experimenting in research. Why you may need this package This project is meant to provide an

Huan Wang 20 Feb 3, 2022
A basic logging library for Python.

log.py ?? About: A basic logging library for Python with the capability to: save to files. have custom formats. have custom levels. be used instantiat

Sebastiaan Bij 1 Jan 19, 2022