How to overwrite a specific frame in a trace?
In python, you can compile () a string that will run faster with exec (). But as soon as I use it, we lost information when the exception happened in exec.
For example, here's a piece of code that calls an unknown method (for demonstration purposes):
code = 'my_unknown_method()'
bytecode = compile(code, '<string>', 'exec')
And later I call exec on this bytecode:
exec bytecode
Trace shown:
Traceback (most recent call last):
File "test.py", line 3, in <module>
exec bytecode
File "<string>", line 1, in <module>
NameError: name 'my_unknown_method' is not defined
The "exec ()" frame is now unclear. I would like to get a better exception like:
Traceback (most recent call last):
File "test.py", line 3, in <module>
exec "my_unknown_method()"
File "<string>", line 1, in <module>
NameError: name 'my_unknown_method' is not defined
Any thoughts?
Notes:
- I don't want to use the second compilation argument (filename)
- I tested playing with validating and modifying f_code in a frame, but the readonly attribute.
EDIT: After looking more at sys.excepthook, I saw this in the python / traceback.c source code, when python wants to show the contents of a line, they fopen () directly the file if found. No hook available for displaying our own content. The only way to create a real fake filename on disk? Anyone?
EDIT2: I checked some jinja2 debug code and they rewrite the trace as well, but not for content. Do I need a custom other than a hook? My problems with this have to do with the fact that it is not in the trace itself, if the user / module / whatever is receiving the exception, the trace will not contain valuable information.
source to share
You should take a look at this conversation from Armin Ronacher. He is the author of Jinja2 and in this conversation he explained how he manipulates stack traces in Jinja2. If I recall correctly, he used ctypes to manipulate data structures at the C Python level. The conversation was, in my opinion, the best conversation about the whole Europython 2011, by the way.
source to share
How about something like this:
import sys
def mkexec(code_str):
bc = compile(code, '<string>', 'exec')
def run():
try:
exec bc
except: # Yes I know a bare except
t, v, tb = sys.exc_info()
raise MyUsefullException("%s raised %s" % (code_str, v))
return run
exe = mkexec("some_unknown_something()")
exe()
source to share