With a little monkey-patching, this is actually quite easy. Digging around in the source code of the trace
module it seems that callbacks are used to report on each execution step. The basic functionality of Trace.run
, greatly simplified, is:
sys.settrace(globaltrace) # Set the trace callback function
exec function # Execute the function, invoking the callback as necessary
sys.settrace(None) # Reset the trace
globaltrace
is defined in Trace.__init__
depending on the arguments passed. Specifically, with the arguments in your first example, Trace.globaltrace_lt
is used as the global callback, which calls Trace.localtrace_trace
for each line of execution. Changing it is simply a case of modifying Trace.localtrace
, so to get the result you want:
import trace
import sys
import time
import linecache
class Trace(trace.Trace):
def localtrace_trace(self, frame, why, arg):
if why == "line":
# record the file name and line number of every trace
filename = frame.f_code.co_filename
lineno = frame.f_lineno
if self.start_time:
print '%.2f' % (time.time() - self.start_time),
print "%s (%d): %s" % (filename, lineno,
linecache.getline(filename, lineno)),
return self.localtrace
tracer = Trace(count=False, trace=True, ignoredirs=[sys.prefix, sys.exec_prefix])
r = tracer.run('run()')
There is a difference between the two examples you give; if the first the output is printed during the Trace.run
call, in the second it is printed during write_results
. The code I've given above follows the pattern of the former, so tracer.results().write_results()
is not necessary. However, if you want to manipulate this output instead it can be achieved by patching the trace.CoverageResults.write_results
method in a similar manner.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…