[pypy-svn] r72455 - in pypy/trunk/pypy/module/cpyext: . include test
xoraxax at codespeak.net
xoraxax at codespeak.net
Sat Mar 20 16:07:15 CET 2010
Author: xoraxax
Date: Sat Mar 20 16:07:14 2010
New Revision: 72455
Added:
pypy/trunk/pypy/module/cpyext/include/pyerrors.h
pypy/trunk/pypy/module/cpyext/pyerrors.py
Modified:
pypy/trunk/pypy/module/cpyext/__init__.py
pypy/trunk/pypy/module/cpyext/api.py
pypy/trunk/pypy/module/cpyext/include/Python.h
pypy/trunk/pypy/module/cpyext/methodobject.py
pypy/trunk/pypy/module/cpyext/state.py
pypy/trunk/pypy/module/cpyext/test/test_cpyext.py
Log:
Add exception handling to cpyext.
Modified: pypy/trunk/pypy/module/cpyext/__init__.py
==============================================================================
--- pypy/trunk/pypy/module/cpyext/__init__.py (original)
+++ pypy/trunk/pypy/module/cpyext/__init__.py Sat Mar 20 16:07:14 2010
@@ -30,4 +30,5 @@
import pypy.module.cpyext.modsupport
import pypy.module.cpyext.pythonrun
import pypy.module.cpyext.macros
+import pypy.module.cpyext.pyerrors
api.configure()
Modified: pypy/trunk/pypy/module/cpyext/api.py
==============================================================================
--- pypy/trunk/pypy/module/cpyext/api.py (original)
+++ pypy/trunk/pypy/module/cpyext/api.py Sat Mar 20 16:07:14 2010
@@ -12,6 +12,7 @@
from pypy.tool.udir import udir
from pypy.translator import platform
from pypy.module.cpyext.state import State
+from pypy.interpreter.error import OperationError
include_dirs = [
@@ -59,6 +60,12 @@
for name, TYPE in rffi_platform.configure(CConfig).iteritems():
TYPES[name].become(TYPE)
+class NullPointerException(Exception):
+ pass
+
+class InvalidPointerException(Exception):
+ pass
+
def make_ref(space, w_obj):
state = space.fromcache(State)
py_obj = state.py_objects_w2r.get(w_obj)
@@ -75,12 +82,12 @@
def from_ref(space, ref):
state = space.fromcache(State)
if not ref:
- raise RuntimeError("Null pointer dereference!")
+ raise NullPointerException("Null pointer dereference!")
ptr = ctypes.addressof(ref._obj._storage)
try:
obj = state.py_objects_r2w[ptr]
except KeyError:
- raise RuntimeError("Got invalid reference to a PyObject")
+ raise InvalidPointerException("Got invalid reference to a PyObject")
return obj
#_____________________________________________________
@@ -143,6 +150,7 @@
global_objects = """
PyObject *PyPy_None = NULL;
+ PyObject *PyPyExc_Exception = NULL;
"""
code = (prologue +
struct_declaration_code +
@@ -166,6 +174,7 @@
bridge = ctypes.CDLL(str(modulename))
pypyAPI = ctypes.POINTER(ctypes.c_void_p).in_dll(bridge, 'pypyAPI')
Py_NONE = ctypes.c_void_p.in_dll(bridge, 'PyPy_None')
+ PyExc_Exception = ctypes.c_void_p.in_dll(bridge, 'PyPyExc_Exception')
def make_wrapper(callable):
def wrapper(*args):
@@ -176,7 +185,21 @@
if typ is PyObject:
arg = from_ref(space, arg)
boxed_args.append(arg)
- retval = callable(space, *boxed_args)
+ try:
+ retval = callable(space, *boxed_args)
+ except OperationError, e:
+ e.normalize_exception(space)
+ state = space.fromcache(State)
+ state.exc_type = e.w_type
+ state.exc_value = e.get_w_value(space)
+ restype = callable.api_func.restype
+ if restype is lltype.Void:
+ return
+ if restype is PyObject:
+ return lltype.nullptr(PyObject)
+ if restype is lltype.Signed:
+ return -1
+ assert False, "Unknown return type"
if callable.api_func.restype is PyObject:
retval = make_ref(space, retval)
return retval
@@ -189,6 +212,8 @@
ctypes.c_void_p)
Py_NONE.value = ctypes.cast(ll2ctypes.lltype2ctypes(make_ref(space, space.w_None)),
ctypes.c_void_p).value
+ PyExc_Exception.value = ctypes.cast(ll2ctypes.lltype2ctypes(make_ref(space,
+ space.w_Exception)), ctypes.c_void_p).value
return modulename.new(ext='')
Modified: pypy/trunk/pypy/module/cpyext/include/Python.h
==============================================================================
--- pypy/trunk/pypy/module/cpyext/include/Python.h (original)
+++ pypy/trunk/pypy/module/cpyext/include/Python.h Sat Mar 20 16:07:14 2010
@@ -14,5 +14,6 @@
#include "modsupport.h"
#include "pythonrun.h"
+#include "pyerrors.h"
#endif
Added: pypy/trunk/pypy/module/cpyext/include/pyerrors.h
==============================================================================
--- (empty file)
+++ pypy/trunk/pypy/module/cpyext/include/pyerrors.h Sat Mar 20 16:07:14 2010
@@ -0,0 +1,16 @@
+
+/* Exception interface */
+
+#ifndef Py_PYERRORS_H
+#define Py_PYERRORS_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern PyObject *PyPyExc_Exception;
+#define PyExc_Exception PyPyExc_Exception
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* !Py_PYERRORS_H */
Modified: pypy/trunk/pypy/module/cpyext/methodobject.py
==============================================================================
--- pypy/trunk/pypy/module/cpyext/methodobject.py (original)
+++ pypy/trunk/pypy/module/cpyext/methodobject.py Sat Mar 20 16:07:14 2010
@@ -3,8 +3,11 @@
from pypy.interpreter.gateway import ObjSpace, W_Root
from pypy.interpreter.argument import Arguments
from pypy.interpreter.gateway import interp2app, unwrap_spec
+from pypy.interpreter.error import OperationError
from pypy.rpython.lltypesystem import rffi, lltype
-from pypy.module.cpyext.api import PyObject, from_ref
+from pypy.module.cpyext.api import PyObject, from_ref, NullPointerException, \
+ InvalidPointerException
+from pypy.module.cpyext.state import State
from pypy.rlib.objectmodel import we_are_translated
@@ -24,11 +27,19 @@
result = self.ml.c_ml_meth(null, null)
try:
ret = from_ref(space, result)
- except RuntimeError:
+ except NullPointerException:
+ state = space.fromcache(State)
+ exc_value = state.exc_value
+ exc_type = state.exc_type
+ assert exc_value is not None and exc_type is not None
+ state.exc_value = None
+ state.exc_type = None
+ raise OperationError(exc_type, exc_value)
+ except InvalidPointerException:
if not we_are_translated():
import sys
- print >>sys.stderr, "Calling a function failed. Did it" \
- " really return a PyObject?"
+ print >>sys.stderr, "Calling a C function return an invalid PyObject" \
+ " pointer."
raise
# XXX result.decref()
Added: pypy/trunk/pypy/module/cpyext/pyerrors.py
==============================================================================
--- (empty file)
+++ pypy/trunk/pypy/module/cpyext/pyerrors.py Sat Mar 20 16:07:14 2010
@@ -0,0 +1,10 @@
+from pypy.rpython.lltypesystem import rffi, lltype
+from pypy.interpreter.error import OperationError
+from pypy.module.cpyext.api import cpython_api, PyObject, make_ref
+
+ at cpython_api([PyObject, rffi.CCHARP], lltype.Void)
+def PyErr_SetString(space, w_type, message_ptr):
+ message = rffi.charp2str(message_ptr)
+ w_obj = space.call_function(w_type, space.wrap(message))
+ raise OperationError(w_type, w_obj)
+
Modified: pypy/trunk/pypy/module/cpyext/state.py
==============================================================================
--- pypy/trunk/pypy/module/cpyext/state.py (original)
+++ pypy/trunk/pypy/module/cpyext/state.py Sat Mar 20 16:07:14 2010
@@ -6,4 +6,6 @@
def __init__(self, space):
self.py_objects_w2r = identity_dict() # w_obj -> raw PyObject
self.py_objects_r2w = {} # addr of raw PyObject -> w_obj
+ self.exc_type = None
+ self.exc_value = None
Modified: pypy/trunk/pypy/module/cpyext/test/test_cpyext.py
==============================================================================
--- pypy/trunk/pypy/module/cpyext/test/test_cpyext.py (original)
+++ pypy/trunk/pypy/module/cpyext/test/test_cpyext.py Sat Mar 20 16:07:14 2010
@@ -143,3 +143,29 @@
module.drop_pi()
assert module.return_pi() == 3.14
assert module.return_pi() == 3.14
+
+ def test_exception(self):
+ import sys
+ init = """
+ if (Py_IsInitialized())
+ Py_InitModule("foo", methods);
+ """
+ body = """
+ PyObject* foo_pi(PyObject* self, PyObject *args)
+ {
+ PyErr_SetString(PyExc_Exception, "moo!");
+ return NULL;
+ }
+ static PyMethodDef methods[] = {
+ { "raise_exception", foo_pi, METH_NOARGS },
+ { NULL }
+ };
+ """
+ module = self.import_module(name='foo', init=init, body=body)
+ exc = raises(Exception, module.raise_exception)
+ if type(exc.value) is not Exception:
+ raise exc.value
+
+ assert exc.value.message == "moo!"
+
+
More information about the Pypy-commit
mailing list