[pypy-commit] pypy default: merge cpyext-slotdefs2 which fills more slots when creating a PyTypeObject

mattip pypy.commits at gmail.com
Thu Jul 14 15:51:46 EDT 2016


Author: Matti Picus <matti.picus at gmail.com>
Branch: 
Changeset: r85713:ac0972f36db2
Date: 2016-07-14 14:45 -0500
http://bitbucket.org/pypy/pypy/changeset/ac0972f36db2/

Log:	merge cpyext-slotdefs2 which fills more slots when creating a
	PyTypeObject

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
@@ -380,6 +380,7 @@
                           ('tp_as_number.c_nb_absolute', '__abs__'),
                           ('tp_as_number.c_nb_invert', '__invert__'),
                           ('tp_as_number.c_nb_index', '__index__'),
+                          ('tp_as_number.c_nb_hex', '__hex__'),
                           ('tp_str', '__str__'),
                           ('tp_repr', '__repr__'),
                           ('tp_iter', '__iter__'),
@@ -398,7 +399,7 @@
 
     # binary functions
     for tp_name, attr in [('tp_as_number.c_nb_add', '__add__'),
-                          ('tp_as_number.c_nb_subtract', '__subtract__'),
+                          ('tp_as_number.c_nb_subtract', '__sub__'),
                           ('tp_as_number.c_nb_multiply', '__mul__'),
                           ('tp_as_number.c_nb_divide', '__div__'),
                           ('tp_as_number.c_nb_remainder', '__mod__'),
@@ -408,6 +409,8 @@
                           ('tp_as_number.c_nb_and', '__and__'),
                           ('tp_as_number.c_nb_xor', '__xor__'),
                           ('tp_as_number.c_nb_or', '__or__'),
+                          ('tp_as_sequence.c_sq_concat', '__add__'),
+                          ('tp_as_sequence.c_sq_inplace_concat', '__iadd__')
                           ]:
         if name == tp_name:
             slot_fn = w_type.getdictvalue(space, attr)
@@ -421,8 +424,26 @@
             api_func = slot_func.api_func
             handled = True
 
+    # binary-with-Py_ssize_t-type
+    for tp_name, attr in [('tp_as_sequence.c_sq_item', '__getitem'),
+                          ('tp_as_sequence.c_sq_repeat', '__mul__'),
+                          ('tp_as_sequence.c_sq_repeat', '__mul__'),
+                          ('tp_as_sequence.c_sq_inplace_repeat', '__imul__'),
+                          ]:
+        if name == tp_name:
+            slot_fn = w_type.getdictvalue(space, attr)
+            if slot_fn is None:
+                return
+
+            @cpython_api([PyObject, Py_ssize_t], PyObject, header=header)
+            @func_renamer("cpyext_%s_%s" % (name.replace('.', '_'), typedef.name))
+            def slot_func(space, w_self, arg):
+                return space.call_function(slot_fn, w_self, space.wrap(arg))
+            api_func = slot_func.api_func
+            handled = True
+
     # ternary functions
