Add variables to Python traceback
github.com
github.com
this:
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'
becomes: 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 <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'
[1] https://github.com/cknd/stackprinterbetter_exchook: https://pypi.org/project/better-exchook/ / https://github.com/albertz/py_better_exchook
It's just a single file, so you can easily copy it into your project.
It's a bit more advanced than this as well, as it has some further logic about what variables it actually shows:
* It shows only those which are used in the statement of the active line. In bigger functions, you often have other unrelated locals, and this would become incredibly spammy otherwise. Also, the use locals in the current line are almost always exactly those you are interested in.
* It also shows globals (this one only shows locals).
Like the original traceback and this one, it shows the current active line, and not the context around (e.g. like in IPython or stackprinter).
However, it has an extension: If the current statement goes over multiple lines, it will print them as well.
It also has an extension for DomTerm that you can fold away the variables.
MM(variabletodump);
example https://github.com/graydon/monotone/blob/master/graph.cc#L49...
docs https://github.com/graydon/monotone/blob/master/HACKING#L252The implementation was a bit hairy https://github.com/graydon/monotone/blob/master/sanity.hh#L4...
exc_info = ExceptionInfo.from_current()
print(exc_info.getrepr(style="long", showlocals=True))For those like me who didn’t know about this: https://docs.python.org/3/library/cgitb.html
While the function seems similar, the interfaces seem very different. cgitb seems to need to be wrapped and configured to match the fully headless/logger use case. I think they could focus on that in the FAQ.
I could see it going either way. I would probably not use this globally on programs using secrets, but would consider opting-in occasionally where chances are low and value high.
Opt-out is risky and I’d not want to use it in sensitive applications.
Instead, opt-in would be as good as deliberately logging variables but without the additional log/print statements and try/catch blocks.
You leave. New person takes over ownership, doesn't notice the import. Urgent business need says "add this feature to the daemon" and now it's processing secrets. Now, you can argue that the person who took ownership should have read the code more carefully, but perhaps it's their 5th day on the job when that request comes in, or they misread the import as something else.
I suppose you could do a code standard of "variables that containe a secret must always have 'secret' as a prefix", and could then do pattern matching, but humans are going to human and make a mistake.
I'd probably lean towards opt-in, decorator/context only - maybe "@traceback_with_variables_can_log_secrets" as the name...
For debugging, eh, why not - but I've not previously had the need to enable this, let's say, application-wide (where I see the most advantage compared to just adding dumps of locals() per stack).
[0] https://docs.sentry.io/platforms/python/configuration/option...
In dev, sure (assuming local disk only). In prod, not in the form documented.
It requires no changes to your code, you can install it system-wide and all tracebacks will be prettified.
max_value_str_len max length of each variable string, -1 to disable, default=1000
import ipdb; ipdb.pm()
for quick post mortem debugging, which also allows to see the variables at the moment where the exception was raised (Command locals()).
Is there a scenario where this adds value? return '\n'.join(iter_tb_lines(e))