Identifying a function call in a python script line at runtime

I have a python script that I run using 'exec'. When the function is called by the script, I would like to know the line number and line offset for that call.

Here's an example. If my script is:

foo1(); foo2(); foo1()
foo3()

      

And if I have some code that prints (line, offset) in each function, I should get

(0,0), (0,8), (0,16), (1,0)

      

In most cases, this can be done easily by getting a stack frame since it contains the line number and the function name. The only problem is that there are two functions with the same name on the same line. Unfortunately this is a common case for me. Any ideas?


Well it seems that changing the source code is the simplest solution.

How would you solve things like

if foo1(7) or foo1(6):

      

or

foo2(foo1(), foo1())

      

There are some not very elegant solutions for this, for example, automatically turning the previous example to:

def curpos(pos, func):
  record_curpos(pos)
  return func

curpos(foo2,0)(curpos(foo1,5)(), curpos(foo1,13)())

      

Let me know if you have any simpler ideas.

+2


a source to share


2 answers


Python doesn't provide much information about character offsets in a string.

If you are using exec to execute Python, you can rewrite the code mechanically before executing it to tell you what you want to know. For example, you can change the source code:

foo1(); foo2(); foo1()
foo3()

      

into annotated code:



curpos(1,0); foo1(); curpos(1,8); foo2(); curpos(1,16); foo1()
curpos(2,0); foo3()

      

and then execute the annotated code.

Where curpos(line,char)

writes or prints the string and character information of that point in the source code. This will be much easier than flushing the stack frames.

+1


a source


You can of course look line by line and try to find the name of the function, although it won't be reliable if they have one of the functions, for example:

bar = foo2
foo1(); foo2()

      



If not, it becomes very difficult. The coverage module does this, and Ned explained a specific technique in a blog post - it mainly involves rewriting bytecode to separate expressions into different (fake) line numbers.

In fact, you can use the coverage module itself.

0


a source







All Articles