GithubHelp home page GithubHelp logo

stackprinter's Introduction

build

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 rarely use this locally instead of a real debugger, but 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 few source lines & the function header, and only the variables that appear in those lines, and using 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

Option 1: Set and forget

To replace the default python crash printout, call set_excepthook() somewhere once. Afterwards, any uncaught exception will be printed with an extended traceback (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'

Option 2: Call it selectively during exception handling

For more control, call show() or format() inside an except block. show() prints to stderr, 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)

Config options

format(), show() and set_excepthook() accept a common set of keyword args. They allow you to tweak the formatting, hide certain variables by name, skip variables in calls within certain files, and some other stuff.

try:
    something()
except RuntimeError as exc:
    stackprinter.show(exc, suppressed_vars=[r".*secret.*"],
                           suppressed_paths=[r"lib/python.*/site-packages/boringstuff"],
                           truncate_vals=9001,
                           style="darkbg2")

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

Option 3: Integrate with the standard logging module

With a bit of extra plumbing you can log errors like this via the normal logging methods, without having to import stackprinter at the site of the logging call. So you can continue to write nice and simple error handlers like so...

logger = logging.getLogger()
try:
    nothing = {}
    dangerous_function(nothing.get("something"))
except:
    logger.exception('My hovercraft is full of eels.')

...but still get annotated tracebacks in the resulting log.

2022-04-02 16:16:40,905 ERROR: My hovercraft is full of eels.
  ┆ File "demo_logging.py", line 56, in <module>
  ┆     54   try:
  ┆     55       nothing = {}
  ┆ --> 56       dangerous_function(nothing.get("something"))
  ┆     57   except:
  ┆     ..................................................
  ┆      nothing = {}
  ┆     ..................................................
  ┆
  ┆ File "demo_logging.py", line 52, in dangerous_function
  ┆     51   def dangerous_function(something):
  ┆ --> 52       return something + 1
  ┆     ..................................................
  ┆      something = None
  ┆     ..................................................
  ┆
  ┆ TypeError: unsupported operand type(s) for +: 'NoneType' and 'int'

You can get this by adding a custom formatter to the logger before using it:

import logging
import stackprinter

class VerboseExceptionFormatter(logging.Formatter):
    def formatException(self, exc_info):
        msg = stackprinter.format(exc_info)
        lines = msg.split('\n')
        lines_indented = ["  ┆ " + line + "\n" for line in lines]
        msg_indented = "".join(lines_indented)
        return msg_indented

def configure_logger(logger_name=None):
    fmt = '%(asctime)s %(levelname)s: %(message)s'
    formatter = VerboseExceptionFormatter(fmt)

    handler = logging.StreamHandler()
    handler.setFormatter(formatter)

    logger = logging.getLogger(logger_name)
    logger.addHandler(handler)

configure_logger("some_logger")

See demo_logging.py for a runnable example.

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()

stackprinter's People

Contributors

0xflotus avatar alexmojaki avatar cknd avatar delgan avatar spacemanspiff2007 avatar ss18 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

stackprinter's Issues

Use stack_data

Sooner or later this whole thing should be consolidated on @alexmojaki's stack_data, which is a cleaner, more robust and by now also more widely used version of the data extraction routines in here. I currently don't have time for a large refactor and all else things being equal would like to keep the formatted outputs looking more or less exactly like today, and this combination of constraints explains why this hasn't happened yet. See also #22 , #23
(This is not a new idea, just felt it should have an issue to refer to)

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.

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()

Incorrect docstring for `stackprinter.format`, `suppressed_exceptions_types` should be `suppressed_exceptions`

First of all: thanks for this great package!

