Implement _PyTuple_FromPair() and _PyTuple_FromPairSteal().
Co-authored-by: Pieter Eendebak <pieter.eendebak@gmail.com>
Co-authored-by: Victor Stinner <vstinner@python.org>
Co-authored-by: Bartosz Sławecki <bartosz@ilikepython.com>
Co-authored-by: Kumar Aditya <kumaraditya@python.org>
PyAPI_FUNC(PyObject *)_PyTuple_FromArraySteal(PyObject *const *, Py_ssize_t);
PyAPI_FUNC(PyObject *) _PyTuple_BinarySlice(PyObject *, PyObject *, PyObject *);
+PyAPI_FUNC(PyObject *) _PyTuple_FromPair(PyObject *, PyObject *);
+PyAPI_FUNC(PyObject *) _PyTuple_FromPairSteal(PyObject *, PyObject *);
+
typedef struct {
PyObject_HEAD
Py_ssize_t it_index;
import unittest
import gc
+from sys import getrefcount
from test.support import import_helper
_testcapi = import_helper.import_module('_testcapi')
_testlimitedcapi = import_helper.import_module('_testlimitedcapi')
+_testinternalcapi = import_helper.import_module('_testinternalcapi')
NULL = None
PY_SSIZE_T_MIN = _testcapi.PY_SSIZE_T_MIN
# CRASHES pack(1, NULL)
# CRASHES pack(2, [1])
+ def check_tuple_from_pair(self, from_pair):
+ self.assertEqual(type(from_pair(1, 2)), tuple)
+ self.assertEqual(from_pair(1, 145325), (1, 145325))
+ self.assertEqual(from_pair(None, None), (None, None))
+ self.assertEqual(from_pair(True, False), (True, False))
+
+ # user class supports gc
+ class Temp:
+ pass
+ temp = Temp()
+ temp_rc = getrefcount(temp)
+ self.assertEqual(from_pair(temp, temp), (temp, temp))
+ self.assertEqual(getrefcount(temp), temp_rc)
+
+ self._not_tracked(from_pair(1, 2))
+ self._not_tracked(from_pair(None, None))
+ self._not_tracked(from_pair(True, False))
+ self._tracked(from_pair(temp, (1, 2)))
+ self._tracked(from_pair(temp, 1))
+ self._tracked(from_pair([], {}))
+
+ self.assertRaises(TypeError, from_pair, 1, 2, 3)
+ self.assertRaises(TypeError, from_pair, 1)
+ self.assertRaises(TypeError, from_pair)
+
+ def test_tuple_from_pair(self):
+ # Test _PyTuple_FromPair()
+ from_pair = _testinternalcapi.tuple_from_pair
+ self.check_tuple_from_pair(from_pair)
+
+ def test_tuple_from_pair_steal(self):
+ # Test _PyTuple_FromPairSteal()
+ from_pair = _testinternalcapi.tuple_from_pair_steal
+ self.check_tuple_from_pair(from_pair)
+
def test_tuple_size(self):
# Test PyTuple_Size()
size = _testlimitedcapi.tuple_size
@MODULE_XXSUBTYPE_TRUE@xxsubtype xxsubtype.c
@MODULE__XXTESTFUZZ_TRUE@_xxtestfuzz _xxtestfuzz/_xxtestfuzz.c _xxtestfuzz/fuzzer.c
@MODULE__TESTBUFFER_TRUE@_testbuffer _testbuffer.c
-@MODULE__TESTINTERNALCAPI_TRUE@_testinternalcapi _testinternalcapi.c _testinternalcapi/test_lock.c _testinternalcapi/pytime.c _testinternalcapi/set.c _testinternalcapi/test_critical_sections.c _testinternalcapi/complex.c _testinternalcapi/interpreter.c
+@MODULE__TESTINTERNALCAPI_TRUE@_testinternalcapi _testinternalcapi.c _testinternalcapi/test_lock.c _testinternalcapi/pytime.c _testinternalcapi/set.c _testinternalcapi/test_critical_sections.c _testinternalcapi/complex.c _testinternalcapi/interpreter.c _testinternalcapi/tuple.c
@MODULE__TESTCAPI_TRUE@_testcapi _testcapimodule.c _testcapi/vectorcall.c _testcapi/heaptype.c _testcapi/abstract.c _testcapi/unicode.c _testcapi/dict.c _testcapi/set.c _testcapi/list.c _testcapi/tuple.c _testcapi/getargs.c _testcapi/datetime.c _testcapi/docstring.c _testcapi/mem.c _testcapi/watchers.c _testcapi/long.c _testcapi/float.c _testcapi/complex.c _testcapi/numbers.c _testcapi/structmember.c _testcapi/exceptions.c _testcapi/code.c _testcapi/buffer.c _testcapi/pyatomic.c _testcapi/run.c _testcapi/file.c _testcapi/codec.c _testcapi/immortal.c _testcapi/gc.c _testcapi/hash.c _testcapi/time.c _testcapi/bytes.c _testcapi/object.c _testcapi/modsupport.c _testcapi/monitoring.c _testcapi/config.c _testcapi/import.c _testcapi/frame.c _testcapi/type.c _testcapi/function.c _testcapi/module.c
@MODULE__TESTLIMITEDCAPI_TRUE@_testlimitedcapi _testlimitedcapi.c _testlimitedcapi/abstract.c _testlimitedcapi/bytearray.c _testlimitedcapi/bytes.c _testlimitedcapi/codec.c _testlimitedcapi/complex.c _testlimitedcapi/dict.c _testlimitedcapi/eval.c _testlimitedcapi/float.c _testlimitedcapi/heaptype_relative.c _testlimitedcapi/import.c _testlimitedcapi/list.c _testlimitedcapi/long.c _testlimitedcapi/object.c _testlimitedcapi/pyos.c _testlimitedcapi/set.c _testlimitedcapi/sys.c _testlimitedcapi/threadstate.c _testlimitedcapi/tuple.c _testlimitedcapi/unicode.c _testlimitedcapi/vectorcall_limited.c _testlimitedcapi/version.c _testlimitedcapi/file.c
@MODULE__TESTCLINIC_TRUE@_testclinic _testclinic.c
if (_PyTestInternalCapi_Init_CriticalSection(module) < 0) {
return 1;
}
+ if (_PyTestInternalCapi_Init_Tuple(module) < 0) {
+ return 1;
+ }
Py_ssize_t sizeof_gc_head = 0;
#ifndef Py_GIL_DISABLED
int _PyTestInternalCapi_Init_Set(PyObject *module);
int _PyTestInternalCapi_Init_Complex(PyObject *module);
int _PyTestInternalCapi_Init_CriticalSection(PyObject *module);
+int _PyTestInternalCapi_Init_Tuple(PyObject *module);
#endif // Py_TESTINTERNALCAPI_PARTS_H
--- /dev/null
+#include "parts.h"
+
+#include "pycore_tuple.h"
+
+
+static PyObject *
+tuple_from_pair(PyObject *Py_UNUSED(module), PyObject *args)
+{
+ PyObject *first, *second;
+ if (!PyArg_ParseTuple(args, "OO", &first, &second)) {
+ return NULL;
+ }
+
+ return _PyTuple_FromPair(first, second);
+}
+
+static PyObject *
+tuple_from_pair_steal(PyObject *Py_UNUSED(module), PyObject *args)
+{
+ PyObject *first, *second;
+ if (!PyArg_ParseTuple(args, "OO", &first, &second)) {
+ return NULL;
+ }
+
+ return _PyTuple_FromPairSteal(Py_NewRef(first), Py_NewRef(second));
+}
+
+
+static PyMethodDef test_methods[] = {
+ {"tuple_from_pair", tuple_from_pair, METH_VARARGS},
+ {"tuple_from_pair_steal", tuple_from_pair_steal, METH_VARARGS},
+ {NULL},
+};
+
+int
+_PyTestInternalCapi_Init_Tuple(PyObject *m)
+{
+ return PyModule_AddFunctions(m, test_methods);
+}
return (PyObject *)result;
}
+PyObject *
+_PyTuple_FromPair(PyObject *first, PyObject *second)
+{
+ assert(first != NULL);
+ assert(second != NULL);
+
+ return _PyTuple_FromPairSteal(Py_NewRef(first), Py_NewRef(second));
+}
+
+PyObject *
+_PyTuple_FromPairSteal(PyObject *first, PyObject *second)
+{
+ assert(first != NULL);
+ assert(second != NULL);
+
+ PyTupleObject *op = tuple_alloc(2);
+ if (op == NULL) {
+ Py_DECREF(first);
+ Py_DECREF(second);
+ return NULL;
+ }
+ PyObject **items = op->ob_item;
+ items[0] = first;
+ items[1] = second;
+ if (maybe_tracked(first) || maybe_tracked(second)) {
+ _PyObject_GC_TRACK(op);
+ }
+ return (PyObject *)op;
+}
/* Methods */
<ClCompile Include="..\Modules\_testinternalcapi\set.c" />
<ClCompile Include="..\Modules\_testinternalcapi\complex.c" />
<ClCompile Include="..\Modules\_testinternalcapi\interpreter.c" />
+ <ClCompile Include="..\Modules\_testinternalcapi\tuple.c" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="..\PC\python_nt.rc" />
<ClCompile Include="..\Modules\_testinternalcapi\complex.c">
<Filter>Source Files</Filter>
</ClCompile>
+ <ClCompile Include="..\Modules\_testinternalcapi\tuple.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="..\PC\python_nt.rc">