#line in python (dirty tricks)

Duncan Booth duncan.booth at invalid.invalid
Mon Feb 20 13:54:01 EST 2012

Ross Boylan <ross at biostat.ucsf.edu> wrote:

>> No [easy] way to go from bytecodes back to AST, but I see no reason
>> why you can't create a new code object with your filename and line
>> numbers and then create a new function using your modified code
>> object. 
> Could you elaborate?  I don't understand what you are suggesting.

This (written for Python 3.x, needs some attribute names changing for 
Python 2.x:

import functools
def source_line(lineno, filename = None):
    def decorator(f):
        c = f.__code__
        code = type(c)(
            c.co_argcount, c.co_kwonlyargcount, c.co_nlocals, 
c.co_stacksize, c.co_flags, c.co_code,
            c.co_consts, c.co_names, c.co_varnames,
            c.co_filename if filename is None else filename,
            c.co_lnotab, c.co_freevars, c.co_cellvars)
        f.__code__ = code
        return f
    return decorator

@source_line(43, 'foo.bar')
def foo():
    """This is foo"""
    for i in range(10):

@source_line(665, 'evil.txt')
def bar():
    raise RuntimeError("oops")

if __name__=='__main__':
    import traceback
    except RuntimeError as ex:

When you run it the output looks something like this (if you create a 
file evil.txt with 667 lines):

Traceback (most recent call last):
  File "C:\temp\foo.py", line 30, in <module>
  File "foo.bar", line 47, in foo
  File "evil.txt", line 667, in bar
    Evil line 667
RuntimeError: oops

Duncan Booth http://kupuguy.blogspot.com

More information about the Python-list mailing list