]> granicus.if.org Git - python/commitdiff
Merged revisions 72776,72796 via svnmerge from
authorJeffrey Yasskin <jyasskin@gmail.com>
Wed, 20 May 2009 19:09:05 +0000 (19:09 +0000)
committerJeffrey Yasskin <jyasskin@gmail.com>
Wed, 20 May 2009 19:09:05 +0000 (19:09 +0000)
svn+ssh://pythondev@svn.python.org/python/trunk

........
  r72776 | jeffrey.yasskin | 2009-05-18 14:14:54 -0700 (Mon, 18 May 2009) | 6 lines

  While I was modifying test_trace, it threw an exception when I accidentally
  made it try to set the line number from the trace callback for a 'call' event.
  This patch makes the error message a little more helpful in that case, and
  makes it a little less likely that a future editor will make the same mistake
  in test_trace.
........
  r72796 | jeffrey.yasskin | 2009-05-20 10:57:57 -0700 (Wed, 20 May 2009) | 3 lines

  Fix issue #1689458 by teaching frame_setlineno how to jump to the first line of
  a code object.
........

Lib/test/test_trace.py
Objects/frameobject.c

index 48a717ba8f5d64d6bd07ce227d26ca86c27b07f8..ecb588c262694f66240d01d92cfe43b39c65b115 100644 (file)
@@ -472,7 +472,7 @@ class JumpTracer:
     def trace(self, frame, event, arg):
         if not self.done and frame.f_code == self.function.__code__:
             firstLine = frame.f_code.co_firstlineno
-            if frame.f_lineno == firstLine + self.jumpFrom:
+            if event == 'line' and frame.f_lineno == firstLine + self.jumpFrom:
                 # Cope with non-integer self.jumpTo (because of
                 # no_jump_to_non_integers below).
                 try:
@@ -741,6 +741,27 @@ class JumpTestCase(unittest.TestCase):
     def test_19_no_jump_without_trace_function(self):
         no_jump_without_trace_function()
 
+    def test_jump_to_firstlineno(self):
+        # This tests that PDB can jump back to the first line in a
+        # file.  See issue #1689458.  It can only be triggered in a
+        # function call if the function is defined on a single line.
+        code = compile("""
+# Comments don't count.
+output.append(2)  # firstlineno is here.
+output.append(3)
+output.append(4)
+""", "<fake module>", "exec")
+        class fake_function:
+            __code__ = code
+            jump = (2, 0)
+        tracer = JumpTracer(fake_function)
+        sys.settrace(tracer.trace)
+        namespace = {"output": []}
+        exec(code, namespace)
+        sys.settrace(None)
+        self.compare_jump_output([2, 3, 2, 3, 4], namespace["output"])
+
+
 def test_main():
     support.run_unittest(
         TraceTestCase,
index e29c64742c0bc3f924964a36d6c6a9b9e5118b63..8bb0f9c6277cf44af4d001428d9e5e8bbd1ca080 100644 (file)
@@ -98,7 +98,8 @@ frame_setlineno(PyFrameObject *f, PyObject* p_new_lineno)
        if (!f->f_trace)
        {
                PyErr_Format(PyExc_ValueError,
-                            "f_lineno can only be set by a trace function");
+                            "f_lineno can only be set by a"
+                            " line trace function");
                return -1;
        }
 
@@ -122,20 +123,26 @@ frame_setlineno(PyFrameObject *f, PyObject* p_new_lineno)
                             new_lineno);
                return -1;
        }
-
-       /* Find the bytecode offset for the start of the given line, or the
-        * first code-owning line after it. */
-       PyBytes_AsStringAndSize(f->f_code->co_lnotab, &lnotab, &lnotab_len);
-       addr = 0;
-       line = f->f_code->co_firstlineno;
-       new_lasti = -1;
-       for (offset = 0; offset < lnotab_len; offset += 2) {
-               addr += lnotab[offset];
-               line += lnotab[offset+1];
-               if (line >= new_lineno) {
-                       new_lasti = addr;
-                       new_lineno = line;
-                       break;
+       else if (new_lineno == f->f_code->co_firstlineno) {
+               new_lasti = 0;
+               new_lineno = f->f_code->co_firstlineno;
+       }
+       else {
+               /* Find the bytecode offset for the start of the given
+                * line, or the first code-owning line after it. */
+               PyBytes_AsStringAndSize(f->f_code->co_lnotab,
+                                       &lnotab, &lnotab_len);
+               addr = 0;
+               line = f->f_code->co_firstlineno;
+               new_lasti = -1;
+               for (offset = 0; offset < lnotab_len; offset += 2) {
+                       addr += lnotab[offset];
+                       line += lnotab[offset+1];
+                       if (line >= new_lineno) {
+                               new_lasti = addr;
+                               new_lineno = line;
+                               break;
+                       }
                }
        }