[pypy-svn] r26115 - in pypy/dist/pypy/rpython/rctypes: . test tool

arigo at codespeak.net arigo at codespeak.net
Fri Apr 21 21:41:43 CEST 2006


Author: arigo
Date: Fri Apr 21 21:41:41 2006
New Revision: 26115

Modified:
   pypy/dist/pypy/rpython/rctypes/afunc.py
   pypy/dist/pypy/rpython/rctypes/apyobject.py
   pypy/dist/pypy/rpython/rctypes/test/test_ctypes.py
   pypy/dist/pypy/rpython/rctypes/test/test_rfunc.py
   pypy/dist/pypy/rpython/rctypes/tool/cpyobjspace.py
Log:
Use a ctypes trick: use a subclass W_Object of py_object.
This prevents automatic unwrapping: functions with
res_type == W_Object will really return a W_Object instance,
which is not the case if res_type == py_object.


Modified: pypy/dist/pypy/rpython/rctypes/afunc.py
==============================================================================
--- pypy/dist/pypy/rpython/rctypes/afunc.py	(original)
+++ pypy/dist/pypy/rpython/rctypes/afunc.py	Fri Apr 21 21:41:41 2006
@@ -21,6 +21,13 @@
         result_ctype = self.instance.restype
         if result_ctype is None:
             return None
+        if result_ctype is ctypes.py_object:
+            raise Exception("ctypes functions cannot have restype=py_object; "
+                            "set their restype to a subclass of py_object "
+                            "and call apyobject.register_py_object_subclass")
+            #... because then in ctypes you don't get automatic unwrapping.
+            #    That would not be annotatable, for the same reason that
+            #    reading the .value attribute of py_object is not annotatable
         s_result = SomeCTypesObject(result_ctype, SomeCTypesObject.OWNSMEMORY)
         return s_result.return_annotation()
 

Modified: pypy/dist/pypy/rpython/rctypes/apyobject.py
==============================================================================
--- pypy/dist/pypy/rpython/rctypes/apyobject.py	(original)
+++ pypy/dist/pypy/rpython/rctypes/apyobject.py	Fri Apr 21 21:41:41 2006
@@ -26,3 +26,9 @@
         from pypy.rpython.rctypes.rpyobject import CTypesPyObjRepr
         lowleveltype = lltype.Ptr(lltype.PyObject)
         return CTypesPyObjRepr(rtyper, s_pyobject, lowleveltype)
+
+
+def register_py_object_subclass(subcls):
+    assert issubclass(subcls, py_object)
+    CallEntry._register_value(subcls)
+    ObjEntry._register_type(subcls)

Modified: pypy/dist/pypy/rpython/rctypes/test/test_ctypes.py
==============================================================================
--- pypy/dist/pypy/rpython/rctypes/test/test_ctypes.py	(original)
+++ pypy/dist/pypy/rpython/rctypes/test/test_ctypes.py	Fri Apr 21 21:41:41 2006
@@ -178,3 +178,16 @@
     pythonapi.PyInt_AsLong.restype = c_long
     assert pythonapi.PyInt_AsLong(py_object(17L)) == 17
     py.test.raises(TypeError, "pythonapi.PyInt_AsLong(py_object('hello'))")
+
+def test_py_object_subclass():
+    # automatic unwrapping of the py_object result
+    pythonapi.PyInt_FromLong.argtypes = [c_long]
+    pythonapi.PyInt_FromLong.restype = py_object
+    assert isinstance(pythonapi.PyInt_FromLong(17), int)
+
+    # but not if we subclass it...
+    class W_Object(py_object):
+        pass
+    pythonapi.PyInt_FromLong.argtypes = [c_long]
+    pythonapi.PyInt_FromLong.restype = W_Object
+    assert isinstance(pythonapi.PyInt_FromLong(17), W_Object)

Modified: pypy/dist/pypy/rpython/rctypes/test/test_rfunc.py
==============================================================================
--- pypy/dist/pypy/rpython/rctypes/test/test_rfunc.py	(original)
+++ pypy/dist/pypy/rpython/rctypes/test/test_rfunc.py	Fri Apr 21 21:41:41 2006
@@ -183,24 +183,28 @@
         assert int(t1) <= t2 <= int(t3 + 1.0)
 
     def test_compile_pythonapi(self):
+        from pypy.rpython.rctypes import apyobject
+        class W_Object(py_object):
+            pass
+        apyobject.register_py_object_subclass(W_Object)
         PyInt_AsLong = pythonapi.PyInt_AsLong
-        PyInt_AsLong.argtypes = [py_object]
+        PyInt_AsLong.argtypes = [W_Object]
         PyInt_AsLong.restype = c_long
         assert PyInt_AsLong._flags_ & _FUNCFLAG_PYTHONAPI
 
         PyNumber_Add = pythonapi.PyNumber_Add