-    for tp_name, attr in [('tp_as_number.c_nb_power', ''),
+    for tp_name, attr in [('tp_as_number.c_nb_power', '__pow__'),
                           ]:
         if name == tp_name:
             slot_fn = w_type.getdictvalue(space, attr)
@@ -522,6 +543,8 @@
         api_func = slot_tp_new.api_func
     else:
         # missing: tp_as_number.nb_nonzero, tp_as_number.nb_coerce
+        # tp_as_sequence.c_sq_contains, tp_as_sequence.c_sq_length
+        # richcmpfunc(s)
         return
 
     return lambda: llhelper(api_func.functype, api_func.get_wrapper(space))
diff --git a/pypy/module/cpyext/test/test_listobject.py b/pypy/module/cpyext/test/test_listobject.py
--- a/pypy/module/cpyext/test/test_listobject.py
+++ b/pypy/module/cpyext/test/test_listobject.py
@@ -64,7 +64,7 @@
         assert space.unwrap(w_s) == [2, 1]
 
 class AppTestListObject(AppTestCpythonExtensionBase):
-    def test_listobject(self):
+    def test_basic_listobject(self):
         import sys
         module = self.import_extension('foo', [
             ("newlist", "METH_NOARGS",
@@ -104,6 +104,15 @@
              Py_RETURN_NONE;
              """
              ),
+            ('test_tp_as_', "METH_NOARGS",
+             '''
+               PyObject *l = PyList_New(3);
+               int ok = l->ob_type->tp_as_sequence != NULL; /* 1 */
+               ok += 2 * (l->ob_type->tp_as_number == NULL); /* 2 */
+               Py_DECREF(l);
+               return PyLong_FromLong(ok); /* should be 3 */
+             '''
+             ),
             ])
         l = module.newlist()
         assert l == [3, -5, 1000]
@@ -137,6 +146,9 @@
         module.setlistitem(l,0)
         assert l == [None, 2, 3]
 
+        # tp_as_sequence should be filled, but tp_as_number should be NULL
+        assert module.test_tp_as_() == 3
+
     def test_list_macros(self):
         """The PyList_* macros cast, and calls expecting that build."""
         module = self.import_extension('foo', [
diff --git a/pypy/module/cpyext/test/test_longobject.py b/pypy/module/cpyext/test/test_longobject.py
--- a/pypy/module/cpyext/test/test_longobject.py
+++ b/pypy/module/cpyext/test/test_longobject.py
@@ -227,4 +227,40 @@
              """)])
         assert module.from_str() == 0
 
-
+    def test_slots(self):
+        module = self.import_extension('foo', [
+            ("has_sub", "METH_NOARGS",
+             """
+                PyObject *ret, *obj = PyLong_FromLong(42);
+                if (obj->ob_type->tp_as_number->nb_subtract)
+                    ret = obj->ob_type->tp_as_number->nb_subtract(obj, obj);
+                else
+                    ret = PyLong_FromLong(-1);
+                Py_DECREF(obj);
+                return ret;
+             """),
+             ("has_pow", "METH_NOARGS",
+             """
+                PyObject *ret, *obj = PyLong_FromLong(42);
+                PyObject *one = PyLong_FromLong(1);
+                if (obj->ob_type->tp_as_number->nb_power)
+                    ret = obj->ob_type->tp_as_number->nb_power(obj, one, one);
+                else
+                    ret = PyLong_FromLong(-1);
+                Py_DECREF(obj);
+                return ret;
+             """),
+            ("has_hex", "METH_NOARGS",
+             """
+                PyObject *ret, *obj = PyLong_FromLong(42);
+                if (obj->ob_type->tp_as_number->nb_hex)
+                    ret = obj->ob_type->tp_as_number->nb_hex(obj);
+                else
+                    ret = PyLong_FromLong(-1);
+                Py_DECREF(obj);
+                return ret;
+             """)])
+        assert module.has_sub() == 0
+        assert module.has_pow() == 0
+        assert module.has_hex() == '0x2aL'
+                
diff --git a/pypy/module/cpyext/typeobject.py b/pypy/module/cpyext/typeobject.py
--- a/pypy/module/cpyext/typeobject.py
+++ b/pypy/module/cpyext/typeobject.py
@@ -238,7 +238,7 @@
             i += 1
 
 def update_all_slots(space, w_type, pto):
-    #  XXX fill slots in pto
+    # fill slots in pto
     # Not very sure about it, but according to
     # test_call_tp_dealloc_when_created_from_python, we should not
     # overwrite slots that are already set: these ones are probably
@@ -272,6 +272,15 @@
         if len(slot_names) == 1:
             if not getattr(pto, slot_names[0]):
                 setattr(pto, slot_names[0], slot_func_helper)
+        elif (w_type.getname(space) in ('list', 'tuple') and 
+              slot_names[0] == 'c_tp_as_number'):
+            # XXX hack - hwo can we generalize this? The problem is method
+            # names like __mul__ map to more than one slot, and we have no
+            # convenient way to indicate which slots CPython have filled
+            # 
+            # We need at least this special case since Numpy checks that
+            # (list, tuple) do __not__ fill tp_as_number
+            pass
         else:
             assert len(slot_names) == 2
             struct = getattr(pto, slot_names[0])


More information about the pypy-commit mailing list