The docstring of stackprinter.format states, that there is a keyword argument named suppressed_exception_types.
Using that parameter results in a stackprinter crash with the following error message:

  ┆ Stackprinter failed:
  ┆   File "/.../lib/python3.11/site-packages/stackprinter/formatting.py", line 176, in format_exc_info
  ┆     whole_stack = format_stack(frameinfos, style=style,
  ┆                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  ┆ TypeError: format_stack() got an unexpected keyword argument 'suppressed_exception_types'
  ┆ 
  ┆ So here is your original traceback at least:
  ┆ 
  ┆ Traceback (most recent call last):
  ┆   File "/...

stackprinter.format uses stackprinter.formatting.format_exc_info internally, which has a keyword arg suppressed_exceptions.
Using suppressed_exceptions instead of suppressed_exception_types solved the TypeError.

Here is the working Formatter Class:

class VerboseExceptionFormatter(logging.Formatter):
  def formatException(self, exc_info):
    msg = stackprinter.format(
      exc_info,
      ...
      suppressed_exceptions=[KeyboardInterrupt, SystemExit],
      ...
    )
    return "\n".join("  ┆ " + "%s"%(line) for line in msg.split("\n"))

Python 2 support

Using 2.7.15. My gut tells me this lib is python3 only but then I wonder why pip was able to install it in my python 2 env.

File "lib/python2.7/site-packages/stackprinter/__init__.py", line 163
    print(format(thing, **kwargs), file=file)

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.

Picked an invalid source context

Ran into a "Picked an invalid source context".

I've only seen this once thus far. On python 3.12.0 with StackPrinter 0.2.12.

Stackprinter failed while formatting <FrameInfo xyz.py, line 2249, scope main>:
  File "venv312/lib/python3.12/site-packages/stackprinter/frame_formatting.py", line 225, in select_scope
    raise Exception("Picked an invalid source context: %s" % info)
Exception: Picked an invalid source context: [2249], [2233], dict_keys([2233, 2234, 2235, 2236, 2237, 2238, 2239])

So here is your original traceback at least:

Traceback (most recent call last):
...
KeyError: 0

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

The option to only apply the stackprinter styles to certain exceptions (Alternatively, a whitelist/blacklist system)

As the title suggests, it would be great if we were able to add the stackprinter styles to only a select exception classes.

I came across this idea while developing a module. I wanted the error messages for my module to be prettier, but I didn't want any other error messages to be affected. If I use stackprinter within my module, I essentially force the user to also have its styles for all other exceptions including the ones within their own program, or at least that's what I experienced while testing.

A way to implement this could be by specifying a list of exception classes to whitelist or blacklist (but never both):

stackprinter.set_excepthook(
    style='darkbg2',
    whitelist=[
        TypeError,
        CustomException1,
        CustomException2
    ]
)

outputting the dump as html instead of just text opens up new possibilities

Hello,

I am using a custom library to log loads of information in error-scenarios in a long-running computation.
Today I discovered your library which is way more awesome than what I built.

However, there is one feature that I implemented in my code that I miss: The error-dumps are created as html.
This makes it possible to
(1) email them around, preserving colors
(2) print variables in a short form but keep the 'full' version as expandable on a click
(3) beatifully render objects that already define an html-representation (pandas dataframes)

Here is an example of what the script demo.py would output: (github doesnt let me upload as html but it is html)

demo_stack_dump.txt

If you are interested in having this feature I can code it up properly and we can maybe find a good way to expose it through the api in a backwards-compatible way.

Can't accept non-string multiline tokens

Recently, quite often I end up struggling with this error:

  File "venv312/lib/python3.12/site-packages/stackprinter/source_inspection.py", line 151, in _tokenize
    assert sline == eline, "Can't accept non-string multiline tokens"
AssertionError: Can't accept non-string multiline tokens```

Any hint as to what may be going on?

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. πŸ˜„

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.

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')

Output for ExceptionGroups hides sub-exceptions

Only the outer-most exception seems be be visible in the output for a handled ExceptionGroup.
here is a contrived example:

>>> def fn():
...     e = ExceptionGroup("multiple exceptions",
...             [ExceptionGroup("file not found",
...                 [FileNotFoundError("unknown filename file1.txt"), 
...                  FileNotFoundError("unknown filename file2.txt")]), 
...              KeyError("missing key")])
...     raise e

the normal output shows the sub-exceptions:

>>> fn()
  + Exception Group Traceback (most recent call last):
  |   File "<stdin>", line 1, in <module>
  |   File "<stdin>", line 7, in fn
  | ExceptionGroup: multiple exceptions (2 sub-exceptions)
  +-+---------------- 1 ----------------
    | ExceptionGroup: file not found (2 sub-exceptions)
    +-+---------------- 1 ----------------
      | FileNotFoundError: unknown filename file1.txt
      +---------------- 2 ----------------
      | FileNotFoundError: unknown filename file2.txt
      +------------------------------------
    +---------------- 2 ----------------
    | KeyError: 'missing key'
    +------------------------------------

but with stackprinter

>>> import stackprinter
>>> stackprinter.set_excepthook()
>>> fn()
File "<stdin>", line 1, in <module>

File "<stdin>", line 7, in fn

ExceptionGroup: multiple exceptions (2 sub-exceptions)

all we see is there are sub-exceptions.

I don't have any great suggestions, but maybe at least stackprinter could fall back to the basic output in the case of an ExceptionGroup

Inspect the AST instead of iterating through the tokenized source

Currently, to find out where in the code which variable names occur, I traverse the code token-by-token and apply a sort of ad hoc stack machine that detects stuff like the beginning of function definitions, dot attributes etc. This is clearly nuts, and purely a path effect (= it's how ipython's ultratb does it, and then my scope expanded and here we are).
https://github.com/cknd/stackprinter/blob/master/stackprinter/source_inspection.py

This approach works for now, but it has hit its limits. For example, I'd like to ignore the left-hand side of named arguments in function calls.

Goals:

  • annotate in a piece of code where each variable name occurs, exactly like the current system, but with less of a home made rube goldberg machine behind it.
  • keep the ability to rerender the original code character by character as it appears in the source file (incl extra whitespaces, comment ascii art etc -- so people can visually recognize their code)

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

(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

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!

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.

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

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?

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'

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.

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.

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?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.