[pypy-svn] r72743 - in pypy/branch/cpython-extension/pypy: module/cpyext module/cpyext/include module/cpyext/test objspace/std

afa at codespeak.net afa at codespeak.net
Wed Mar 24 18:55:34 CET 2010


Author: afa
Date: Wed Mar 24 18:55:32 2010
New Revision: 72743

Modified:
   pypy/branch/cpython-extension/pypy/module/cpyext/api.py
   pypy/branch/cpython-extension/pypy/module/cpyext/floatobject.py
   pypy/branch/cpython-extension/pypy/module/cpyext/include/pyerrors.h
   pypy/branch/cpython-extension/pypy/module/cpyext/object.py
   pypy/branch/cpython-extension/pypy/module/cpyext/pyerrors.py
   pypy/branch/cpython-extension/pypy/module/cpyext/test/conftest.py
   pypy/branch/cpython-extension/pypy/module/cpyext/test/test_cpyext.py
   pypy/branch/cpython-extension/pypy/module/cpyext/test/test_floatobject.py
   pypy/branch/cpython-extension/pypy/module/cpyext/test/test_object.py
   pypy/branch/cpython-extension/pypy/objspace/std/fake.py
Log:
more progress:
- add a way to specify the value returned when RPython raises an exception
- greatly simplify tests for the regular part of the C API: call it directly from interp-level.
- Add support for PyErr_Clear() and PyErr_Occurred()
- fix attribute access of FakedInstance objects, very useful in tests!


Modified: pypy/branch/cpython-extension/pypy/module/cpyext/api.py
==============================================================================
--- pypy/branch/cpython-extension/pypy/module/cpyext/api.py	(original)
+++ pypy/branch/cpython-extension/pypy/module/cpyext/api.py	Wed Mar 24 18:55:32 2010
@@ -43,14 +43,17 @@
     setattr(CConfig_constants, name, rffi_platform.ConstantInteger(name))
 globals().update(rffi_platform.configure(CConfig_constants))
 
+_NOT_SPECIFIED = object()
 
 class ApiFunction:
-    def __init__(self, argtypes, restype, callable, borrowed):
+    def __init__(self, argtypes, restype, callable, borrowed, error):
         self.argtypes = argtypes
         self.restype = restype
         self.functype = lltype.Ptr(lltype.FuncType(argtypes, restype))
         self.callable = callable
         self.borrowed = borrowed
+        if error is not _NOT_SPECIFIED:
+            self.error_value = error
 
         # extract the signature from the (CPython-level) code object
         from pypy.interpreter import pycode
@@ -60,11 +63,12 @@
         self.argnames = argnames[1:]
         assert len(self.argnames) == len(self.argtypes)
 
+def cpython_api(argtypes, restype, borrowed=False, error=_NOT_SPECIFIED):
+    if restype is PyObject and error is _NOT_SPECIFIED:
+        error = None
 
-def cpython_api(argtypes, restype, borrowed=False):
     def decorate(func):
-        api_function = ApiFunction(argtypes, restype, func, borrowed)
-        FUNCTIONS[func.func_name] = api_function
+        api_function = ApiFunction(argtypes, restype, func, borrowed, error)
 
         def unwrapper(space, *args):
             "NOT_RPYTHON: XXX unsure"
@@ -82,6 +86,14 @@
                 newargs.append(arg)
             try:
                 return func(space, *newargs)
+            except OperationError, e:
+                if not hasattr(api_function, "error_value"):
+                    raise
+                state = space.fromcache(State)
+                e.normalize_exception(space)
+                state.exc_type = e.w_type
+                state.exc_value = e.get_w_value(space)
+                return api_function.error_value
             finally:
                 from pypy.module.cpyext.macros import Py_DECREF
                 for arg in to_decref:
@@ -89,6 +101,8 @@
 
         func.api_func = api_function
         unwrapper.api_func = api_function
+        FUNCTIONS[func.func_name] = api_function
+        INTERPLEVEL_API[func.func_name] = unwrapper
         return unwrapper
     return decorate
 
@@ -105,6 +119,7 @@
     TYPES[configname] = forward
     return forward
 