-        PyNumber_Add.argtypes = [py_object, py_object]
-        PyNumber_Add.restype = py_object
+        PyNumber_Add.argtypes = [W_Object, W_Object]
+        PyNumber_Add.restype = W_Object
 
         def fn1(x, crash):
-            pyobj = py_object(x)
+            pyobj = W_Object(x)
             pyobj = PyNumber_Add(pyobj, pyobj)
             x = PyInt_AsLong(pyobj)
             if crash:
                 # fn(sys.maxint, 1) should crash on PyInt_AsLong before
                 # it arrives here.  If by mistake it arrives here then
                 # we get a TypeError instead of the OverflowError
-                PyNumber_Add(py_object(5), py_object("x"))
+                PyNumber_Add(W_Object(5), W_Object("x"))
             return x
 
         fn = compile(fn1, [int, int])

Modified: pypy/dist/pypy/rpython/rctypes/tool/cpyobjspace.py
==============================================================================
--- pypy/dist/pypy/rpython/rctypes/tool/cpyobjspace.py	(original)
+++ pypy/dist/pypy/rpython/rctypes/tool/cpyobjspace.py	Fri Apr 21 21:41:41 2006
@@ -1,58 +1,65 @@
 import sys
 from ctypes import *
 
+class W_Object(py_object):
+    "A py_object subclass, representing wrapped objects for the CPyObjSpace."
+
+from pypy.rpython.rctypes import apyobject
+apyobject.register_py_object_subclass(W_Object)
+
+
 assert sys.version < (2, 5), "XXX fix Py_ssize_t for Python 2.5"
 Py_ssize_t = c_int
 
 PyObject_GetAttr = pythonapi.PyObject_GetAttr
-PyObject_GetAttr.argtypes = [py_object, py_object]
-PyObject_GetAttr.restype = py_object
+PyObject_GetAttr.argtypes = [W_Object, W_Object]
+PyObject_GetAttr.restype = W_Object
 
 PyImport_ImportModule = pythonapi.PyImport_ImportModule
 PyImport_ImportModule.argtypes = [c_char_p]
-PyImport_ImportModule.restype = py_object
+PyImport_ImportModule.restype = W_Object
 
 PyInt_FromLong = pythonapi.PyInt_FromLong
 PyInt_FromLong.argtypes = [c_long]
-PyInt_FromLong.restype = py_object
+PyInt_FromLong.restype = W_Object
 
 PyString_FromStringAndSize = pythonapi.PyString_FromStringAndSize
 PyString_FromStringAndSize.argtypes = [c_char_p, Py_ssize_t]
-PyString_FromStringAndSize.restype = py_object
+PyString_FromStringAndSize.restype = W_Object
 
 PyString_InternInPlace = pythonapi.PyString_InternInPlace
-PyString_InternInPlace.argtypes = [POINTER(py_object)]
+PyString_InternInPlace.argtypes = [POINTER(W_Object)]
 PyString_InternInPlace.restype = None
 
 PyObject_SetItem = pythonapi.PyObject_SetItem
-PyObject_SetItem.argtypes = [py_object, py_object, py_object]
+PyObject_SetItem.argtypes = [W_Object, W_Object, W_Object]
 PyObject_SetItem.restype = c_int
 
 PyObject_Call = pythonapi.PyObject_Call
-PyObject_Call.argtypes = [py_object, py_object, py_object]
-PyObject_Call.restype = py_object
+PyObject_Call.argtypes = [W_Object, W_Object, W_Object]
+PyObject_Call.restype = W_Object
 
 PyTuple_New = pythonapi.PyTuple_New
 PyTuple_New.argtypes = [Py_ssize_t]
-PyTuple_New.restype = py_object
+PyTuple_New.restype = W_Object
 
 PyDict_New = pythonapi.PyDict_New
 PyDict_New.argtypes = []
-PyDict_New.restype = py_object
+PyDict_New.restype = W_Object
 
 PyDict_SetItem = pythonapi.PyDict_SetItem
-PyDict_SetItem.argtypes = [py_object, py_object, py_object]
+PyDict_SetItem.argtypes = [W_Object, W_Object, W_Object]
 PyDict_SetItem.restype = c_int
 
 
 class CPyObjSpace:
-    W_Object = py_object
+    W_Object = W_Object
 
     def __init__(self):
-        self.w_int = py_object(int)
-        self.w_None = py_object(None)
-        self.w_False = py_object(False)
-        self.w_True = py_object(True)
+        self.w_int   = W_Object(int)
+        self.w_None  = W_Object(None)
+        self.w_False = W_Object(False)
+        self.w_True  = W_Object(True)
 
     def getbuiltinmodule(self, name):
         return PyImport_ImportModule(name)



More information about the Pypy-commit mailing list