summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBenjamin Peterson <benjamin@python.org>2009-09-09 11:40:54 (GMT)
committerBenjamin Peterson <benjamin@python.org>2009-09-09 11:40:54 (GMT)
commit8246968b1222b25352d1aade43336686dc388221 (patch)
treeb5a6bcda00c91ace7a3123366e1ef53ae3ee8654
parentbed26a3ce371d5244898e1d160a3ca566aec4486 (diff)
downloadcpython-8246968b1222b25352d1aade43336686dc388221.zip
cpython-8246968b1222b25352d1aade43336686dc388221.tar.gz
cpython-8246968b1222b25352d1aade43336686dc388221.tar.bz2
tabbify
-rw-r--r--Lib/test/test_traceback.py44
-rw-r--r--Modules/pwdmodule.c2
-rw-r--r--Python/traceback.c94
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;