Improper Backtraces in Exec'd Code

Peter Otten __peter__ at web.de
Thu Jul 22 13:00:43 EDT 2010


Burton Samograd wrote:

> Hello,
> 
> I have written an importing extension along the lines of PEP 302
> (http://www.python.org/dev/peps/pep-0302/) and have run into a bit of a
> problem with stack backtraces after exceptions.
> 
> When I run code with the using my importing extension, backtraces come
> up looking like this:
> 
> Traceback (most recent call last):
>   File "<string>", line 134, in <module>
>   File "<string>", line 9, in <module>
>   File "<string>", line 7, in a
>   File "<string>", line 4, in b
> TypeError
> 
> What I'm having a problem with is that the file names are no longer
> being printed during the backtrace.  The following code is from my
> importer function load_module:
> 
>        try:
>             mod = sys.modules[module_name]
>             already_in_sys_modules = True
>         except KeyError:
>             mod = sys.modules.setdefault(module_name,
>                                          imp.new_module(module_name))
>             already_in_sys_modules = False
>         mod.__file__ = "%s" % module_path
>         mod.__loader__ = self
>         if is_package:
>             mod.__path__ = [ module_path ]
>         mod.__dict__['__file__'] = module_path
>         try:
>             exec code in mod.__dict__
>         except:
>             import traceback
>             print traceback.format_exc(5)
>             print "ERROR: could not load module: %s" % module_path
>             if not already_in_sys_modules:
>                 del sys.modules[module_name]
>                 mod = None
>  
> As shown in PEP 302, I am setting the mod.__file__ variable and as my
> own idea I set __file__ in mod.__dict__.  Niether of these steps seem to
> set the file properly in the backtrace.
> 
> So the question here is, where does the backtrace printing module get
> it's __file__ parameters from, or what am I missing to set it properly?
> 
> Thanks in advance.
> 
> --
> Burton Samograd

exec code 

implicitly compiles code with "<string>" as the filename. 
The filename is stored in f.func_code.co_filename and it is read-only.

>> exec "def f(x): return f(x-1) if x else 1/0"
>>> f(3)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<string>", line 1, in f
  File "<string>", line 1, in f
  File "<string>", line 1, in f
  File "<string>", line 1, in f
ZeroDivisionError: integer division or modulo by zero

If you make the compilation step explicit you can pass a filename:

>>> exec compile("def f(x): return f(x-1) if x else 1/0", "yadda.py", 
"exec")
>>> f(3)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "yadda.py", line 1, in f
  File "yadda.py", line 1, in f
  File "yadda.py", line 1, in f
  File "yadda.py", line 1, in f
ZeroDivisionError: integer division or modulo by zero

Of course the offending line isn't quoted because there is no file 
"yadda.py" on my harddisk. But I can change that:

>>> with open("yadda.py", "w") as out: print >> out, "I was fooled!"
...
>>> f(3)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "yadda.py", line 1, in f
    I was fooled!
  File "yadda.py", line 1, in f
    I was fooled!
  File "yadda.py", line 1, in f
    I was fooled!
  File "yadda.py", line 1, in f
    I was fooled!
ZeroDivisionError: integer division or modulo by zero

Peter





More information about the Python-list mailing list