Skip to content

Commit 4e46463

Browse files
Add PyTuple_Make[Single,Pair]
1 parent f262297 commit 4e46463

File tree

6 files changed

+121
-0
lines changed

6 files changed

+121
-0
lines changed

Doc/c-api/tuple.rst

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,34 @@ Tuple Objects
5858
``PyTuple_Pack(2, a, b)`` is equivalent to ``Py_BuildValue("(OO)", a, b)``.
5959
6060
61+
.. c:function:: PyObject* PyTuple_MakeSingle(PyObject *one)
62+
63+
Return a new tuple object of size 1,
64+
or ``NULL`` with an exception set on failure. The tuple value
65+
is initialized with the new reference to the *one* object.
66+
``PyTuple_MakeSingle(a)`` is equivalent to ``PyTuple_Pack(1, a)``.
67+
68+
.. warning::
69+
70+
This function expects non ``NULL`` object *one*.
71+
Checking is performed as an assertion if Python is built in
72+
:ref:`debug mode <debug-build>` or :option:`with assertions <--with-assertions>`.
73+
74+
75+
.. c:function:: PyObject* PyTuple_MakePair(PyObject *one, PyObject *two)
76+
77+
Return a new tuple object of size 2,
78+
or ``NULL`` with an exception set on failure. The tuple values
79+
are initialized with the new references to the *one* and *two* objects.
80+
``PyTuple_MakePair(a, b)`` is equivalent to ``PyTuple_Pack(2, a, b)``.
81+
82+
.. warning::
83+
84+
This function expects non ``NULL`` objects *one* and *two*.
85+
Checking is performed as an assertion if Python is built in
86+
:ref:`debug mode <debug-build>` or :option:`with assertions <--with-assertions>`.
87+
88+
6189
.. c:function:: Py_ssize_t PyTuple_Size(PyObject *p)
6290
6391
Take a pointer to a tuple object, and return the size of that tuple.

Doc/data/refcounts.dat

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2359,6 +2359,13 @@ PyTuple_GetSlice:PyObject*:p:0:
23592359
PyTuple_GetSlice:Py_ssize_t:low::
23602360
PyTuple_GetSlice:Py_ssize_t:high::
23612361

2362+
PyTuple_MakePair:PyObject*::+1
2363+
PyTuple_MakePair:PyObject*:one:+1
2364+
PyTuple_MakePair:PyObject*:two:+1
2365+
2366+
PyTuple_MakeSingle:PyObject*::+1
2367+
PyTuple_MakeSingle:PyObject*:one:+1
2368+
23622369
PyTuple_New:PyObject*::+1:
23632370
PyTuple_New:Py_ssize_t:len::
23642371

Include/tupleobject.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ PyAPI_FUNC(int) PyTuple_SetItem(PyObject *, Py_ssize_t, PyObject *);
3434
PyAPI_FUNC(PyObject *) PyTuple_GetSlice(PyObject *, Py_ssize_t, Py_ssize_t);
3535
PyAPI_FUNC(PyObject *) PyTuple_Pack(Py_ssize_t, ...);
3636

37+
PyAPI_FUNC(PyObject *) PyTuple_MakeSingle(PyObject *one);
38+
PyAPI_FUNC(PyObject *) PyTuple_MakePair(PyObject *one, PyObject *two);
39+
3740
#ifndef Py_LIMITED_API
3841
# define Py_CPYTHON_TUPLEOBJECT_H
3942
# include "cpython/tupleobject.h"

Lib/test/test_capi/test_tuple.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,35 @@ def test_tuple_pack(self):
9999
# CRASHES pack(1, NULL)
100100
# CRASHES pack(2, [1])
101101

