[pypy-svn] pypy default: merge heads
arigo
commits-noreply at bitbucket.org
Fri Apr 8 17:53:08 CEST 2011
Author: Armin Rigo <arigo at tunes.org>
Branch:
Changeset: r43227:2f723ee92a83
Date: 2011-04-08 17:52 +0200
http://bitbucket.org/pypy/pypy/changeset/2f723ee92a83/
Log: merge heads
diff --git a/pypy/module/cpyext/stubs.py b/pypy/module/cpyext/stubs.py
--- a/pypy/module/cpyext/stubs.py
+++ b/pypy/module/cpyext/stubs.py
@@ -351,14 +351,6 @@
"""Return the number of free variables in co."""
raise NotImplementedError
- at cpython_api([rffi.INT_real, rffi.INT_real, rffi.INT_real, rffi.INT_real, PyObject, PyObject, PyObject, PyObject, PyObject, PyObject, PyObject, PyObject, rffi.INT_real, PyObject], PyCodeObject)
-def PyCode_New(space, argcount, nlocals, stacksize, flags, code, consts, names, varnames, freevars, cellvars, filename, name, firstlineno, lnotab):
- """Return a new code object. If you need a dummy code object to
- create a frame, use PyCode_NewEmpty() instead. Calling
- PyCode_New() directly can bind you to a precise Python
- version since the definition of the bytecode changes often."""
- raise NotImplementedError
-
@cpython_api([PyObject], rffi.INT_real, error=-1)
def PyCodec_Register(space, search_function):
"""Register a new codec search function.
@@ -1116,20 +1108,6 @@
with an exception set on failure (the module still exists in this case)."""
raise NotImplementedError
- at cpython_api([rffi.CCHARP], PyObject)
-def PyImport_AddModule(space, name):
- """Return the module object corresponding to a module name. The name argument
- may be of the form package.module. First check the modules dictionary if
- there's one there, and if not, create a new one and insert it in the modules
- dictionary. Return NULL with an exception set on failure.
-
- This function does not load or import the module; if the module wasn't already
- loaded, you will get an empty module object. Use PyImport_ImportModule()
- or one of its variants to import a module. Package structures implied by a
- dotted name for name are not created if not already present."""
- borrow_from()
- raise NotImplementedError
-
@cpython_api([rffi.CCHARP, PyObject], PyObject)
def PyImport_ExecCodeModule(space, name, co):
"""Given a module name (possibly of the form package.module) and a code
@@ -1965,14 +1943,6 @@
"""
raise NotImplementedError
- at cpython_api([PyObject, PyObject, rffi.INTP], rffi.INT_real, error=-1)
-def PyObject_Cmp(space, o1, o2, result):
- """Compare the values of o1 and o2 using a routine provided by o1, if one
- exists, otherwise with a routine provided by o2. The result of the
- comparison is returned in result. Returns -1 on failure. This is the
- equivalent of the Python statement result = cmp(o1, o2)."""
- raise NotImplementedError
-
@cpython_api([PyObject], PyObject)
def PyObject_Bytes(space, o):
"""Compute a bytes representation of object o. In 2.x, this is just a alias
diff --git a/pypy/module/cpyext/include/code.h b/pypy/module/cpyext/include/code.h
new file mode 100644
--- /dev/null
+++ b/pypy/module/cpyext/include/code.h
@@ -0,0 +1,12 @@
+#ifndef Py_CODE_H
+#define Py_CODE_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef PyObject PyCodeObject;
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* !Py_CODE_H */
diff --git a/pypy/module/cpyext/api.py b/pypy/module/cpyext/api.py
--- a/pypy/module/cpyext/api.py
+++ b/pypy/module/cpyext/api.py
@@ -539,7 +539,8 @@
elif is_PyObject(callable.api_func.restype):
if result is None:
- retval = make_ref(space, None)
+ retval = rffi.cast(callable.api_func.restype,
+ make_ref(space, None))
elif isinstance(result, Reference):
retval = result.get_ref(space)
elif not rffi._isllptr(result):
diff --git a/pypy/interpreter/nestedscope.py b/pypy/interpreter/nestedscope.py
--- a/pypy/interpreter/nestedscope.py
+++ b/pypy/interpreter/nestedscope.py
@@ -220,11 +220,13 @@
for cell in self.space.fixedview(w_freevarstuple)]
else:
nfreevars = len(codeobj.co_freevars)
- freevars = [self.space.interp_w(Cell, self.popvalue())
- for i in range(nfreevars)]
- freevars.reverse()
- defaultarguments = [self.popvalue() for i in range(numdefaults)]
- defaultarguments.reverse()
+ freevars = [None] * nfreevars
+ while True:
+ nfreevars -= 1
+ if nfreevars < 0:
+ break
+ freevars[n] = self.space.interp_w(Cell, self.popvalue())
+ defaultarguments = self.popvalues(numdefaults)
fn = function.Function(self.space, codeobj, self.w_globals,
defaultarguments, freevars)
self.pushvalue(self.space.wrap(fn))
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
@@ -46,6 +46,7 @@
import pypy.module.cpyext.complexobject
import pypy.module.cpyext.weakrefobject
import pypy.module.cpyext.funcobject
+import pypy.module.cpyext.frameobject
import pypy.module.cpyext.classobject
import pypy.module.cpyext.pypyintf
import pypy.module.cpyext.memoryobject
diff --git a/pypy/module/cpyext/frameobject.py b/pypy/module/cpyext/frameobject.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/cpyext/frameobject.py
@@ -0,0 +1,82 @@
+from pypy.rpython.lltypesystem import rffi, lltype
+from pypy.module.cpyext.api import (
+ cpython_api, bootstrap_function, PyObjectFields, cpython_struct)
+from pypy.module.cpyext.pyobject import (
+ PyObject, Py_DecRef, make_ref, from_ref, track_reference,
+ make_typedescr, get_typedescr)
+from pypy.module.cpyext.state import State
+from pypy.module.cpyext.pystate import PyThreadState
+from pypy.module.cpyext.funcobject import PyCodeObject
+from pypy.interpreter.pyframe import PyFrame
+from pypy.interpreter.pycode import PyCode
+
+PyFrameObjectStruct = lltype.ForwardReference()
+PyFrameObject = lltype.Ptr(PyFrameObjectStruct)
+PyFrameObjectFields = (PyObjectFields +
+ (("f_code", PyCodeObject),
+ ("f_globals", PyObject),
+ ("f_lineno", rffi.INT),
+ ))
+cpython_struct("PyFrameObject", PyFrameObjectFields, PyFrameObjectStruct)
+
+ at bootstrap_function
+def init_frameobject(space):
+ make_typedescr(PyFrame.typedef,
+ basestruct=PyFrameObject.TO,
+ attach=frame_attach,
+ dealloc=frame_dealloc,
+ realize=frame_realize)
+
+def frame_attach(space, py_obj, w_obj):
+ "Fills a newly allocated PyFrameObject with a frame object"
+ frame = space.interp_w(PyFrame, w_obj)
+ py_frame = rffi.cast(PyFrameObject, py_obj)
+ py_frame.c_f_code = rffi.cast(PyCodeObject, make_ref(space, frame.pycode))
+ py_frame.c_f_globals = make_ref(space, frame.w_globals)
+ py_frame.c_f_lineno = frame.f_lineno
+
+ at cpython_api([PyObject], lltype.Void, external=False)
+def frame_dealloc(space, py_obj):
+ py_frame = rffi.cast(PyFrameObject, py_obj)
+ py_code = rffi.cast(PyObject, py_frame.c_f_code)
+ Py_DecRef(space, py_code)
+ Py_DecRef(space, py_frame.c_f_globals)
+ from pypy.module.cpyext.object import PyObject_dealloc
+ PyObject_dealloc(space, py_obj)
+
+def frame_realize(space, py_obj):
+ """
+ Creates the frame in the interpreter. The PyFrameObject structure must not
+ be modified after this call.
+ """
+ py_frame = rffi.cast(PyFrameObject, py_obj)
+ py_code = rffi.cast(PyObject, py_frame.c_f_code)
+ w_code = from_ref(space, py_code)
+ code = space.interp_w(PyCode, w_code)
+ w_globals = from_ref(space, py_frame.c_f_globals)
+
+ frame = PyFrame(space, code, w_globals, closure=None)
+ frame.f_lineno = py_frame.c_f_lineno
+ w_obj = space.wrap(frame)
+ track_reference(space, py_obj, w_obj)
+ return w_obj
+
+ at cpython_api([PyThreadState, PyCodeObject, PyObject, PyObject], PyFrameObject)
+def PyFrame_New(space, tstate, w_code, w_globals, w_locals):
+ typedescr = get_typedescr(PyFrame.typedef)
+ py_obj = typedescr.allocate(space, space.gettypeobject(PyFrame.typedef))
+ py_frame = rffi.cast(PyFrameObject, py_obj)
+ space.interp_w(PyCode, w_code) # sanity check
+ py_frame.c_f_code = rffi.cast(PyCodeObject, make_ref(space, w_code))
+ py_frame.c_f_globals = make_ref(space, w_globals)
+ return py_frame
+
+ at cpython_api([PyFrameObject], rffi.INT_real, error=-1)
+def PyTraceBack_Here(space, w_frame):
+ from pypy.interpreter.pytraceback import record_application_traceback
+ state = space.fromcache(State)
+ if state.operror is None:
+ return -1
+ frame = space.interp_w(PyFrame, w_frame)
+ record_application_traceback(space, state.operror, frame, 0)
+ return 0
diff --git a/pypy/module/cpyext/test/test_api.py b/pypy/module/cpyext/test/test_api.py
--- a/pypy/module/cpyext/test/test_api.py
+++ b/pypy/module/cpyext/test/test_api.py
@@ -61,6 +61,12 @@
except OperationError, e:
print e.errorstr(self.space)
raise
+
+ try:
+ del self.space.getexecutioncontext().cpyext_threadstate
+ except AttributeError:
+ pass
+
if self.check_and_print_leaks():
assert False, "Test leaks or loses object(s)."
diff --git a/pypy/tool/pytest/appsupport.py b/pypy/tool/pytest/appsupport.py
--- a/pypy/tool/pytest/appsupport.py
+++ b/pypy/tool/pytest/appsupport.py
@@ -196,7 +196,7 @@
class _ExceptionInfo(object):
def __init__(self):
import sys
- self.type, self.value, _ = sys.exc_info()
+ self.type, self.value, self.traceback = sys.exc_info()
return _ExceptionInfo
""")
diff --git a/pypy/module/cpyext/object.py b/pypy/module/cpyext/object.py
--- a/pypy/module/cpyext/object.py
+++ b/pypy/module/cpyext/object.py
@@ -245,6 +245,16 @@
expression cmp(o1, o2)."""
return space.int_w(space.cmp(w_o1, w_o2))
+ at cpython_api([PyObject, PyObject, rffi.INTP], rffi.INT_real, error=-1)
+def PyObject_Cmp(space, w_o1, w_o2, result):
+ """Compare the values of o1 and o2 using a routine provided by o1, if one
+ exists, otherwise with a routine provided by o2. The result of the
+ comparison is returned in result. Returns -1 on failure. This is the
+ equivalent of the Python statement result = cmp(o1, o2)."""
+ res = space.int_w(space.cmp(w_o1, w_o2))
+ result[0] = rffi.cast(rffi.INT, res)
+ return 0
+
@cpython_api([PyObject, PyObject, rffi.INT_real], PyObject)
def PyObject_RichCompare(space, w_o1, w_o2, opid_int):
"""Compare the values of o1 and o2 using the operation specified by opid,
diff --git a/pypy/module/cpyext/funcobject.py b/pypy/module/cpyext/funcobject.py
--- a/pypy/module/cpyext/funcobject.py
+++ b/pypy/module/cpyext/funcobject.py
@@ -14,6 +14,10 @@
(("func_name", PyObject),)
cpython_struct("PyFunctionObject", PyFunctionObjectFields, PyFunctionObjectStruct)
+PyCodeObjectStruct = lltype.ForwardReference()
+PyCodeObject = lltype.Ptr(PyCodeObjectStruct)
+cpython_struct("PyCodeObject", PyObjectFields, PyCodeObjectStruct)
+
@bootstrap_function
def init_functionobject(space):
make_typedescr(Function.typedef,
@@ -65,7 +69,36 @@
assert isinstance(w_method, Method)
return borrow_from(w_method, w_method.w_class)
- at cpython_api([CONST_STRING, CONST_STRING, rffi.INT_real], PyObject)
+def unwrap_list_of_strings(space, w_list):
+ return [space.str_w(w_item) for w_item in space.fixedview(w_list)]
+
+ at cpython_api([rffi.INT_real, rffi.INT_real, rffi.INT_real, rffi.INT_real,
+ PyObject, PyObject, PyObject, PyObject, PyObject, PyObject,
+ PyObject, PyObject, rffi.INT_real, PyObject], PyCodeObject)
+def PyCode_New(space, argcount, nlocals, stacksize, flags,
+ w_code, w_consts, w_names, w_varnames, w_freevars, w_cellvars,
+ w_filename, w_funcname, firstlineno, w_lnotab):
+ """Return a new code object. If you need a dummy code object to
+ create a frame, use PyCode_NewEmpty() instead. Calling
+ PyCode_New() directly can bind you to a precise Python
+ version since the definition of the bytecode changes often."""
+ return space.wrap(PyCode(space,
+ argcount=rffi.cast(lltype.Signed, argcount),
+ nlocals=rffi.cast(lltype.Signed, nlocals),
+ stacksize=rffi.cast(lltype.Signed, stacksize),
+ flags=rffi.cast(lltype.Signed, flags),
+ code=space.str_w(w_code),
+ consts=space.fixedview(w_consts),
+ names=unwrap_list_of_strings(space, w_names),
+ varnames=unwrap_list_of_strings(space, w_varnames),
+ filename=space.str_w(w_filename),
+ name=space.str_w(w_funcname),
+ firstlineno=rffi.cast(lltype.Signed, firstlineno),
+ lnotab=space.str_w(w_lnotab),
+ freevars=unwrap_list_of_strings(space, w_freevars),
+ cellvars=unwrap_list_of_strings(space, w_cellvars)))
+
+ at cpython_api([CONST_STRING, CONST_STRING, rffi.INT_real], PyCodeObject)
def PyCode_NewEmpty(space, filename, funcname, firstlineno):
"""Creates a new empty code object with the specified source location."""
return space.wrap(PyCode(space,
diff --git a/pypy/module/cpyext/test/test_import.py b/pypy/module/cpyext/test/test_import.py
--- a/pypy/module/cpyext/test/test_import.py
+++ b/pypy/module/cpyext/test/test_import.py
@@ -1,5 +1,6 @@
from pypy.module.cpyext.test.test_api import BaseApiTest
from pypy.module.cpyext.test.test_cpyext import AppTestCpythonExtensionBase
+from pypy.rpython.lltypesystem import rffi, lltype
class TestImport(BaseApiTest):
def test_import(self, space, api):
@@ -7,6 +8,16 @@
assert pdb
assert space.getattr(pdb, space.wrap("pm"))
+ def test_addmodule(self, space, api):
+ with rffi.scoped_str2charp("sys") as modname:
+ w_sys = api.PyImport_AddModule(modname)
+ assert w_sys is space.sys
+
+ with rffi.scoped_str2charp("foobar") as modname:
+ w_foobar = api.PyImport_AddModule(modname)
+ assert space.str_w(space.getattr(w_foobar,
+ space.wrap('__name__'))) == 'foobar'
+
def test_reload(self, space, api):
pdb = api.PyImport_Import(space.wrap("pdb"))
space.delattr(pdb, space.wrap("set_trace"))
diff --git a/pypy/module/cpyext/include/compile.h b/pypy/module/cpyext/include/compile.h
new file mode 100644
--- /dev/null
+++ b/pypy/module/cpyext/include/compile.h
@@ -0,0 +1,13 @@
+#ifndef Py_COMPILE_H
+#define Py_COMPILE_H
+
+#include "code.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* !Py_COMPILE_H */
diff --git a/pypy/module/cpyext/test/test_cpyext.py b/pypy/module/cpyext/test/test_cpyext.py
--- a/pypy/module/cpyext/test/test_cpyext.py
+++ b/pypy/module/cpyext/test/test_cpyext.py
@@ -106,6 +106,11 @@
del obj
import gc; gc.collect()
+ try:
+ del space.getexecutioncontext().cpyext_threadstate
+ except AttributeError:
+ pass
+
for w_obj in state.non_heaptypes_w:
Py_DecRef(space, w_obj)
state.non_heaptypes_w[:] = []
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
@@ -110,6 +110,8 @@
#include "intobject.h"
#include "listobject.h"
#include "unicodeobject.h"
+#include "compile.h"
+#include "frameobject.h"
#include "eval.h"
#include "pymem.h"
#include "pycobject.h"
diff --git a/pypy/module/cpyext/import_.py b/pypy/module/cpyext/import_.py
--- a/pypy/module/cpyext/import_.py
+++ b/pypy/module/cpyext/import_.py
@@ -1,8 +1,10 @@
from pypy.interpreter import module
from pypy.module.cpyext.api import (
generic_cpy_call, cpython_api, PyObject, CONST_STRING)
+from pypy.module.cpyext.pyobject import borrow_from
from pypy.rpython.lltypesystem import rffi
from pypy.interpreter.error import OperationError
+from pypy.interpreter.module import Module
@cpython_api([PyObject], PyObject)
def PyImport_Import(space, w_name):
@@ -51,3 +53,23 @@
from pypy.module.imp.importing import reload
return reload(space, w_mod)
+ at cpython_api([CONST_STRING], PyObject)
+def PyImport_AddModule(space, name):
+ """Return the module object corresponding to a module name. The name
+ argument may be of the form package.module. First check the modules
+ dictionary if there's one there, and if not, create a new one and insert
+ it in the modules dictionary. Return NULL with an exception set on
+ failure.
+
+ This function does not load or import the module; if the module wasn't
+ already loaded, you will get an empty module object. Use
+ PyImport_ImportModule() or one of its variants to import a module.
+ Package structures implied by a dotted name for name are not created if
+ not already present."""
+ from pypy.module.imp.importing import check_sys_modules_w
+ modulename = rffi.charp2str(name)
+ w_mod = check_sys_modules_w(space, modulename)
+ if not w_mod or space.is_w(w_mod, space.w_None):
+ w_mod = Module(space, space.wrap(modulename))
+ return borrow_from(None, w_mod)
+
diff --git a/pypy/module/cpyext/test/test_pystate.py b/pypy/module/cpyext/test/test_pystate.py
--- a/pypy/module/cpyext/test/test_pystate.py
+++ b/pypy/module/cpyext/test/test_pystate.py
@@ -29,20 +29,14 @@
state = api.PyInterpreterState_Head()
assert nullptr(PyInterpreterState.TO) == api.PyInterpreterState_Next(state)
-def clear_threadstate(space):
- # XXX: this should collect the ThreadState memory
- del space.getexecutioncontext().cpyext_threadstate
-
class TestThreadState(BaseApiTest):
def test_thread_state_get(self, space, api):
ts = api.PyThreadState_Get()
assert ts != nullptr(PyThreadState.TO)
- clear_threadstate(space)
def test_thread_state_interp(self, space, api):
ts = api.PyThreadState_Get()
assert ts.c_interp == api.PyInterpreterState_Head()
- clear_threadstate(space)
def test_basic_threadstate_dance(self, space, api):
# Let extension modules call these functions,
@@ -54,5 +48,3 @@
api.PyEval_AcquireThread(tstate)
api.PyEval_ReleaseThread(tstate)
-
- clear_threadstate(space)
diff --git a/pypy/module/cpyext/test/test_object.py b/pypy/module/cpyext/test/test_object.py
--- a/pypy/module/cpyext/test/test_object.py
+++ b/pypy/module/cpyext/test/test_object.py
@@ -174,6 +174,17 @@
assert api.PyObject_Compare(space.wrap(72), space.wrap(42)) == 1
assert api.PyObject_Compare(space.wrap("a"), space.wrap("a")) == 0
+ def test_cmp(self, space, api):
+ w = space.wrap
+ with lltype.scoped_alloc(rffi.INTP.TO, 1) as ptr:
+ assert api.PyObject_Cmp(w(42), w(72), ptr) == 0
+ assert ptr[0] == -1
+ assert api.PyObject_Cmp(w("a"), w("a"), ptr) == 0
+ assert ptr[0] == 0
+ assert api.PyObject_Cmp(w(u"\xe9"), w("\xe9"), ptr) < 0
+ assert api.PyErr_Occurred()
+ api.PyErr_Clear()
+
def test_unicode(self, space, api):
assert space.unwrap(api.PyObject_Unicode(space.wrap([]))) == u"[]"
assert space.unwrap(api.PyObject_Unicode(space.wrap("e"))) == u"e"
diff --git a/pypy/module/cpyext/include/traceback.h b/pypy/module/cpyext/include/traceback.h
new file mode 100644
--- /dev/null
+++ b/pypy/module/cpyext/include/traceback.h
@@ -0,0 +1,12 @@
+#ifndef Py_TRACEBACK_H
+#define Py_TRACEBACK_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef PyObject PyTracebackObject;
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* !Py_TRACEBACK_H */
diff --git a/pypy/module/cpyext/test/test_frameobject.py b/pypy/module/cpyext/test/test_frameobject.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/cpyext/test/test_frameobject.py
@@ -0,0 +1,66 @@
+from pypy.module.cpyext.test.test_cpyext import AppTestCpythonExtensionBase
+
+class AppTestFrameObject(AppTestCpythonExtensionBase):
+
+ def test_forge_frame(self):
+ module = self.import_extension('foo', [
+ ("raise_exception", "METH_NOARGS",
+ """
+ PyObject *py_srcfile = PyString_FromString("filename");
+ PyObject *py_funcname = PyString_FromString("funcname");
+ PyObject *py_globals = PyDict_New();
+ PyObject *empty_string = PyString_FromString("");
+ PyObject *empty_tuple = PyTuple_New(0);
+ PyCodeObject *py_code;
+ PyFrameObject *py_frame;
+
+ py_code = PyCode_New(
+ 0, /*int argcount,*/
+ #if PY_MAJOR_VERSION >= 3
+ 0, /*int kwonlyargcount,*/
+ #endif
+ 0, /*int nlocals,*/
+ 0, /*int stacksize,*/
+ 0, /*int flags,*/
+ empty_string, /*PyObject *code,*/
+ empty_tuple, /*PyObject *consts,*/
+ empty_tuple, /*PyObject *names,*/
+ empty_tuple, /*PyObject *varnames,*/
+ empty_tuple, /*PyObject *freevars,*/
+ empty_tuple, /*PyObject *cellvars,*/
+ py_srcfile, /*PyObject *filename,*/
+ py_funcname, /*PyObject *name,*/
+ 42, /*int firstlineno,*/
+ empty_string /*PyObject *lnotab*/
+ );
+
+ if (!py_code) goto bad;
+ py_frame = PyFrame_New(
+ PyThreadState_Get(), /*PyThreadState *tstate,*/
+ py_code, /*PyCodeObject *code,*/
+ py_globals, /*PyObject *globals,*/
+ 0 /*PyObject *locals*/
+ );
+ if (!py_frame) goto bad;
+ py_frame->f_lineno = 48; /* Does not work with CPython */
+ PyErr_SetString(PyExc_ValueError, "error message");
+ PyTraceBack_Here(py_frame);
+ bad:
+ Py_XDECREF(py_srcfile);
+ Py_XDECREF(py_funcname);
+ Py_XDECREF(empty_string);
+ Py_XDECREF(empty_tuple);
+ Py_XDECREF(py_globals);
+ Py_XDECREF(py_code);
+ Py_XDECREF(py_frame);
+ return NULL;
+ """),
+ ])
+ exc = raises(ValueError, module.raise_exception)
+ frame = exc.traceback.tb_frame
+ assert frame.f_code.co_filename == "filename"
+ assert frame.f_code.co_name == "funcname"
+
+ # Cython does not work on CPython as well...
+ assert exc.traceback.tb_lineno == 42 # should be 48
+ assert frame.f_lineno == 42
diff --git a/pypy/module/cpyext/include/frameobject.h b/pypy/module/cpyext/include/frameobject.h
new file mode 100644
--- /dev/null
+++ b/pypy/module/cpyext/include/frameobject.h
@@ -0,0 +1,17 @@
+#ifndef Py_FRAMEOBJECT_H
+#define Py_FRAMEOBJECT_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct {
+ PyObject_HEAD
+ PyCodeObject *f_code;
+ PyObject *f_globals;
+ int f_lineno;
+} PyFrameObject;
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* !Py_FRAMEOBJECT_H */
More information about the Pypy-commit
mailing list