[Python-Dev] sys.settrace: behavior doesn't match docs (original) (raw)

Guido van Rossum guido at python.org
Sun May 1 02:43:27 CEST 2011


I think you need to go back farther in time. :-) In Python 2.0 the call_trace function in ceval.c has a completely different signature (but the docs are the same). I haven't checked all history but somewhere between 2.0 and 2.3, SET_LINENO-less tracing was added, and that's where the implementation must have gone wrong. So I think we should fix the code.

--Guido

On Sat, Apr 30, 2011 at 3:49 PM, Ned Batchelder <ned at nedbatchelder.com> wrote:

This week I learned something new about trace functions (how to write a C trace function that survives a sys.settrace(sys.gettrace()) round-trip), and while writing up what I learned, I was surprised to discover that trace functions don't behave the way I thought, or the way the docs say they behave.

The docs say: The trace function is invoked (with event set to 'call') whenever a new local scope is entered; it should return a reference to a local trace function to be used that scope, or None if the scope shouldn’t be traced. The local trace function should return a reference to itself (or to another function for further tracing in that scope), or None to turn off tracing in that scope. It's that last part that's wrong: returning None from the trace function only has an effect on the first call in a new frame.  Once the trace function returns a function for a frame, returning None from subsequent calls is ignored.  A "local trace function" can't turn off tracing in its scope. To demonstrate: import sys UPTOLINE = 1 def t(frame, event, arg): num = frame.flineno print("line %d" % num) if num < UPTOLINE: return t def tryit(): print("twelve") print("thirteen") print("fourteen") print("fifteen") UPTOLINE = 1 sys.settrace(t) tryit() UPTOLINE = 13 sys.settrace(t) tryit() Produces: line 11 twelve thirteen fourteen fifteen line 11 line 12 twelve line 13 thirteen line 14 fourteen line 15 fifteen line 15 The first call to tryit() returns None immediately, preventing tracing for the rest of the function.  The second call returns None at line 13, but the rest of the function is traced anyway.  This behavior is the same in all versions from 2.3 to 3.2, in fact, the 100 lines of code in sysmodule.c responsible for Python tracing functions are completely unchanged through those versions.  (A deeper mystery that I haven't looked into yet is why Python 3.x intersperses all of these lines with "line 18" interjections.) I'm writing this email because I'm not sure whether this is a behavior bug or a doc bug.  One of them is wrong, since they disagree.  The documented behavior makes sense, and is what people have all along thought the trace function did.  The actual behavior is a bit more complicated to explain, but is what people have actually been experiencing.  FWIW, PyPy implements the documented behavior. Should we fix the code or the docs?  I'd be glad to supply a patch for either. --Ned.


Python-Dev mailing list Python-Dev at python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/guido%40python.org

-- --Guido van Rossum (python.org/~guido)



More information about the Python-Dev mailing list