+INTERPLEVEL_API = {}
 FUNCTIONS = {}
 FUNCTIONS_C = {}
 TYPES = {}

Modified: pypy/branch/cpython-extension/pypy/module/cpyext/floatobject.py
==============================================================================
--- pypy/branch/cpython-extension/pypy/module/cpyext/floatobject.py	(original)
+++ pypy/branch/cpython-extension/pypy/module/cpyext/floatobject.py	Wed Mar 24 18:55:32 2010
@@ -5,6 +5,6 @@
 def PyFloat_FromDouble(space, value):
     return space.wrap(value)
 
- at cpython_api([PyObject], lltype.Float)
+ at cpython_api([PyObject], lltype.Float, error=-1)
 def PyFloat_AsDouble(space, w_obj):
     return space.float_w(space.float(w_obj))

Modified: pypy/branch/cpython-extension/pypy/module/cpyext/include/pyerrors.h
==============================================================================
--- pypy/branch/cpython-extension/pypy/module/cpyext/include/pyerrors.h	(original)
+++ pypy/branch/cpython-extension/pypy/module/cpyext/include/pyerrors.h	Wed Mar 24 18:55:32 2010
@@ -9,6 +9,8 @@
 
 PyAPI_DATA(PyObject *) PyExc_Exception;
 void PyErr_SetString(PyObject *, char *);
+PyObject * PyErr_Occurred(void);
+void PyErr_Clear(PyObject *, char *);
 
 #ifdef __cplusplus
 }

Modified: pypy/branch/cpython-extension/pypy/module/cpyext/object.py
==============================================================================
--- pypy/branch/cpython-extension/pypy/module/cpyext/object.py	(original)
+++ pypy/branch/cpython-extension/pypy/module/cpyext/object.py	Wed Mar 24 18:55:32 2010
@@ -26,11 +26,11 @@
     obj_voidp = rffi.cast(rffi.VOIDP_real, obj)
     generic_cpy_call(space, pto.c_tp_free, obj_voidp)
 
- at cpython_api([PyObject], rffi.INT_real)
+ at cpython_api([PyObject], rffi.INT_real, error=-1)
 def PyObject_IsTrue(space, w_obj):
     return space.is_true(w_obj)
 
- at cpython_api([PyObject], rffi.INT_real)
+ at cpython_api([PyObject], rffi.INT_real, error=-1)
 def PyObject_Not(space, w_obj):
     return not space.is_true(w_obj)
 

Modified: pypy/branch/cpython-extension/pypy/module/cpyext/pyerrors.py
==============================================================================
--- pypy/branch/cpython-extension/pypy/module/cpyext/pyerrors.py	(original)
+++ pypy/branch/cpython-extension/pypy/module/cpyext/pyerrors.py	Wed Mar 24 18:55:32 2010
@@ -1,7 +1,7 @@
 from pypy.rpython.lltypesystem import rffi, lltype
 from pypy.interpreter.error import OperationError
 from pypy.module.cpyext.api import cpython_api, PyObject, make_ref
-
+from pypy.module.cpyext.state import State
 
 @cpython_api([PyObject, rffi.CCHARP], lltype.Void)
 def PyErr_SetString(space, w_type, message_ptr):
@@ -9,6 +9,16 @@
     w_obj = space.call_function(w_type, space.wrap(message))
     raise OperationError(w_type, w_obj)
 
+ at cpython_api([], PyObject)
+def PyErr_Occurred(space):
+    state = space.fromcache(State)
+    return state.exc_value
+
+ at cpython_api([], lltype.Void)
+def PyErr_Clear(space):
+    state = space.fromcache(State)
+    state.exc_type = None
+    state.exc_value = None
 
 @cpython_api([], lltype.Void)
 def PyErr_BadInternalCall(space):

Modified: pypy/branch/cpython-extension/pypy/module/cpyext/test/conftest.py
==============================================================================
--- pypy/branch/cpython-extension/pypy/module/cpyext/test/conftest.py	(original)
+++ pypy/branch/cpython-extension/pypy/module/cpyext/test/conftest.py	Wed Mar 24 18:55:32 2010
@@ -6,3 +6,7 @@
         if option.runappdirect:
             py.test.skip("cannot be run by py.test -A")
         return super(Directory, self).collect()
