Search code examples
pythonpython-3.xtrace

Why no call event when entering code blocks?


I'm using Python's sys.settrace to trace through code execution for a program analysis task.

In contrast to what the documentation states I do not see a call event being registered when entering a code block.

A sample tracer I'm using is below:

class BasicTracer(object):
    def __init__(self, fun):
        self.fun = fun
        self.result_acc = []
        self.orig_tracer = None

    def trace(self, frame, event, arg):
        self.result_acc.append((event, self.fun(frame)))
        return self.trace

    def setup(self):
        self.orig_tracer = sys.gettrace()
        sys.settrace(self.trace)

    def shutdown(self):
        sys.settrace(self.orig_tracer)

    def run(self, file_path):
        if not os.path.exists(file_path):
            with open('_instrumented.py', 'w') as f:
                f.write(file_path)
                file_path = '_instrumented.py'
        src = open(file_path, 'r').read()
        # compile, execute instrumented version
        namespace = {
            '__name__'      : '__main__',
            '__file__'      : file_path,
            '__builtins__'  : __builtins__,
        }
        compiled = compile(src, filename=file_path, mode='exec')
        self.frame_acc = []
        self.result_acc = []
        self.setup()
        exec(compiled, namespace)
        self.shutdown()

For example, consider the source code:

src = """
x = 1
while x < 3:
  x += 1
"""

I see the expected return event upon exiting the while body, but there is no call event when entering. Am I missing something here?

import inspect
tracer = BasicTracer(lambda x: inspect.getframeinfo(x).code_context)
tracer.run(src)
tracer.result_acc
[('call', ['x = 1\n']),
 ('line', ['x = 1\n']),
 ('line', ['while x < 3:\n']),
 ('line', ['  x += 1\n']),
 ('line', ['while x < 3:\n']),
 ('line', ['  x += 1\n']),
 ('line', ['while x < 3:\n']),
 ('return', ['while x < 3:\n']),
 ('call', ['    def shutdown(self):\n']),
 ('line', ['        sys.settrace(self.orig_tracer)\n'])]

I'm using Python 3.6.3 on Mac OSX, in case that is relevant.


Solution

  • The docs are poorly worded. They say a 'call' event occurs when

    A function is called (or some other code block entered).

    but "some other code block" is referring to anything with its own code object and associated scope, not blocks like while.