<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>

    <meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
  </head>
  <body text="#000000" bgcolor="#ffffff">
    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.<br>
    <br>
    The docs say:<br>
    <blockquote>
      <p>The trace function is invoked (with <em>event</em> set to <tt
          class="docutils literal"><span class="pre">'call'</span></tt>)
        whenever a new
        local scope is entered; it should return a reference to a local
        trace
        function to be used that scope, or <tt class="xref docutils
          literal"><span class="pre">None</span></tt> if the scope
        shouldn&#8217;t be traced.</p>
      <p>The local trace function should return a reference to itself
        (or to another
        function for further tracing in that scope), or <tt class="xref
          docutils literal"><span class="pre">None</span></tt> to turn
        off tracing
        in that scope.<br>
      </p>
    </blockquote>
    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.&nbsp; Once
    the trace function returns a function for a frame, returning None
    from subsequent calls is ignored.&nbsp; A "local trace function" can't
    turn off tracing in its scope.<br>
    <br>
    To demonstrate:<br>
    <blockquote><tt>import sys</tt><br>
      <br>
      <tt>UPTO_LINE = 1</tt><br>
      <br>
      <tt>def t(frame, event, arg):</tt><br>
      <tt>&nbsp;&nbsp;&nbsp; num = frame.f_lineno</tt><br>
      <tt>&nbsp;&nbsp;&nbsp; print("line %d" % num)</tt><br>
      <tt>&nbsp;&nbsp;&nbsp; if num &lt; UPTO_LINE:</tt><br>
      <tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return t</tt><br>
      <br>
      <tt>def try_it():</tt><br>
      <tt>&nbsp;&nbsp;&nbsp; print("twelve")</tt><br>
      <tt>&nbsp;&nbsp;&nbsp; print("thirteen")</tt><br>
      <tt>&nbsp;&nbsp;&nbsp; print("fourteen")</tt><br>
      <tt>&nbsp;&nbsp;&nbsp; print("fifteen")</tt><br>
      <br>
      <tt>UPTO_LINE = 1</tt><br>
      <tt>sys.settrace(t)</tt><br>
      <tt>try_it()</tt><br>
      <br>
      <tt>UPTO_LINE = 13</tt><br>
      <tt>sys.settrace(t)</tt><br>
      <tt>try_it()</tt><br>
    </blockquote>
    Produces:<br>
    <blockquote><tt>line 11</tt><br>
      <tt>twelve</tt><br>
      <tt>thirteen</tt><br>
      <tt>fourteen</tt><br>
      <tt>fifteen</tt><br>
      <tt>line 11</tt><br>
      <tt>line 12</tt><br>
      <tt>twelve</tt><br>
      <tt>line 13</tt><br>
      <tt>thirteen</tt><br>
      <tt>line 14</tt><br>
      <tt>fourteen</tt><br>
      <tt>line 15</tt><br>
      <tt>fifteen</tt><br>
      <tt>line 15</tt><br>
    </blockquote>
    The first call to try_it() returns None immediately, preventing
    tracing for the rest of the function.&nbsp; The second call returns None
    at line 13, but the rest of the function is traced anyway.&nbsp; 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.&nbsp; (A
    deeper mystery that I haven't looked into yet is why Python 3.x
    intersperses all of these lines with "line 18" interjections.)<br>
    <br>
    I'm writing this email because I'm not sure whether this is a
    behavior bug or a doc bug.&nbsp; One of them is wrong, since they
    disagree.&nbsp; The documented behavior makes sense, and is what people
    have all along thought the trace function did.&nbsp; The actual behavior
    is a bit more complicated to explain, but is what people have
    actually been experiencing.&nbsp; FWIW, PyPy implements the documented
    behavior.<br>
    <p>Should we fix the code or the docs?&nbsp; I'd be glad to supply a
      patch for either.<br>
    </p>
    <p>--Ned.<br>
    </p>
    <br>
  </body>
</html>