+
+def pytest_funcarg__api(request):
+    return request.cls.api
+

Modified: pypy/branch/cpython-extension/pypy/module/cpyext/test/test_cpyext.py
==============================================================================
--- pypy/branch/cpython-extension/pypy/module/cpyext/test/test_cpyext.py	(original)
+++ pypy/branch/cpython-extension/pypy/module/cpyext/test/test_cpyext.py	Wed Mar 24 18:55:32 2010
@@ -54,6 +54,18 @@
         standalone=False)
     return str(soname)
 
+class BaseApiTest:
+    def setup_class(cls):
+        class CAPI:
+            def __getattr__(self, name):
+                return getattr(cls.space, name)
+        cls.api = CAPI()
+        CAPI.__dict__.update(api.INTERPLEVEL_API)
+
+    def teardown_method(self, func):
+        state = self.space.fromcache(State)
+        assert state.exc_value is None
+
 class AppTestCpythonExtensionBase:
     def setup_class(cls):
         cls.space = gettestobjspace(usemodules=['cpyext'])

Modified: pypy/branch/cpython-extension/pypy/module/cpyext/test/test_floatobject.py
==============================================================================
--- pypy/branch/cpython-extension/pypy/module/cpyext/test/test_floatobject.py	(original)
+++ pypy/branch/cpython-extension/pypy/module/cpyext/test/test_floatobject.py	Wed Mar 24 18:55:32 2010
@@ -1,22 +1,9 @@
-from pypy.module.cpyext.test.test_cpyext import AppTestCpythonExtensionBase
+from pypy.module.cpyext.test.test_cpyext import BaseApiTest
 
-import py
-import sys
+class TestFloatObject(BaseApiTest):
+    def test_floatobject(self, space, api):
+        assert space.unwrap(api.PyFloat_FromDouble(3.14)) == 3.14
+        assert api.PyFloat_AsDouble(space.wrap(23.45)) == 23.45
 
-class AppTestFloatObject(AppTestCpythonExtensionBase):
-    def test_floatobject(self):
-        module = self.import_extension('foo', [
-            ("FromDouble", "METH_NOARGS",
-             """
-                 return PyFloat_FromDouble(3.14);
-             """),
-            ("AsDouble", "METH_NOARGS",
-             """
-                 PyObject* obj = PyFloat_FromDouble(23.45);
-                 double d = PyFloat_AsDouble(obj);
-                 Py_DECREF(obj);
-                 return PyFloat_FromDouble(d);
-             """),
-            ])
-        assert module.FromDouble() == 3.14
-        assert module.AsDouble() == 23.45
+        assert api.PyFloat_AsDouble(space.w_None) == -1
+        api.PyErr_Clear()

Modified: pypy/branch/cpython-extension/pypy/module/cpyext/test/test_object.py
==============================================================================
--- pypy/branch/cpython-extension/pypy/module/cpyext/test/test_object.py	(original)
+++ pypy/branch/cpython-extension/pypy/module/cpyext/test/test_object.py	Wed Mar 24 18:55:32 2010
@@ -1,66 +1,40 @@
-from pypy.module.cpyext.test.test_cpyext import AppTestCpythonExtensionBase
+from pypy.module.cpyext.test.test_cpyext import BaseApiTest
 
