[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