[pypy-commit] pypy default: Expose traceback fields in cpyext, and expose PyFrameObject as "struct _frame".

devin.jeanpierre noreply at buildbot.pypy.org
Wed Oct 14 07:47:47 EDT 2015


Author: Devin Jeanpierre <jeanpierreda at gmail.com>
Branch: 
Changeset: r80197:6e335c196a45
Date: 2015-10-04 23:35 -0700
http://bitbucket.org/pypy/pypy/changeset/6e335c196a45/

Log:	Expose traceback fields in cpyext, and expose PyFrameObject as
	"struct _frame".

diff --git a/pypy/module/cpyext/__init__.py b/pypy/module/cpyext/__init__.py
--- a/pypy/module/cpyext/__init__.py
+++ b/pypy/module/cpyext/__init__.py
@@ -66,6 +66,7 @@
 import pypy.module.cpyext.codecs
 import pypy.module.cpyext.pyfile
 import pypy.module.cpyext.pystrtod
+import pypy.module.cpyext.pytraceback
 
 # now that all rffi_platform.Struct types are registered, configure them
 api.configure_types()
diff --git a/pypy/module/cpyext/include/Python.h b/pypy/module/cpyext/include/Python.h
--- a/pypy/module/cpyext/include/Python.h
+++ b/pypy/module/cpyext/include/Python.h
@@ -126,6 +126,7 @@
 #include "fileobject.h"
 #include "pysignals.h"
 #include "pythread.h"
+#include "traceback.h"
 
 /* Missing definitions */
 #include "missing.h"
diff --git a/pypy/module/cpyext/include/frameobject.h b/pypy/module/cpyext/include/frameobject.h
--- a/pypy/module/cpyext/include/frameobject.h
+++ b/pypy/module/cpyext/include/frameobject.h
@@ -4,7 +4,7 @@
 extern "C" {
 #endif
 
-typedef struct {
+typedef struct _frame {
     PyObject_HEAD
     PyCodeObject *f_code;
     PyObject *f_globals;
diff --git a/pypy/module/cpyext/include/traceback.h b/pypy/module/cpyext/include/traceback.h
--- a/pypy/module/cpyext/include/traceback.h
+++ b/pypy/module/cpyext/include/traceback.h
@@ -4,7 +4,15 @@
 extern "C" {
 #endif
 
-typedef PyObject PyTracebackObject;
+struct _frame;
+
+typedef struct _traceback {
+        PyObject_HEAD
+        struct _traceback *tb_next;
+        struct _frame *tb_frame;
+        int tb_lasti;
+        int tb_lineno;
+} PyTracebackObject;
 
 #ifdef __cplusplus
 }
diff --git a/pypy/module/cpyext/pytraceback.py b/pypy/module/cpyext/pytraceback.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/cpyext/pytraceback.py
@@ -0,0 +1,47 @@
+from rpython.rtyper.lltypesystem import rffi, lltype
+from pypy.module.cpyext.api import (
+    PyObjectFields, generic_cpy_call, CONST_STRING, CANNOT_FAIL, Py_ssize_t,
+    cpython_api, bootstrap_function, cpython_struct, build_type_checkers)
+from pypy.module.cpyext.pyobject import (
+    PyObject, make_ref, from_ref, Py_DecRef, make_typedescr, borrow_from)
+from pypy.module.cpyext.frameobject import PyFrameObject
+from rpython.rlib.unroll import unrolling_iterable
+from pypy.interpreter.error import OperationError
+from pypy.interpreter.pytraceback import PyTraceback
+from pypy.interpreter import pycode
+
+
+PyTracebackObjectStruct = lltype.ForwardReference()
+PyTracebackObject = lltype.Ptr(PyTracebackObjectStruct)
+PyTracebackObjectFields = PyObjectFields + (
+    ("tb_next", PyTracebackObject),
+    ("tb_frame", PyFrameObject),
+    ("tb_lasti", rffi.INT),
+    ("tb_lineno", rffi.INT),
+)
+cpython_struct("PyTracebackObject", PyTracebackObjectFields, PyTracebackObjectStruct)
+
+ at bootstrap_function
+def init_traceback(space):
+    make_typedescr(PyTraceback.typedef,
+                   basestruct=PyTracebackObject.TO,
+                   attach=traceback_attach,
+                   dealloc=traceback_dealloc)
+    # TODO: decref tb_frame properly!
+
+
+def traceback_attach(space, py_obj, w_obj):
+    py_traceback = rffi.cast(PyTracebackObject, py_obj)
+    traceback = space.interp_w(PyTraceback, w_obj)
+    py_traceback.c_tb_next = rffi.cast(PyTracebackObject, make_ref(space, space.wrap(traceback.next)))
+    py_traceback.c_tb_frame = rffi.cast(PyFrameObject, make_ref(space, space.wrap(traceback.frame)))
+    rffi.setintfield(py_traceback, 'c_tb_lasti', traceback.lasti)
+    rffi.setintfield(py_traceback, 'c_tb_lineno',traceback.get_lineno())
+
+ at cpython_api([PyObject], lltype.Void, external=False)
+def traceback_dealloc(space, py_obj):
+    py_traceback = rffi.cast(PyTracebackObject, py_obj)
+    Py_DecRef(space, rffi.cast(PyObject, py_traceback.c_tb_next))
+    Py_DecRef(space, rffi.cast(PyObject, py_traceback.c_tb_frame))
+    from pypy.module.cpyext.object import PyObject_dealloc
+    PyObject_dealloc(space, py_obj)
diff --git a/pypy/module/cpyext/test/test_traceback.py b/pypy/module/cpyext/test/test_traceback.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/cpyext/test/test_traceback.py
@@ -0,0 +1,28 @@
+from rpython.rtyper.lltypesystem import rffi
+from pypy.module.cpyext.test.test_api import BaseApiTest
+from pypy.module.cpyext.pyobject import PyObject, make_ref, from_ref
+from pypy.module.cpyext.pytraceback import PyTracebackObject
+from pypy.interpreter.pytraceback import PyTraceback
+from pypy.interpreter.pyframe import PyFrame
+
+class TestPyTracebackObject(BaseApiTest):
+    def test_traceback(self, space, api):
+        w_traceback = space.appexec([], """():
+            import sys
+            try:
+                1/0
+            except:
+                return sys.exc_info()[2]
+        """)
+        py_obj = make_ref(space, w_traceback)
+        py_traceback = rffi.cast(PyTracebackObject, py_obj)
+        assert (from_ref(space, rffi.cast(PyObject, py_traceback.c_ob_type)) is
+                space.gettypeobject(PyTraceback.typedef))
+
+        traceback = space.interp_w(PyTraceback, w_traceback)
+        assert traceback.lasti == py_traceback.c_tb_lasti
+        assert traceback.get_lineno() == py_traceback.c_tb_lineno
+        assert traceback.next is space.interp_w(PyTraceback, from_ref(space, rffi.cast(PyObject, py_traceback.c_tb_next)), can_be_None=True)
+        assert traceback.frame is space.interp_w(PyFrame, from_ref(space, rffi.cast(PyObject, py_traceback.c_tb_frame)), can_be_None=True)
+
+        api.Py_DecRef(py_obj)


More information about the pypy-commit mailing list