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.

+2


source to share


3 answers


After a deep search, this is not possible, CPython uses its own API to determine where the file is, etc., and it cannot be fixed in pure Python.



+2


source


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.



+3


source


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

      

0


source







All Articles