Author: Matti Picus <[email protected]>
Branch: py3.6
Changeset: r96315:12d0c4f992fd
Date: 2019-03-14 17:17 +0200
http://bitbucket.org/pypy/pypy/changeset/12d0c4f992fd/
Log: merge issue 2968 into py3.6
diff --git a/pypy/module/cpyext/api.py b/pypy/module/cpyext/api.py
--- a/pypy/module/cpyext/api.py
+++ b/pypy/module/cpyext/api.py
@@ -1191,7 +1191,9 @@
state.C.get_pyos_inputhook = rffi.llexternal(
'_PyPy_get_PyOS_InputHook', [], FUNCPTR,
compilation_info=eci, _nowrapper=True)
-
+ state.C.tuple_new = rffi.llexternal(
+ 'tuple_new', [PyTypeObjectPtr, PyObject, PyObject], PyObject,
+ compilation_info=eci, _nowrapper=True)
def init_function(func):
INIT_FUNCTIONS.append(func)
diff --git a/pypy/module/cpyext/include/tupleobject.h
b/pypy/module/cpyext/include/tupleobject.h
--- a/pypy/module/cpyext/include/tupleobject.h
+++ b/pypy/module/cpyext/include/tupleobject.h
@@ -18,6 +18,7 @@
PyAPI_FUNC(PyObject *) PyTuple_New(Py_ssize_t size);
PyAPI_FUNC(void) _PyPy_tuple_dealloc(PyObject *);
+PyAPI_FUNC(PyObject *) tuple_new(PyTypeObject *type, PyObject *args, PyObject
*kwds);
/* defined in varargswrapper.c */
PyAPI_FUNC(PyObject *) PyTuple_Pack(Py_ssize_t, ...);
diff --git a/pypy/module/cpyext/src/tupleobject.c
b/pypy/module/cpyext/src/tupleobject.c
--- a/pypy/module/cpyext/src/tupleobject.c
+++ b/pypy/module/cpyext/src/tupleobject.c
@@ -89,3 +89,48 @@
done:
Py_TRASHCAN_SAFE_END(op)
}
+
+static PyObject *
+tuple_subtype_new(PyTypeObject *type, PyObject *args, PyObject *kwds);
+
+PyObject *
+tuple_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+ PyObject *arg = NULL;
+ static char *kwlist[] = {"sequence", 0};
+
+ if (type != &PyTuple_Type)
+ return tuple_subtype_new(type, args, kwds);
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O:tuple", kwlist, &arg))
+ return NULL;
+
+ if (arg == NULL)
+ return PyTuple_New(0);
+ else
+ return PySequence_Tuple(arg);
+}
+
+static PyObject *
+tuple_subtype_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+ PyObject *tmp, *newobj, *item;
+ Py_ssize_t i, n;
+
+ assert(PyType_IsSubtype(type, &PyTuple_Type));
+ tmp = tuple_new(&PyTuple_Type, args, kwds);
+ if (tmp == NULL)
+ return NULL;
+ assert(PyTuple_Check(tmp));
+ newobj = type->tp_alloc(type, n = PyTuple_GET_SIZE(tmp));
+ if (newobj == NULL)
+ return NULL;
+ for (i = 0; i < n; i++) {
+ item = PyTuple_GET_ITEM(tmp, i);
+ Py_INCREF(item);
+ PyTuple_SET_ITEM(newobj, i, item);
+ }
+ Py_DECREF(tmp);
+ return newobj;
+}
+
+
diff --git a/pypy/module/cpyext/test/test_tupleobject.py
b/pypy/module/cpyext/test/test_tupleobject.py
--- a/pypy/module/cpyext/test/test_tupleobject.py
+++ b/pypy/module/cpyext/test/test_tupleobject.py
@@ -226,3 +226,44 @@
raises(SystemError, module.set_after_use, s)
else:
module.set_after_use(s)
+
+ def test_mp_length(self):
+ # issue 2968: creating a subclass of tuple in C led to recursion
+ # since the default tp_new needs to build a w_obj, but that needs
+ # to call space.len_w, which needs to call tp_new.
+ module = self.import_module('THPSize')
+ module = self.import_extension('foo', [
+ ("get_size", "METH_NOARGS",
+ """
+ return (PyObject*)&THPSizeType;
+ """),
+ ], prologue='''
+ #include "Python.h"
+
+ struct THPSize {
+ PyTupleObject tuple;
+ } THPSize;
+
+ static PyMappingMethods THPSize_as_mapping = {
+ 0, //PyTuple_Type.tp_as_mapping->mp_length,
+ 0,
+ 0
+ };
+
+ PyTypeObject THPSizeType = {
+ PyVarObject_HEAD_INIT(0, 0)
+ "torch.Size", /* tp_name */
+ sizeof(THPSize), /* tp_basicsize */
+ };
+ ''' , more_init = '''
+ THPSize_as_mapping.mp_length =
PyTuple_Type.tp_as_mapping->mp_length;
+ THPSizeType.tp_base = &PyTuple_Type;
+ THPSizeType.tp_flags = Py_TPFLAGS_DEFAULT;
+ THPSizeType.tp_as_mapping = &THPSize_as_mapping;
+ THPSizeType.tp_new = PyTuple_Type.tp_new;
+ if (PyType_Ready(&THPSizeType) < 0) INITERROR;
+ ''')
+ SZ = module.get_size()
+ s = SZ((1, 2, 3))
+ assert len(s) == 3
+
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
@@ -686,6 +686,11 @@
update_all_slots(space, w_type, pto)
else:
update_all_slots_builtin(space, w_type, pto)
+
+ # XXX generlize this pattern for various slot functions implemented in C
+ if space.is_w(w_type, space.w_tuple):
+ pto.c_tp_new = state.C.tuple_new
+
if not pto.c_tp_new:
base_object_pyo = make_ref(space, space.w_object)
base_object_pto = rffi.cast(PyTypeObjectPtr, base_object_pyo)
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit