[pypy-commit] pypy release-pypy3.5-5.x: tp_descr_set on built-in types

arigo pypy.commits at gmail.com
Mon Jun 5 15:58:18 EDT 2017


Author: Armin Rigo <arigo at tunes.org>
Branch: release-pypy3.5-5.x
Changeset: r91539:a39af0be3a22
Date: 2017-06-05 22:57 +0300
http://bitbucket.org/pypy/pypy/changeset/a39af0be3a22/

Log:	tp_descr_set on built-in types (grafted from
	7ca42aeab616fee1898cd0b2bdaef48be7825e3b)

diff --git a/pypy/module/cpyext/slotdefs.py b/pypy/module/cpyext/slotdefs.py
--- a/pypy/module/cpyext/slotdefs.py
+++ b/pypy/module/cpyext/slotdefs.py
@@ -826,11 +826,32 @@
 
         @slot_function([PyObject, PyObject, PyObject], PyObject)
         @func_renamer("cpyext_%s_%s" % (name.replace('.', '_'), typedef.name))
-        def slot_tp_descr_get(space, w_self, w_arg1, w_arg2):
-            if w_arg1 is None:
-                w_arg1 = space.w_None
-            return space.call_function(get_fn, w_self, w_arg1, w_arg2)
+        def slot_tp_descr_get(space, w_self, w_obj, w_value):
+            if w_obj is None:
+                w_obj = space.w_None
+            return space.call_function(get_fn, w_self, w_obj, w_value)
         slot_func = slot_tp_descr_get
+    elif name == 'tp_descr_set':
+        set_fn = w_type.getdictvalue(space, '__set__')
+        delete_fn = w_type.getdictvalue(space, '__delete__')
+        if set_fn is None and delete_fn is None:
+            return
+
+        @slot_function([PyObject, PyObject, PyObject], rffi.INT_real, error=-1)
+        @func_renamer("cpyext_%s_%s" % (name.replace('.', '_'), typedef.name))
+        def slot_tp_descr_set(space, w_self, w_obj, w_value):
+            if w_value is not None:
+                if set_fn is None:
+                    raise oefmt(space.w_TypeError,
+                                "%s object has no __set__", typedef.name)
+                space.call_function(set_fn, w_self, w_obj, w_value)
+            else:
+                if delete_fn is None:
+                    raise oefmt(space.w_TypeError,
+                                "%s object has no __delete__", typedef.name)
+                space.call_function(delete_fn, w_self, w_obj)
+            return 0
+        slot_func = slot_tp_descr_set
     else:
         # missing: tp_as_number.nb_nonzero, tp_as_number.nb_coerce
         # tp_as_sequence.c_sq_contains, tp_as_sequence.c_sq_length
diff --git a/pypy/module/cpyext/test/test_typeobject.py b/pypy/module/cpyext/test/test_typeobject.py
--- a/pypy/module/cpyext/test/test_typeobject.py
+++ b/pypy/module/cpyext/test/test_typeobject.py
@@ -405,6 +405,42 @@
         assert type(ubm) is type(Y.unbound_method_example)
         assert ubm(42) == 43
 
+    def test_tp_descr_set(self):
+        module = self.import_extension('foo', [
+           ("tp_descr_set", "METH_O",
+            '''
+                if (args->ob_type->tp_descr_set == NULL) {
+                    Py_INCREF(Py_False);
+                    return Py_False;
+                }
+                if (args->ob_type->tp_descr_set(args, Py_False, Py_True) != 0)
+                    return NULL;
+                if (args->ob_type->tp_descr_set(args, Py_Ellipsis, NULL) != 0)
+                    return NULL;
+
+                Py_INCREF(Py_True);
+                return Py_True;
+             '''
+             )
+            ])
+        assert module.tp_descr_set(42) is False
+
+        class Y(object):
+            def __set__(self, obj, value):
+                assert obj is False
+                assert value is True
+            def __delete__(self, obj):
+                assert obj is Ellipsis
+        assert module.tp_descr_set(Y()) is True
+        #
+        def pset(obj, value):
+            assert obj is False
+            assert value is True
+        def pdel(obj):
+            assert obj is Ellipsis
+        p = property(lambda: "never used", pset, pdel)
+        assert module.tp_descr_set(p) is True
+
 
 class TestTypes(BaseApiTest):
     def test_type_attributes(self, space, api):


More information about the pypy-commit mailing list