A small utility to pretty-print Python tracebacks. ⛺

Overview

TBVaccine

TBVaccine is a utility that pretty-prints Python tracebacks. It automatically highlights lines you care about and deemphasizes lines you don't, and colorizes the various elements in a traceback to make it easier to parse.

Here are some screenshots. This is the before:

misc/before.png

And this is the after:

misc/after.png

If you add the hook or call TBVaccine in your code, it can also print all variables in each stack frame. That is, it turns this:

misc/before-vars.png

into this:

misc/after-vars.png

Installation

To install, use pip:

pip install tbvaccine

You are done!

Global usage

You can have TBVaccine insert itself all up in your system and stick its tentacles in all your libraries, like a cute, useful Cthulhu. That way, every single Python traceback in your system will be pretty. Just set the TBVACCINE environment variable to 1, and you're done.

E.g. for bash:

export TBVACCINE=1

Or fish:

set -x TBVACCINE=1

If you want to prettify tracebacks even when stderr is not a tty, set TBVACCINE_FORCE to 1:

export TBVACCINE=1
export TBVACCINE_FORCE=1
python -c '1/0' 2>&1 | cat  # pretty!

NOTE: If you're on Ubuntu, you most likely have Apport installed, which overrides TBVaccine's hook with its own. To disable Apport for Python, delete a file named /etc/python<version>/sitecustomize.py. Note that this will disable Apport for Python, and you won't be asked to submit info to Ubuntu when Python programs crash any more. For some, this is a good thing.

Usage as a command-line utility

TBVaccine can be used from the command line several ways.:

python -m tbvaccine myscript.py

Or just pipe STDERR into it from the program you want to watch:

./myscript.py 2>&1 | tbvaccine

And all the tracebacks will now be pretty!

Usage as a Python library

There are various ways to use TBVaccine as a Python library.

Initialize it like so:

from tbvaccine import TBVaccine
tbv = TBVaccine(
    code_dir="/my/code/dir",
    isolate=True
)

code_dir marks the directory we code about. Files under that directory that appear in the traceback will be highlighted. If not passed, the current directory, as returned by os.getcwd() will be used.

If isolate is False, all lines are colorized, and code_dir is ignored.

If show_vars is False, variables will not be printed in each stack frame.

To use it in an except block:

from tbvaccine import TBVaccine
try:
    some_stuff()
except:
    print(TBVaccine().format_exc())

To make it the default way of printing tracebacks, use add_hook() (which also accepts any argument the TBVaccine class does):

import tbvaccine
tbvaccine.add_hook(isolate=False)

1 / 0

Bam! Instant pretty tracebacks.

Logging integration

You can integrate TBVaccine with logging like so:

class TbVaccineFormatter(logging.Formatter):
    def  formatException(self, exc_info):
        return TBVaccine(isolate=True).format_exc()

sh = logging.StreamHandler()
sh.setFormatter(TbVaccineFormatter('[%(levelname)s] %(asctime)s : %(message)s', '%Y-%m-%d %H:%M:%S'))
logger.addHandler(sh)

Configuration