-import py
-import sys
+class TestObject(BaseApiTest):
+    def test_IsTrue(self, space, api):
+        assert api.PyObject_IsTrue(space.wrap(1.0)) == 1
+        assert api.PyObject_IsTrue(space.wrap(False)) == 0
+        assert api.PyObject_IsTrue(space.wrap(0)) == 0
+
+    def test_Not(self, space, api):
+        assert api.PyObject_Not(space.wrap(False)) == 1
+        assert api.PyObject_Not(space.wrap(0)) == 1
+        assert api.PyObject_Not(space.wrap(True)) == 0
+        assert api.PyObject_Not(space.wrap(3.14)) == 0
+
+    def test_exception(self, space, api):
+        class C:
+            def __nonzero__(self):
+                raise ValueError
+
+        assert api.PyObject_IsTrue(space.wrap(C())) == -1
+        assert api.PyObject_Not(space.wrap(C())) == -1
+        api.PyErr_Clear()
+
+    def test_HasAttr(self, space, api):
+        hasattr_ = lambda w_obj, name: api.PyObject_HasAttr(w_obj,
+                                                            space.wrap(name))
+        assert hasattr_(space.wrap(''), '__len__')
+        assert hasattr_(space.w_int, '__eq__')
+        assert not hasattr_(space.w_int, 'nonexistingattr')
 
-
-class AppTestObject(AppTestCpythonExtensionBase):
-    def test_IsTrue(self):
-        module = self.import_extension('foo', [
-            ("is_true", "METH_VARARGS",
-             """
-                 PyObject* arg = PyTuple_GetItem(args, 0);
-                 return PyBool_FromLong(PyObject_IsTrue(arg));
-             """),
-            ])
-        assert module.is_true(True)
-        assert module.is_true(1.0)
-        assert not module.is_true(False)
-        assert not module.is_true(0)
-
-    def test_Not(self):
-        module = self.import_extension('foo', [
-            ("not_", "METH_VARARGS",
-             """
-                 PyObject* arg = PyTuple_GetItem(args, 0);
-                 return PyBool_FromLong(PyObject_Not(arg));
-             """),
-            ])
-        assert module.not_(False)
-        assert module.not_(0)
-        assert not module.not_(True)
-        assert not module.not_(3.14)
-
-    def test_HasAttr(self):
-        module = self.import_extension('foo', [
-            ("hasattr", "METH_VARARGS",
-             """
-                 PyObject* obj = PyTuple_GetItem(args, 0);
-                 PyObject* name = PyTuple_GetItem(args, 1);
-                 return PyBool_FromLong(PyObject_HasAttr(obj, name));
-             """),
-            ])
-        assert module.hasattr('', '__len__')
-        assert module.hasattr(int, '__eq__')
-        assert not module.hasattr(int, 'nonexistingattr')
-
-    def test_SetAttr(self):
-        module = self.import_extension('foo', [
-            ("setattr", "METH_VARARGS",
-             """
-                 PyObject* obj = PyTuple_GetItem(args, 0);
-                 PyObject* name = PyTuple_GetItem(args, 1);
-                 PyObject* value = PyTuple_GetItem(args, 2);
-                 PyObject_SetAttr(obj, name, value);
-                 Py_INCREF(Py_None);
-                 return Py_None;
-             """),
-            ])
+    def test_SetAttr(self, space, api):
         class X:
             pass
         x = X()
-        module.setattr(x, 'test', 5)
-        assert hasattr(x, 'test')
+        api.PyObject_SetAttr(space.wrap(x), space.wrap('test'), space.wrap(5))
+        assert not api.PyErr_Occurred()
         assert x.test == 5
-        module.setattr(x, 'test', 10)
+        assert api.PyObject_HasAttr(space.wrap(x), space.wrap('test'))
+        api.PyObject_SetAttr(space.wrap(x), space.wrap('test'), space.wrap(10))
         assert x.test == 10

Modified: pypy/branch/cpython-extension/pypy/objspace/std/fake.py
==============================================================================
--- pypy/branch/cpython-extension/pypy/objspace/std/fake.py	(original)
+++ pypy/branch/cpython-extension/pypy/objspace/std/fake.py	Wed Mar 24 18:55:32 2010
@@ -114,6 +114,9 @@
             cpy_type.__name__, base, **kw)
         def __init__(w_self, space, val):
             w_self.val = val
+            w_self.space = space
+        def getdict(w_self):
+            return w_self.space.wrap(w_self.val.__dict__)
         def unwrap(w_self, space):
             return w_self.val
     W_Fake.__name__ = 'W_Fake%s'%(cpy_type.__name__.capitalize())



More information about the Pypy-commit mailing list