Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit a12fe4e

Browse files
committed
- 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.
1 parent 12dd7b1 commit a12fe4e

5 files changed

Lines changed: 78 additions & 0 deletions

File tree

Include/eval.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ PyAPI_FUNC(PyObject *) PyEval_EvalCodeEx(PyCodeObject *co,
1717
PyObject **defs, int defc,
1818
PyObject *closure);
1919

20+
PyAPI_FUNC(PyObject *) _PyEval_CallTracing(PyObject *func, PyObject *args);
21+
2022
#ifdef __cplusplus
2123
}
2224
#endif

Lib/pdb.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -523,6 +523,33 @@ def do_jump(self, arg):
523523
print '*** Jump failed:', e
524524
do_j = do_jump
525525

526+
def do_debug(self, arg):
527+
sys.settrace(None)
528+
globals = self.curframe.f_globals
529+
locals = self.curframe.f_locals
530+
p = Pdb()
531+
p.prompt = "(%s) " % self.prompt.strip()
532+
print "ENTERING RECURSIVE DEBUGGER"
533+
sys.call_tracing(p.run, (arg, globals, locals))
534+
print "LEAVING RECURSIVE DEBUGGER"
535+
sys.settrace(self.trace_dispatch)
536+
self.lastcmd = p.lastcmd
537+
538+
def dont_debug(self, arg):
539+
locals = self.curframe.f_locals
540+
globals = self.curframe.f_globals
541+
try:
542+
r = sys.call_tracing(eval, (arg, globals, locals))
543+
print "--- DEBUG RETURNED ---"
544+
if r is not None:
545+
print repr(r)
546+
except:
547+
t, v = sys.exc_info()[:2]
548+
if type(t) == type(''):
549+
exc_type_name = t
550+
else: exc_type_name = t.__name__
551+
print '***', exc_type_name + ':', v
552+
526553
def do_quit(self, arg):
527554
self.set_quit()
528555
return 1
@@ -834,6 +861,12 @@ def help_j(self):
834861
print """j(ump) lineno
835862
Set the next line that will be executed."""
836863

864+
def help_debug(self):
865+
print """debug code
866+
Enter a recursive debugger that steps through the code argument
867+
(which is an arbitrary expression or statement to be executed
868+
in the current environment)."""
869+
837870
def help_list(self):
838871
self.help_l()
839872

Misc/NEWS

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,9 @@ Core and builtins
4949
Extension modules
5050
-----------------
5151

52+
- New function sys.call_tracing() allows pdb to debug code
53+
recursively.
54+
5255
- New function gc.get_referents(obj) returns a list of objects
5356
directly referenced by obj. In effect, it exposes what the object's
5457
tp_traverse slot does, and can be helpful when debugging memory
@@ -86,6 +89,9 @@ Extension modules
8689
Library
8790
-------
8891

92+
- pdb has a new command, "debug", which lets you step through
93+
arbitrary code from the debugger's (pdb) prompt.
94+
8995
- unittest.failUnlessEqual and its equivalent unittest.assertEqual now
9096
return 'not a == b' rather than 'a != b'. This gives the desired
9197
result for classes that define __eq__ without defining __ne__.

Python/ceval.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3024,6 +3024,24 @@ call_trace(Py_tracefunc func, PyObject *obj, PyFrameObject *frame,
30243024
return result;
30253025
}
30263026

3027+
PyObject *
3028+
_PyEval_CallTracing(PyObject *func, PyObject *args)
3029+
{
3030+
PyFrameObject *frame = PyEval_GetFrame();
3031+
PyThreadState *tstate = frame->f_tstate;
3032+
int save_tracing = tstate->tracing;
3033+
int save_use_tracing = tstate->use_tracing;
3034+
PyObject *result;
3035+
3036+
tstate->tracing = 0;
3037+
tstate->use_tracing = ((tstate->c_tracefunc != NULL)
3038+
|| (tstate->c_profilefunc != NULL));
3039+
result = PyObject_Call(func, args, NULL);
3040+
tstate->tracing = save_tracing;
3041+
tstate->use_tracing = save_use_tracing;
3042+
return result;
3043+
}
3044+
30273045
static int
30283046
maybe_call_line_trace(Py_tracefunc func, PyObject *obj,
30293047
PyFrameObject *frame, int *instr_lb, int *instr_ub)

Python/sysmodule.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ Data members:
1717
#include "Python.h"
1818
#include "compile.h"
1919
#include "frameobject.h"
20+
#include "eval.h"
2021

2122
#include "osdefs.h"
2223

@@ -609,6 +610,23 @@ sys_getframe(PyObject *self, PyObject *args)
609610
return (PyObject*)f;
610611
}
611612

613+
PyDoc_STRVAR(call_tracing_doc,
614+
"call_tracing(func, args) -> object\n\
615+
\n\
616+
Call func(*args), while tracing is enabled. The tracing state is\n\
617+
saved, and restored afterwards. This is intended to be called from\n\
618+
a debugger from a checkpoint, to recursively debug some other code."
619+
);
620+
621+
static PyObject *
622+
sys_call_tracing(PyObject *self, PyObject *args)
623+
{
624+
PyObject *func, *funcargs;
625+
if (!PyArg_ParseTuple(args, "OO:call_tracing", &func, &funcargs))
626+
return NULL;
627+
return _PyEval_CallTracing(func, funcargs);
628+
}
629+
612630
PyDoc_STRVAR(callstats_doc,
613631
"callstats() -> tuple of integers\n\
614632
\n\
@@ -700,6 +718,7 @@ static PyMethodDef sys_methods[] = {
700718
{"setrecursionlimit", sys_setrecursionlimit, METH_VARARGS,
701719
setrecursionlimit_doc},
702720
{"settrace", sys_settrace, METH_O, settrace_doc},
721+
{"call_tracing", sys_call_tracing, METH_VARARGS, call_tracing_doc},
703722
{NULL, NULL} /* sentinel */
704723
};
705724

0 commit comments

Comments
 (0)