diff options
author | Benjamin Peterson <benjamin@python.org> | 2009-09-09 11:40:54 (GMT) |
---|---|---|
committer | Benjamin Peterson <benjamin@python.org> | 2009-09-09 11:40:54 (GMT) |
commit | 8246968b1222b25352d1aade43336686dc388221 (patch) | |
tree | b5a6bcda00c91ace7a3123366e1ef53ae3ee8654 | |
parent | bed26a3ce371d5244898e1d160a3ca566aec4486 (diff) | |
download | cpython-8246968b1222b25352d1aade43336686dc388221.zip cpython-8246968b1222b25352d1aade43336686dc388221.tar.gz cpython-8246968b1222b25352d1aade43336686dc388221.tar.bz2 |
tabbify
-rw-r--r-- | Lib/test/test_traceback.py | 44 | ||||
-rw-r--r-- | Modules/pwdmodule.c | 2 | ||||
-rw-r--r-- | Python/traceback.c | 94 |
3 files changed, 131 insertions, 9 deletions
diff --git a/Lib/test/test_traceback.py b/Lib/test/test_traceback.py index b29869a..d7dcbac 100644 --- a/Lib/test/test_traceback.py +++ b/Lib/test/test_traceback.py @@ -21,6 +21,50 @@ class TracebackCases(unittest.TestCase): else: raise ValueError, "call did not raise exception" + def test_tb_next(self): + def f(): + raise Exception + def g(): + f() + try: + g() + except Exception: + tb = sys.exc_info()[2] + self.assertEqual(tb.tb_frame.f_code.co_name, "test_tb_next") + g_tb = tb.tb_next + self.assertEqual(g_tb.tb_frame.f_code.co_name, "g") + f_tb = g_tb.tb_next + self.assertEqual(f_tb.tb_frame.f_code.co_name, "f") + self.assertIsNone(f_tb.tb_next) + tb.tb_next = None + self.assertIsNone(tb.tb_next) + self.assertRaises(ValueError, setattr, f_tb, "tb_next", g_tb) + self.assertRaises(TypeError, setattr, tb, "tb_next", 4) + g_tb.tb_next = None + f_tb.tb_next = g_tb + self.assertIs(f_tb.tb_next, g_tb) + self.assertRaises(ValueError, setattr, f_tb, "tb_next", f_tb) + self.assertRaises(TypeError, delattr, tb, "tb_next") + + def test_tb_frame(self): + def f(): + x = 2 + raise Exception + try: + f() + except Exception: + tb = sys.exc_info()[2] + self.assertIs(sys._getframe(), tb.tb_frame) + f_tb = tb.tb_next + self.assertEqual(f_tb.tb_frame.f_code.co_name, "f") + self.assertEqual(f_tb.tb_frame.f_locals["x"], 2) + f_tb.tb_frame = None + self.assertIsNone(f_tb.tb_frame) + self.assertRaises(TypeError, setattr, t_tb, "tb_frame", 4) + self.assertRaises(TypeError, delattr, t_tb, "tb_frame") + t_tb.tb_frame = sys._getframe() + self.assertIs(t_tb.tb_frame, tb.tb_frame) + def syntax_error_with_caret(self): compile("def fact(x):\n\treturn x!\n", "?", "exec") diff --git a/Modules/pwdmodule.c b/Modules/pwdmodule.c index 2865dc6..d1ce394 100644 --- a/Modules/pwdmodule.c +++ b/Modules/pwdmodule.c @@ -194,7 +194,7 @@ initpwd(void) Py_INCREF((PyObject *) &StructPwdType); PyModule_AddObject(m, "struct_passwd", (PyObject *) &StructPwdType); /* And for b/w compatibility (this was defined by mistake): */ - Py_INCREF((PyObject *) &StructPwdType); + Py_INCREF((PyObject *) &StructPwdType); PyModule_AddObject(m, "struct_pwent", (PyObject *) &StructPwdType); initialized = 1; } diff --git a/Python/traceback.c b/Python/traceback.c index 1c26ba2..b96ca47 100644 --- a/Python/traceback.c +++ b/Python/traceback.c @@ -12,8 +12,6 @@ #define OFF(x) offsetof(PyTracebackObject, x) static PyMemberDef tb_memberlist[] = { - {"tb_next", T_OBJECT, OFF(tb_next), READONLY}, - {"tb_frame", T_OBJECT, OFF(tb_frame), READONLY}, {"tb_lasti", T_INT, OFF(tb_lasti), READONLY}, {"tb_lineno", T_INT, OFF(tb_lineno), READONLY}, {NULL} /* Sentinel */ @@ -45,6 +43,81 @@ tb_clear(PyTracebackObject *tb) Py_CLEAR(tb->tb_frame); } +static PyObject * +tb_get_next(PyTracebackObject *tb) { + if (tb->tb_next) { + Py_INCREF(tb->tb_next); + return (PyObject *)tb->tb_next; + } + Py_RETURN_NONE; +} + +static int +tb_set_next(PyTracebackObject *tb, PyObject *new, void *context) { + if (!new) { + PyErr_SetString(PyExc_TypeError, "can't delete tb_next"); + return -1; + } + else if (new == Py_None) { + new = NULL; + } + else if (PyTraceBack_Check(new)) { + /* Check for cycles in the traceback. */ + PyTracebackObject *current = (PyTracebackObject *)new; + do { + if (tb == current) { + PyErr_SetString(PyExc_ValueError, "cycle in traceback"); + return -1; + } + } while ((current = current->tb_next)); + Py_INCREF(new); + } + else { + PyErr_SetString(PyExc_TypeError, + "tb_next must be an traceback object"); + return -1; + } + Py_XDECREF(tb->tb_next); + tb->tb_next = (PyTracebackObject *)new; + return 0; +} + +static PyObject * +tb_get_frame(PyTracebackObject *tb) { + if (tb->tb_frame) { + Py_INCREF(tb->tb_frame); + return (PyObject *)tb->tb_frame; + } + Py_RETURN_NONE; +} + +static int +tb_set_frame(PyTracebackObject *tb, PyObject *new, void *context) { + if (!new) { + PyErr_SetString(PyExc_TypeError, + "can't delete tb_frame attribute"); + return -1; + } + else if (new == Py_None) { + new = NULL; + } + else if (PyFrame_Check(new)) { + Py_INCREF(new); + } + else { + PyErr_SetString(PyExc_TypeError, + "tb_frame must be a frame object"); + return -1; + } + tb->tb_frame = (PyFrameObject *)new; + return 0; +} + +static PyGetSetDef tb_getset[] = { + {"tb_next", (getter)tb_get_next, (setter)tb_set_next, NULL}, + {"tb_frame", (getter)tb_get_frame, (setter)tb_set_frame, NULL}, +}; + PyTypeObject PyTraceBack_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) "traceback", @@ -75,7 +148,7 @@ PyTypeObject PyTraceBack_Type = { 0, /* tp_iternext */ 0, /* tp_methods */ tb_memberlist, /* tp_members */ - 0, /* tp_getset */ + tb_getset, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ }; @@ -245,11 +318,16 @@ tb_printinternal(PyTracebackObject *tb, PyObject *f, long limit) } while (tb != NULL && err == 0) { if (depth <= limit) { - err = tb_displayline(f, - PyString_AsString( - tb->tb_frame->f_code->co_filename), - tb->tb_lineno, - PyString_AsString(tb->tb_frame->f_code->co_name)); + PyFrameObject *frame = tb->tb_frame; + char *filename, *name; + if (frame) { + filename = PyString_AS_STRING(frame->f_code->co_filename); + name = PyString_AS_STRING(frame->f_code->co_name); + } + else { + filename = name = "unkown (no frame on traceback)"; + } + err = tb_displayline(f, filename, tb->tb_lineno, name); } depth--; tb = tb->tb_next; |