- New function sys.call_tracing() allows pdb to debug code
recursively. - pdb has a new command, "debug", which lets you step through arbitrary code from the debugger's (pdb) prompt.
This commit is contained in:
parent
12dd7b12c6
commit
a12fe4e81f
|
@ -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
|
||||
|
|
33
Lib/pdb.py
33
Lib/pdb.py
|
@ -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()
|
||||
|
||||
|
|
|
@ -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__.
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 */
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue