X Tutup
Skip to content

Commit 478a315

Browse files
sergey-miryanoveendebakptvstinnerjohnslavikkumaraditya303
authored
GH-145247: Implement _PyTuple_FromPair() (#145325)
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>
1 parent 3f7141d commit 478a315

File tree

9 files changed

+117
-1
lines changed

9 files changed

+117
-1
lines changed

Include/internal/pycore_tuple.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ PyAPI_FUNC(PyObject *)_PyTuple_FromStackRefStealOnSuccess(const union _PyStackRe
2727
PyAPI_FUNC(PyObject *)_PyTuple_FromArraySteal(PyObject *const *, Py_ssize_t);
2828
PyAPI_FUNC(PyObject *) _PyTuple_BinarySlice(PyObject *, PyObject *, PyObject *);
2929

30+
PyAPI_FUNC(PyObject *) _PyTuple_FromPair(PyObject *, PyObject *);
31+
PyAPI_FUNC(PyObject *) _PyTuple_FromPairSteal(PyObject *, PyObject *);
32+
3033
typedef struct {
3134
PyObject_HEAD
3235
Py_ssize_t it_index;

Lib/test/test_capi/test_tuple.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
import unittest
22
import gc
3+
from sys import getrefcount
34
from test.support import import_helper
45

56
_testcapi = import_helper.import_module('_testcapi')
67
_testlimitedcapi = import_helper.import_module('_testlimitedcapi')
8+
_testinternalcapi = import_helper.import_module('_testinternalcapi')
79

810
NULL = None
911
PY_SSIZE_T_MIN = _testcapi.PY_SSIZE_T_MIN
@@ -118,6 +120,41 @@ def test_tuple_pack(self):
118120
# CRASHES pack(1, NULL)
119121
# CRASHES pack(2, [1])
120122

123+
def check_tuple_from_pair(self, from_pair):
124+
self.assertEqual(type(from_pair(1, 2)), tuple)
125+
self.assertEqual(from_pair(1, 145325), (1, 145325))
126+
self.assertEqual(from_pair(None, None), (None, None))
127+
self.assertEqual(from_pair(True, False), (True, False))
128+
129+
# user class supports gc
130+
class Temp:
131+
pass
132+
temp = Temp()
133+
temp_rc = getrefcount(temp)
134+
self.assertEqual(from_pair(temp, temp), (temp, temp))
135+
self.assertEqual(getrefcount(temp), temp_rc)
136+
137+
self._not_tracked(from_pair(1, 2))
138+
self._not_tracked(from_pair(None, None))
139+
self._not_tracked(from_pair(True, False))
140+
self._tracked(from_pair(temp, (1, 2)))
141+
self._tracked(from_pair(temp, 1))
142+
self._tracked(from_pair([], {}))
143+
144+
self.assertRaises(TypeError, from_pair, 1, 2, 3)
145+
self.assertRaises(TypeError, from_pair, 1)
146+
self.assertRaises(TypeError, from_pair)
147+
148+
def test_tuple_from_pair(self):
149+
# Test _PyTuple_FromPair()
150+
from_pair = _testinternalcapi.tuple_from_pair
151+
self.check_tuple_from_pair(from_pair)
152+
153+
def test_tuple_from_pair_steal(self):
154+
# Test _PyTuple_FromPairSteal()
155+
from_pair = _testinternalcapi.tuple_from_pair_steal
156+
self.check_tuple_from_pair(from_pair)
157+
121158
def test_tuple_size(self):
122159
# Test PyTuple_Size()
123160
size = _testlimitedcapi.tuple_size

Modules/Setup.stdlib.in

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@
174174
@MODULE_XXSUBTYPE_TRUE@xxsubtype xxsubtype.c
175175
@MODULE__XXTESTFUZZ_TRUE@_xxtestfuzz _xxtestfuzz/_xxtestfuzz.c _xxtestfuzz/fuzzer.c
176176
@MODULE__TESTBUFFER_TRUE@_testbuffer _testbuffer.c
177-
@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
177+
@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
178178
@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
179179
@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
180180
@MODULE__TESTCLINIC_TRUE@_testclinic _testclinic.c

Modules/_testinternalcapi.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2987,6 +2987,9 @@ module_exec(PyObject *module)
29872987
if (_PyTestInternalCapi_Init_CriticalSection(module) < 0) {
29882988
return 1;
29892989
}
2990+
if (_PyTestInternalCapi_Init_Tuple(module) < 0) {
2991+
return 1;
2992+
}
29902993

29912994
Py_ssize_t sizeof_gc_head = 0;
29922995
#ifndef Py_GIL_DISABLED

Modules/_testinternalcapi/parts.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,6 @@ int _PyTestInternalCapi_Init_PyTime(PyObject *module);
1515
int _PyTestInternalCapi_Init_Set(PyObject *module);
1616
int _PyTestInternalCapi_Init_Complex(PyObject *module);
1717
int _PyTestInternalCapi_Init_CriticalSection(PyObject *module);
18+
int _PyTestInternalCapi_Init_Tuple(PyObject *module);
1819

1920
#endif // Py_TESTINTERNALCAPI_PARTS_H

Modules/_testinternalcapi/tuple.c

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
#include "parts.h"
2+
3+
#include "pycore_tuple.h"
4+
5+
6+
static PyObject *
7+
tuple_from_pair(PyObject *Py_UNUSED(module), PyObject *args)
8+
{
9+
PyObject *first, *second;
10+
if (!PyArg_ParseTuple(args, "OO", &first, &second)) {
11+
return NULL;
12+
}
13+
14+
return _PyTuple_FromPair(first, second);
15+
}
16+
17+
static PyObject *
18+
tuple_from_pair_steal(PyObject *Py_UNUSED(module), PyObject *args)
19+
{
20+
PyObject *first, *second;
21+
if (!PyArg_ParseTuple(args, "OO", &first, &second)) {
22+
return NULL;
23+
}
24+
25+
return _PyTuple_FromPairSteal(Py_NewRef(first), Py_NewRef(second));
26+
}
27+
28+
29+
static PyMethodDef test_methods[] = {
30+
{"tuple_from_pair", tuple_from_pair, METH_VARARGS},
31+
{"tuple_from_pair_steal", tuple_from_pair_steal, METH_VARARGS},
32+
{NULL},
33+
};
34+
35+
int
36+
_PyTestInternalCapi_Init_Tuple(PyObject *m)
37+
{
38+
return PyModule_AddFunctions(m, test_methods);
39+
}

Objects/tupleobject.c

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,35 @@ PyTuple_Pack(Py_ssize_t n, ...)
202202
return (PyObject *)result;
203203
}
204204

205+
PyObject *
206+
_PyTuple_FromPair(PyObject *first, PyObject *second)
207+
{
208+
assert(first != NULL);
209+
assert(second != NULL);
210+
211+
return _PyTuple_FromPairSteal(Py_NewRef(first), Py_NewRef(second));
212+
}
213+
214+
PyObject *
215+
_PyTuple_FromPairSteal(PyObject *first, PyObject *second)
216+
{
217+
assert(first != NULL);
218+
assert(second != NULL);
219+
220+
PyTupleObject *op = tuple_alloc(2);
221+
if (op == NULL) {
222+
Py_DECREF(first);
223+
Py_DECREF(second);
224+
return NULL;
225+
}
226+
PyObject **items = op->ob_item;
227+
items[0] = first;
228+
items[1] = second;
229+
if (maybe_tracked(first) || maybe_tracked(second)) {
230+
_PyObject_GC_TRACK(op);
231+
}
232+
return (PyObject *)op;
233+
}
205234

206235
/* Methods */
207236

PCbuild/_testinternalcapi.vcxproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@
100100
<ClCompile Include="..\Modules\_testinternalcapi\set.c" />
101101
<ClCompile Include="..\Modules\_testinternalcapi\complex.c" />
102102
<ClCompile Include="..\Modules\_testinternalcapi\interpreter.c" />
103+
<ClCompile Include="..\Modules\_testinternalcapi\tuple.c" />
103104
</ItemGroup>
104105
<ItemGroup>
105106
<ResourceCompile Include="..\PC\python_nt.rc" />

PCbuild/_testinternalcapi.vcxproj.filters

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@
2727
<ClCompile Include="..\Modules\_testinternalcapi\complex.c">
2828
<Filter>Source Files</Filter>
2929
</ClCompile>
30+
<ClCompile Include="..\Modules\_testinternalcapi\tuple.c">
31+
<Filter>Source Files</Filter>
32+
</ClCompile>
3033
</ItemGroup>
3134
<ItemGroup>
3235
<ResourceCompile Include="..\PC\python_nt.rc">

0 commit comments

Comments
 (0)
X Tutup