To configure TBVaccine, open its configuration file in ~/.config/tbvaccine/tbvaccine.cfg (or your operating system's equivalent) and edit it. You can currently configure the color style there by specifying one of the Pygments styles <http://pygments.org/demo/6778888/?style=monokai>.

Epilogue

This library is still pretty new, please contribute patches if something doesn't work as intended, and also please tell your friends about it! Hopefully one day it will be implemented in the Python interpreters themselves.

-- Stavros

Comments
  • switching on and off using an environment variable

    switching on and off using an environment variable

    If tbvaccine provides (e.g.) a tbvaccine.pth file with contents similar to

    import os; exec("if os.environ.get('TBVACCINE'):\n    <activation code>")
    

    this would make it much easier to switch its functionality on and off without having to modify the "vaccined" code. You could even load the kwargs to TBVaccine from the environment variable, say as json: see https://github.com/anntzer/mplcursors/blob/master/setup.py for a self-contained example.

    help wanted 
    opened by anntzer 10
  • Cap long lines

    Cap long lines

    I'm having issues where I have very long variables (like a spreadsheet loaded in memory) and so when TBVaccine prints that, I lose everything else in my console buffer. Here is a quick and dirty hack to cap line length. It works by dropping ANSI sequences from long variable lines, and cap their length at 79*4 chars (approx. 4 output lines). A note is added to the line that there is more un-printed data.

    (I can't figure out how to get decent lengths with normal string slicing on strings with ANSI codes embedded. For example, the output line | __annotations__ = {} clocks in with a length of 148 (!) due to ANSI control codes.)

    The downside of dropping ANSI sequences like this is that the line won't be coloured....

    opened by MinchinWeb 6
  • ValueError: max() arg is an empty sequence

    ValueError: max() arg is an empty sequence

    Executing:

    def x():
        raise Exception('hello')
    
    def a(b):
        b()
    
    a(x)
    
    d:\...>python -m tbvaccine test_stack_trace.py
    Error in sys.excepthook:
    Traceback (most recent call last):
      File "d:\...\tbvaccine\tbv.py", line 193, in print_exception
        formatted = self._format_tb_string_with_locals(etype, value, tb)
      File "d:\...\tbvaccine\tbv.py", line 173, in _format_tb_string_with_locals
        max_length = max([len(x[0]) for x in var_tuples])
    ValueError: max() arg is an empty sequence
    
    Original exception was:
    Traceback (most recent call last):
      File "C:\...\lib\runpy.py", line 193, in _run_module_as_main
        "__main__", mod_spec)
      File "C:\...\lib\runpy.py", line 85, in _run_code
        exec(code, run_globals)
      File "d:\...\tbvaccine\__main__.py", line 67, in <module>
        exec(code, variables, variables)
      File "test_stack_trace.py", line 7, in <module>
        a(x)
      File "test_stack_trace.py", line 5, in a
        b()
      File "test_stack_trace.py", line 2, in x
        raise Exception('hello')
    Exception: hello
    
    opened by szabolcsdombi 6
  • Running tbvaccine on non python file - colors don't work

    Running tbvaccine on non python file - colors don't work

    By mistake I just called python -m tbvaccine tox.ini.

    The trace has no colors and it is longer then 100 lines, however calling python directly on a non python file causes only 4 lines for a single exception.

    image

    It would be great if tbvaccine could detect when a non python file is passed.

    opened by szabolcsdombi 5
  • Simplify isatty

    Simplify isatty

    IOBase.stderr() has existed from at latest Python 2.7.4 and 3.1 (https://github.com/python/cpython/commit/4fa88fa0b), so sys.stderr.isatty() likely exists.

    opened by wataash 3
  • Support force-enable (even when not isatty)

    Support force-enable (even when not isatty)

    Hi, thanks for creating this great library!

    I want to use this library in a kubernetes container where stderr is not a tty. It'll be convenient if we can do force-enabling by setting an environment variable.

    opened by wataash 3
  • How to integrate with flask or logging?

    How to integrate with flask or logging?

    It no effect when exception raised in flask request because the tracebacks are formatted by logging, the sys.excepthook is not called.

    eg:

    import tbvaccine
    from flask import Flask
    
    tbvaccine.add_hook(isolate=True)
    app = Flask(__name__)
    
    
    @app.route('/')
    def index():
        return 1 / 0
    
    
    if __name__ == '__main__':
        app.run()
    

    the outputs:

     * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
    [2017-06-01 21:59:08,086] ERROR in app: Exception on / [GET]
    Traceback (most recent call last):
      File "/home/guyskk/.local/share/virtualenvs/next_passport-OfYZSIo0/lib/python3.6/site-packages/flask/app.py", line 1982, in wsgi_app
        response = self.full_dispatch_request()
      File "/home/guyskk/.local/share/virtualenvs/next_passport-OfYZSIo0/lib/python3.6/site-packages/flask/app.py", line 1614, in full_dispatch_request
        rv = self.handle_user_exception(e)
      File "/home/guyskk/.local/share/virtualenvs/next_passport-OfYZSIo0/lib/python3.6/site-packages/flask/app.py", line 1517, in handle_user_exception
        reraise(exc_type, exc_value, tb)
      File "/home/guyskk/.local/share/virtualenvs/next_passport-OfYZSIo0/lib/python3.6/site-packages/flask/_compat.py", line 33, in reraise
        raise value
      File "/home/guyskk/.local/share/virtualenvs/next_passport-OfYZSIo0/lib/python3.6/site-packages/flask/app.py", line 1612, in full_dispatch_request
        rv = self.dispatch_request()
      File "/home/guyskk/.local/share/virtualenvs/next_passport-OfYZSIo0/lib/python3.6/site-packages/flask/app.py", line 1598, in dispatch_request
        return self.view_functions[rule.endpoint](**req.view_args)
      File "app.py", line 10, in index
        return 1 / 0
    ZeroDivisionError: division by zero
    127.0.0.1 - - [01/Jun/2017 21:59:08] "GET / HTTP/1.1" 500 -
    
    opened by guyskk 2
  • TBVaccine in pipe mode is broken

    TBVaccine in pipe mode is broken

    $ echo 1 | tbvaccine
    Traceback (most recent call last):
      File "/mnt/storage/miniconda3/envs/CloudSML-Computational-Backend/bin/tbvaccine", line 11, in <module>
        sys.exit(main())
      File "/mnt/storage/miniconda3/envs/CloudSML-Computational-Backend/lib/python3.5/site-packages/tbvaccine/cli.py", line 29, in main
        output = tbv.process_line(line)
    AttributeError: 'TBVaccine' object has no attribute 'process_line'
    
    opened by frol 2
  • Integration with IDEs

    Integration with IDEs

    Hello there! Thank you very much for your work.

    I'd like to get it to work in PyCharm, alas it's not trigerring at all there, but it works in consoles. Any advice here? :)

    opened by Day0Dreamer 1
  • Hooked by TBVACCINE=0 is confusing

    Hooked by TBVACCINE=0 is confusing

    README says export TBVACCINE=1 hooks tbvaccine, so I expected export TBVACCINE=0 would not hook, but it did. I think the hook should be done only if TBVACCINE is exactly 1. (but that's a breaking change...)

    opened by wataash 1
  • Fix CodeShelter link

    Fix CodeShelter link

    Otherwise it was a relative link, and so was returning a GitHub 404 error page. --> https://github.com/skorokithakis/tbvaccine/blob/master/www.codeshelter.co

    opened by MinchinWeb 1
  • Add hyperlinks to source files in traceback

    Add hyperlinks to source files in traceback

    There is a specification for hyperlinks in terminals

    https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda

    It would be good if TBVacine could link to the python files mentioned.

    Currently there isn't a way of linking to particular lines, but being able to open a file from the terminal is a nice improvement.

    This may be worth gating behind config or envvar in case a terminal doesn't support it (though most should display nothing where the link will be anyway)

    opened by stuaxo 5
  • On Ubuntu 16.04, with Python 2.7, performance impact is non-trivial

    On Ubuntu 16.04, with Python 2.7, performance impact is non-trivial

    Without adding hook to my module (tgv):

    Traceback (most recent call last): File "./tgv.py", line 618, in if name == "main": tgv() File "./tgv.py", line 426, in tgv 1/0 ZeroDivisionError: integer division or modulo by zero

    real 0m2.904s user 0m2.344s sys 0m0.536s

    With hook added

    Traceback (most recent call last): File "./tgv.py", line 618, in if name == "main": tgv() <6 variables printed> File "./tgv.py", line 426, in tgv 1/0 <20 odd variables> ZeroDivisionError: integer division or modulo by zero

    real 0m30.856s user 0m29.192s sys 0m1.572s

    I'm guessing mostly the perf degradation is due to the high count of variables being printed. Anyway to control the output?

    opened by anandr165 3
  • ipython integration

    ipython integration

    There's at least a couple problems with this working with ipython.

    1. Exporting the env var seems to have no effect.
    2. This brings the formatting of tbvaccine, and some things, but not the locals I added in the shell.
    from tbvaccine import TBVaccine 
    try:
        some_stuff()
    except:
        print(TBVaccine().format_exc())
    

    imagine this is styled:

    Traceback (most recent call last):
      File "<ipython-input-2-6c94a79ed40f>", line 4, in <module>
    >   some_stuff()
    |     __annotations__ = {}
    |     __builtins__    = <module 'builtins' (built-in)>
    |     __cached__      = None
    |     __doc__         = None
    |     __file__        = [path to]/bin/ipython
    |     __loader__      = <_frozen_importlib_external.SourceFileLoader object at 0x7f880a16fc88>
    |     __name__        = __main__
    |     __package__     = None
    |     __spec__        = None
    |     re              = <module 're' from '[path to]/lib/python3.6/re.py'>
    |     start_ipython   = <function start_ipython at 0x7f88069a18c8>
    |     sys             = <module 'sys' (built-in)>
    NameError: name 'some_stuff' is not defined
    
    
    1. This seems to not be any different from a normal exception in ipython. It looks identical either way.
    import tbvaccine
    tbvaccine.add_hook(isolate=False)
    
    1 / 0
    

    The same seems to hold for at least flask-shell-ipython, which is unsurprising.

    Possibly out-of-scope: I have no idea really, but maybe whatever is needed to get this to work would also suffice for Jupyter as well. If we're lucky.

    opened by nixjdm 4
  • [feature request] settings on displaying local variables

    [feature request] settings on displaying local variables

    All local variables displayed on each stack frame lead to huge unreadable stack pretty fast. You could add a setting to display or not display them. Also, displaying functions and modules does not seem so helpful. You might get rid of them, or add a distinct setting to display them too.

    enhancement 
    opened by afeblot 3
  • Support Python 3's 'raise Exception from e'?

    Support Python 3's 'raise Exception from e'?

    It's not clear if tbvaccine supports Python 3's 'raise MyException from e' syntax.

    Or at least the original exception is not being emitted in the tbvaccine output.

    opened by dsully 5
  • TBVaccine produces insane reporting when Dask or Dask Distributed task crashes

    TBVaccine produces insane reporting when Dask or Dask Distributed task crashes

    Here is the reproduction:

    import tbvaccine
    tbvaccine.add_hook(isolate=False)
    
    import dask
    
    def x(arg1=123):
        assert arg1 == 122, "qwe"
    
    if __name__ == '__main__':
        dask.delayed(x)().compute()
    

    The error:

      File "/tmp/env/lib/python3.5/site-packages/dask/async.py", line 272, in _execute_task
        return func(*args2)
      File "qq5.py", line 7, in x
        assert arg1 == 122, "qwe"
    |     worker_id                = None
    AssertionError: qwe
    

    I don't understand at all where worker_id came from.

    Running Dask Distributed, I see the output, which reports things which don't exist in that scope at all...

    import tbvaccine
    tbvaccine.add_hook(isolate=False)
    
    import dask
    import dask.distributed
    
    
    def x(arg1=123):
        assert arg1 == 122, "qwe"
    
    if __name__ == '__main__':
        client = dask.distributed.Client()
        dask.delayed(x)().compute(get=client.get)
    
      File "/tmp/env/lib/python3.5/site-packages/dask/base.py", line 203, in compute
        results = get(dsk, keys, **kwargs)
    |     x = b'\x80\x04\x95\xa1\x00\x00\x00\x00\x00\x00\x00\x8c\x16tblib.pickling_support\x94\x8c\x12unpickle_traceback\x94\x93\x94\x8c\x05tblib\x94\x8c\x05Frame\x94\x93\x94)\x81\x94}\x94(\x8c\x06f_code\x94h\x03\x8c\x04Code\x94\x93\x94)\x81\x94}\x94(\x8c\x07co_name\x94\x8c\x01x\x94\x8c\x0bco_filename\x94\x8c\x06qq4.py\x94ub\x8c\tf_globals\x94}\x94ubK\tN\x87\x94R\x94.'
      File "/tmp/env/lib/python3.5/site-packages/distributed/client.py", line 1590, in get
        resources=resources)
    |     ret       = <tblib.Traceback object at 0x7f95aeadfcf8>
    |     tb_frame  = <tblib.Frame object at 0x7f95aeadf908>
    |     tb_lineno = 9
    |     tb_next   = None
      File "/tmp/env/lib/python3.5/site-packages/distributed/utils.py", line 223, in sync
        six.reraise(*error[0])
    |     code   = <code object x at 0x7f95aeb33270, file "qq4.py", line 9>
    |     f_code = <tblib.Code object at 0x7f95aeadf9b0>
    |     self   = <tblib.Traceback object at 0x7f95aeadfcf8>
    |     tb     = <traceback object at 0x7f95aeaeb148>
      File "/tmp/env/lib/python3.5/site-packages/six.py", line 686, in reraise
        raise value
    AssertionError: qwe
    

    The direct call to x() produces a sane output, so it should be some magic involved with Dask. Better-Exceptions module just hangs in this situation, so TBVaccine is better in this respect, but it is still completely misleading and unhelpful.

    opened by frol 0
Releases(v0.2.2)
Owner
Stavros Korokithakis
I love writing code, making stupid devices and writing about writing code and making stupid devices.
Stavros Korokithakis
Pretty and useful exceptions in Python, automatically.

better-exceptions Pretty and more helpful exceptions in Python, automatically. Usage Install better_exceptions via pip: $ pip install better_exception

Qix 4.3k Dec 29, 2022
Multi-processing capable print-like logger for Python

MPLogger Multi-processing capable print-like logger for Python Requirements and Installation Python 3.8+ is required Pip pip install mplogger Manual P

Eötvös Loránd University Department of Digital Humanities 1 Jan 28, 2022
Small toolkit for python multiprocessing logging to file

Small Toolkit for Python Multiprocessing Logging This is a small toolkit for solving unsafe python mutliprocess logging (file logging and rotation) In

Qishuai 1 Nov 10, 2021
Lazy Profiler is a simple utility to collect CPU, GPU, RAM and GPU Memory stats while the program is running.

lazyprofiler Lazy Profiler is a simple utility to collect CPU, GPU, RAM and GPU Memory stats while the program is running. Installation Use the packag

Shankar Rao Pandala 28 Dec 9, 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 795 Dec 18, 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 13.7k Jan 2, 2023
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.4k Dec 31, 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 23.7k Jan 1, 2023
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 41.5k Jan 7, 2023
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 2.3k Jan 5, 2023
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.4k Jan 4, 2023
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 778 Dec 26, 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 496 Dec 30, 2022
Debugging-friendly exceptions for Python

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 v

Clemens Korndörfer 1.2k Dec 28, 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.6k Jan 4, 2023
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 Nov 11, 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 56 Jan 3, 2023