102+
def test_tuple_make_single(self):
103+
# Test PyTuple_MakeSingle()
104+
make_single = _testcapi.tuple_make_single
105+
106+
self.assertEqual(make_single(1), (1,))
107+
self.assertEqual(make_single(None), (None,))
108+
self.assertEqual(make_single(True), (True,))
109+
110+
temp = object()
111+
self.assertEqual(make_single(temp), (temp,))
112+
113+
self.assertRaises(TypeError, make_single, 1, 2)
114+
self.assertRaises(TypeError, make_single)
115+
116+
def test_tuple_make_pair(self):
117+
# Test PyTuple_MakePair()
118+
make_pair = _testcapi.tuple_make_pair
119+
120+
self.assertEqual(make_pair(1, 2), (1, 2))
121+
self.assertEqual(make_pair(None, None), (None, None))
122+
self.assertEqual(make_pair(True, False), (True, False))
123+
124+
temp = object()
125+
self.assertEqual(make_pair(temp, temp), (temp, temp))
126+
127+
self.assertRaises(TypeError, make_pair, 1, 2, 3)
128+
self.assertRaises(TypeError, make_pair, 1)
129+
self.assertRaises(TypeError, make_pair)
130+
102131
def test_tuple_size(self):
103132
# Test PyTuple_Size()
104133
size = _testlimitedcapi.tuple_size

Modules/_testcapi/tuple.c

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,29 @@ tuple_fromarray(PyObject* Py_UNUSED(module), PyObject *args)
130130
return PyTuple_FromArray(items, size);
131131
}
132132

133+
static PyObject *
134+
tuple_make_single(PyObject *Py_UNUSED(module), PyObject *args)
135+
{
136+
PyObject *one;
137+
if (!PyArg_ParseTuple(args, "O", &one)) {
138+
return NULL;
139+
}
140+
141+
return PyTuple_MakeSingle(one);
142+
}
143+
144+
static PyObject *
145+
tuple_make_pair(PyObject *Py_UNUSED(module), PyObject *args)
146+
{
147+
PyObject *one;
148+
PyObject *two;
149+
if (!PyArg_ParseTuple(args, "OO", &one, &two)) {
150+
return NULL;
151+
}
152+
153+
return PyTuple_MakePair(one, two);
154+
}
155+
133156

134157
static PyMethodDef test_methods[] = {
135158
{"tuple_get_size", tuple_get_size, METH_O},
@@ -138,6 +161,8 @@ static PyMethodDef test_methods[] = {
138161
{"_tuple_resize", _tuple_resize, METH_VARARGS},
139162
{"_check_tuple_item_is_NULL", _check_tuple_item_is_NULL, METH_VARARGS},
140163
{"tuple_fromarray", tuple_fromarray, METH_VARARGS},
164+
{"tuple_make_single", tuple_make_single, METH_VARARGS},
165+
{"tuple_make_pair", tuple_make_pair, METH_VARARGS},
141166
{NULL},
142167
};
143168

Objects/tupleobject.c

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,35 @@ PyTuple_Pack(Py_ssize_t n, ...)
184184
return (PyObject *)result;
185185
}
186186

187+
PyObject *
188+
PyTuple_MakeSingle(PyObject *one)
189+
{
190+
assert (one != NULL);
191+
192+
PyTupleObject *op = tuple_alloc(1);
193+
if (op == NULL) {
194+
return NULL;
195+
}
196+
op->ob_item[0] = Py_NewRef(one);
197+
_PyObject_GC_TRACK(op);
198+
return (PyObject *) op;
199+
}
200+
201+
PyObject *
202+
PyTuple_MakePair(PyObject *one, PyObject *two)
203+
{
204+
assert (one != NULL);
205+
assert (two != NULL);
206+
207+
PyTupleObject *op = tuple_alloc(2);
208+
if (op == NULL) {
209+
return NULL;
210+
}
211+
op->ob_item[0] = Py_NewRef(one);
212+
op->ob_item[1] = Py_NewRef(two);
213+
_PyObject_GC_TRACK(op);
214+
return (PyObject *) op;
215+
}
187216

188217
/* Methods */
189218

0 commit comments

Comments
 (0)