]> granicus.if.org Git - python/commitdiff
- New function sys.call_tracing() allows pdb to debug code
authorGuido van Rossum <guido@python.org>
Wed, 9 Apr 2003 19:06:21 +0000 (19:06 +0000)
committerGuido van Rossum <guido@python.org>
Wed, 9 Apr 2003 19:06:21 +0000 (19:06 +0000)
  recursively.
- pdb has a new command, "debug", which lets you step through
  arbitrary code from the debugger's (pdb) prompt.

Include/eval.h
Lib/pdb.py
Misc/NEWS
Python/ceval.c
Python/sysmodule.c

index 66638e75d1380f11ed4e4cccbe14766474ac20aa..b78dfe0fae0027e609ad232c7cac28b25a7978a5 100644 (file)
@@ -17,6 +17,8 @@ PyAPI_FUNC(PyObject *) PyEval_EvalCodeEx(PyCodeObject *co,
                                        PyObject **defs, int defc,
                                        PyObject *closure);
 
+PyAPI_FUNC(PyObject *) _PyEval_CallTracing(PyObject *func, PyObject *args);
+
 #ifdef __cplusplus
 }
 #endif
index d7215cfa7b742ea64b2cffc440273c51591991e9..46dff55c915ff1a34156d29dff8c89cfc2f1a8dd 100755 (executable)
@@ -523,6 +523,33 @@ class Pdb(bdb.Bdb, cmd.Cmd):
                 print '*** Jump failed:', e
     do_j = do_jump
 
+    def do_debug(self, arg):
+        sys.settrace(None)
+        globals = self.curframe.f_globals
+        locals = self.curframe.f_locals
+       p = Pdb()
+       p.prompt = "(%s) " % self.prompt.strip()
+       print "ENTERING RECURSIVE DEBUGGER"
+       sys.call_tracing(p.run, (arg, globals, locals))
+       print "LEAVING RECURSIVE DEBUGGER"
+        sys.settrace(self.trace_dispatch)
+        self.lastcmd = p.lastcmd
+
+    def dont_debug(self, arg):
+        locals = self.curframe.f_locals
+        globals = self.curframe.f_globals
+        try:
+            r = sys.call_tracing(eval, (arg, globals, locals))
+           print "--- DEBUG RETURNED ---"
+           if r is not None:
+               print repr(r)
+        except:
+            t, v = sys.exc_info()[:2]
+            if type(t) == type(''):
+                exc_type_name = t
+            else: exc_type_name = t.__name__
+            print '***', exc_type_name + ':', v
+
     def do_quit(self, arg):
         self.set_quit()
         return 1
@@ -834,6 +861,12 @@ Continue execution, only stop when a breakpoint is encountered."""
         print """j(ump) lineno
 Set the next line that will be executed."""
 
+    def help_debug(self):
+        print """debug code
+Enter a recursive debugger that steps through the code argument
+(which is an arbitrary expression or statement to be executed
+in the current environment)."""
+
     def help_list(self):
         self.help_l()
 
index 3ded09e8808bba99dd3598d0d2d6e3ec0511d473..661c2ca8c37fe5dac4de0516cd37129a92013007 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -49,6 +49,9 @@ Core and builtins
 Extension modules
 -----------------
 
+- New function sys.call_tracing() allows pdb to debug code
+  recursively.
+
 - New function gc.get_referents(obj) returns a list of objects
   directly referenced by obj.  In effect, it exposes what the object's
   tp_traverse slot does, and can be helpful when debugging memory
@@ -86,6 +89,9 @@ Extension modules
 Library
 -------
 
+- pdb has a new command, "debug", which lets you step through
+  arbitrary code from the debugger's (pdb) prompt.
+
 - unittest.failUnlessEqual and its equivalent unittest.assertEqual now
   return 'not a == b' rather than 'a != b'.  This gives the desired
   result for classes that define __eq__ without defining __ne__.
index f965d3866bb9fa17eb155b1f15ef2c9de7033886..080b3c16bc3c1710aeca349076d5f02db721e284 100644 (file)
@@ -3024,6 +3024,24 @@ call_trace(Py_tracefunc func, PyObject *obj, PyFrameObject *frame,
        return result;
 }
 
+PyObject *
+_PyEval_CallTracing(PyObject *func, PyObject *args)
+{
+       PyFrameObject *frame = PyEval_GetFrame();
+       PyThreadState *tstate = frame->f_tstate;
+       int save_tracing = tstate->tracing;
+       int save_use_tracing = tstate->use_tracing;
+       PyObject *result;
+
+       tstate->tracing = 0;
+       tstate->use_tracing = ((tstate->c_tracefunc != NULL)
+                              || (tstate->c_profilefunc != NULL));
+       result = PyObject_Call(func, args, NULL);
+       tstate->tracing = save_tracing;
+       tstate->use_tracing = save_use_tracing;
+       return result;
+}
+
 static int
 maybe_call_line_trace(Py_tracefunc func, PyObject *obj, 
                      PyFrameObject *frame, int *instr_lb, int *instr_ub)
index fa7f3c4a544a0eaa96a91932b64539081f60df9b..50b99127a014cf33a667d5ae39d9f9a09717de0c 100644 (file)
@@ -17,6 +17,7 @@ Data members:
 #include "Python.h"
 #include "compile.h"
 #include "frameobject.h"
+#include "eval.h"
 
 #include "osdefs.h"
 
@@ -609,6 +610,23 @@ sys_getframe(PyObject *self, PyObject *args)
        return (PyObject*)f;
 }
 
+PyDoc_STRVAR(call_tracing_doc,
+"call_tracing(func, args) -> object\n\
+\n\
+Call func(*args), while tracing is enabled.  The tracing state is\n\
+saved, and restored afterwards.  This is intended to be called from\n\
+a debugger from a checkpoint, to recursively debug some other code."
+);
+
+static PyObject *
+sys_call_tracing(PyObject *self, PyObject *args)
+{
+       PyObject *func, *funcargs;
+       if (!PyArg_ParseTuple(args, "OO:call_tracing", &func, &funcargs))
+               return NULL;
+       return _PyEval_CallTracing(func, funcargs);
+}
+
 PyDoc_STRVAR(callstats_doc,
 "callstats() -> tuple of integers\n\
 \n\
@@ -700,6 +718,7 @@ static PyMethodDef sys_methods[] = {
        {"setrecursionlimit", sys_setrecursionlimit, METH_VARARGS,
         setrecursionlimit_doc},
        {"settrace",    sys_settrace, METH_O, settrace_doc},
+       {"call_tracing", sys_call_tracing, METH_VARARGS, call_tracing_doc},
        {NULL,          NULL}           /* sentinel */
 };