[pypy-svn] r74866 - in pypy/trunk/pypy/module/cpyext: . test

afa at codespeak.net afa at codespeak.net
Fri May 28 18:12:46 CEST 2010


Author: afa
Date: Fri May 28 18:12:45 2010
New Revision: 74866

Modified:
   pypy/trunk/pypy/module/cpyext/object.py
   pypy/trunk/pypy/module/cpyext/slotdefs.py
   pypy/trunk/pypy/module/cpyext/test/foo.c
   pypy/trunk/pypy/module/cpyext/test/test_typeobject.py
Log:
Implement forwarding calls from __setattr__ and __delattr__ to tp_setattro
Also a test for PyObject_GenericSetAttr when used to delete attributes.


Modified: pypy/trunk/pypy/module/cpyext/object.py
==============================================================================
--- pypy/trunk/pypy/module/cpyext/object.py	(original)
+++ pypy/trunk/pypy/module/cpyext/object.py	Fri May 28 18:12:45 2010
@@ -320,9 +320,14 @@
     over setting the attribute in the instance dictionary. Otherwise, the
     attribute is set in the object's __dict__ (if present).  Otherwise,
     an AttributeError is raised and -1 is returned."""
-    from pypy.objspace.descroperation import object_setattr
-    w_descr = object_setattr(space)
-    return space.get_and_call_function(w_descr, w_obj, w_name, w_value)
+    from pypy.objspace.descroperation import object_setattr, object_delattr
+    if w_value is not None:
+        w_descr = object_setattr(space)
+        space.get_and_call_function(w_descr, w_obj, w_name, w_value)
+    else:
+        w_descr = object_delattr(space)
+        space.get_and_call_function(w_descr, w_obj, w_name)
+    return 0
 
 @cpython_api([PyObject, PyObject], rffi.INT_real, error=-1)
 def PyObject_IsInstance(space, w_inst, w_cls):

Modified: pypy/trunk/pypy/module/cpyext/slotdefs.py
==============================================================================
--- pypy/trunk/pypy/module/cpyext/slotdefs.py	(original)
+++ pypy/trunk/pypy/module/cpyext/slotdefs.py	Fri May 28 18:12:45 2010
@@ -1,12 +1,11 @@
 import re
 
 from pypy.rpython.lltypesystem import rffi, lltype
-from pypy.module.cpyext.api import generic_cpy_call, cpython_api, \
-        PyObject
-from pypy.module.cpyext.typeobjectdefs import unaryfunc, wrapperfunc,\
-        ternaryfunc, PyTypeObjectPtr, binaryfunc, getattrfunc, lenfunc,\
-        ssizeargfunc, ssizessizeargfunc, ssizeobjargproc, iternextfunc,\
-        initproc
+from pypy.module.cpyext.api import generic_cpy_call, cpython_api, PyObject
+from pypy.module.cpyext.typeobjectdefs import (
+    unaryfunc, wrapperfunc, ternaryfunc, PyTypeObjectPtr, binaryfunc,
+    getattrfunc, setattrofunc, lenfunc, ssizeargfunc, ssizessizeargfunc,
+    ssizeobjargproc, iternextfunc, initproc)
 from pypy.module.cpyext.pyobject import from_ref
 from pypy.module.cpyext.pyerrors import PyErr_Occurred
 from pypy.module.cpyext.state import State
@@ -53,6 +52,24 @@
     finally:
         rffi.free_charp(name_ptr)
 
+def wrap_setattr(space, w_self, w_args, func):
+    func_target = rffi.cast(setattrofunc, func)
+    check_num_args(space, w_args, 2)
+    w_name, w_value = space.fixedview(w_args)
+    # XXX "Carlo Verre hack"?
+    if generic_cpy_call(space, func_target, w_self, w_name, w_value) < 0:
+        space.fromcache(State).check_and_raise_exception(always=True)
+    return space.w_None
+
+def wrap_delattr(space, w_self, w_args, func):
+    func_target = rffi.cast(setattrofunc, func)
+    check_num_args(space, w_args, 1)
+    w_name, = space.fixedview(w_args)
+    # XXX "Carlo Verre hack"?
+    if generic_cpy_call(space, func_target, w_self, w_name, None) < 0:
+        space.fromcache(State).check_and_raise_exception(always=True)
+    return space.w_None
+
 def wrap_call(space, w_self, w_args, func, w_kwds):
     func_target = rffi.cast(ternaryfunc, func)
     return generic_cpy_call(space, func_target, w_self, w_args, w_kwds)
@@ -135,11 +152,15 @@
 
 # adopted from typeobject.c
 def FLSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC, FLAGS):
-    wrapper = globals().get(WRAPPER, Ellipsis)
     if WRAPPER is None:
         wrapper = None
+    else:
+        wrapper = globals().get(WRAPPER, Ellipsis)
+
+    # irregular interface, because of tp_getattr/tp_getattro confusion
     if NAME == "__getattr__":
         wrapper = wrap_getattr
+
     function = globals().get(FUNCTION, None)
     slotname = ("c_" + SLOT).split(".")
     assert FLAGS == 0 or FLAGS == PyWrapperFlag_KEYWORDS

Modified: pypy/trunk/pypy/module/cpyext/test/foo.c
==============================================================================
--- pypy/trunk/pypy/module/cpyext/test/foo.c	(original)
+++ pypy/trunk/pypy/module/cpyext/test/foo.c	Fri May 28 18:12:45 2010
@@ -114,6 +114,25 @@
     return kwds;
 }
 
+static int
+foo_setattro(fooobject *self, PyObject *name, PyObject *value)
+{
+    char *name_str;
+    if (!PyString_Check(name)) {
+        PyErr_SetObject(PyExc_AttributeError, name);
+        return -1;
+    }
+    name_str = PyString_AsString(name);
+    if (strcmp(name_str, "set_foo") == 0)
+    {
+        long v = PyInt_AsLong(value);
+        if (v == -1 && PyErr_Occurred())
+            return -1;
+        self->foo = v;
+    }
+    return PyObject_GenericSetAttr(self, name, value);
+}
+
 static PyMemberDef foo_members[] = {
     {"int_member", T_INT, offsetof(fooobject, foo), 0,
      "A helpful docstring."},
@@ -151,7 +170,7 @@
     foo_call,                /*tp_call*/
     0,                       /*tp_str*/
     0,                       /*tp_getattro*/
-    0,                       /*tp_setattro*/
+    foo_setattro,            /*tp_setattro*/
     0,                       /*tp_as_buffer*/
     Py_TPFLAGS_DEFAULT,      /*tp_flags*/
     0,                       /*tp_doc*/

Modified: pypy/trunk/pypy/module/cpyext/test/test_typeobject.py
==============================================================================
--- pypy/trunk/pypy/module/cpyext/test/test_typeobject.py	(original)
+++ pypy/trunk/pypy/module/cpyext/test/test_typeobject.py	Fri May 28 18:12:45 2010
@@ -72,6 +72,9 @@
         del obj.object_member_ex
         raises(AttributeError, "del obj.object_member_ex")
 
+        obj.set_foo = 32
+        assert obj.foo == 32
+
     def test_typeobject_string_member(self):
         module = self.import_module(name='foo')
         obj = module.new()



More information about the Pypy-commit mailing list