mirror of https://github.com/python/cpython
gh-111495: Add tests for PyTuple C API (#118757)
Co-authored-by: kalyanr <kalyan.ben10@live.com> Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Victor Stinner <vstinner@python.org>
This commit is contained in:
parent
6401cdf908
commit
dbc1752d41
|
@ -77,3 +77,7 @@ class CAPITest(unittest.TestCase):
|
|||
# Py_HashPointer((void*)(uintptr_t)-1) doesn't return -1 but -2
|
||||
VOID_P_MAX = -1 & (2 ** (8 * SIZEOF_VOID_P) - 1)
|
||||
self.assertEqual(hash_pointer(VOID_P_MAX), -2)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
|
|
@ -345,3 +345,7 @@ class CAPITest(unittest.TestCase):
|
|||
|
||||
# CRASHES list_extend(NULL, [])
|
||||
# CRASHES list_extend([], NULL)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
|
|
@ -265,3 +265,7 @@ class TestInternalCAPI(BaseSetTests, unittest.TestCase):
|
|||
with self.assertRaises(SystemError):
|
||||
set_next(object(), 0)
|
||||
# CRASHES: set_next(NULL, 0)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
|
|
@ -72,3 +72,7 @@ class CAPITest(unittest.TestCase):
|
|||
# Test PyTime_Time() and PyTime_TimeRaw()
|
||||
self.check_clock(_testcapi.PyTime_Time, time.time)
|
||||
self.check_clock(_testcapi.PyTime_TimeRaw, time.time)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
|
|
@ -0,0 +1,261 @@
|
|||
import unittest
|
||||
import sys
|
||||
from collections import namedtuple
|
||||
from test.support import import_helper
|
||||
|
||||
_testcapi = import_helper.import_module('_testcapi')
|
||||
_testlimitedcapi = import_helper.import_module('_testlimitedcapi')
|
||||
|
||||
NULL = None
|
||||
PY_SSIZE_T_MIN = _testcapi.PY_SSIZE_T_MIN
|
||||
PY_SSIZE_T_MAX = _testcapi.PY_SSIZE_T_MAX
|
||||
|
||||
class TupleSubclass(tuple):
|
||||
pass
|
||||
|
||||
|
||||
class CAPITest(unittest.TestCase):
|
||||
def test_check(self):
|
||||
# Test PyTuple_Check()
|
||||
check = _testlimitedcapi.tuple_check
|
||||
|
||||
self.assertTrue(check((1, 2)))
|
||||
self.assertTrue(check(()))
|
||||
self.assertTrue(check(TupleSubclass((1, 2))))
|
||||
self.assertFalse(check({1: 2}))
|
||||
self.assertFalse(check([1, 2]))
|
||||
self.assertFalse(check(42))
|
||||
self.assertFalse(check(object()))
|
||||
|
||||
# CRASHES check(NULL)
|
||||
|
||||
def test_tuple_checkexact(self):
|
||||
# Test PyTuple_CheckExact()
|
||||
check = _testlimitedcapi.tuple_checkexact
|
||||
|
||||
self.assertTrue(check((1, 2)))
|
||||
self.assertTrue(check(()))
|
||||
self.assertFalse(check(TupleSubclass((1, 2))))
|
||||
self.assertFalse(check({1: 2}))
|
||||
self.assertFalse(check([1, 2]))
|
||||
self.assertFalse(check(42))
|
||||
self.assertFalse(check(object()))
|
||||
|
||||
# CRASHES check(NULL)
|
||||
|
||||
def test_tuple_new(self):
|
||||
# Test PyTuple_New()
|
||||
tuple_new = _testlimitedcapi.tuple_new
|
||||
size = _testlimitedcapi.tuple_size
|
||||
checknull = _testcapi._check_tuple_item_is_NULL
|
||||
|
||||
tup1 = tuple_new(0)
|
||||
self.assertEqual(tup1, ())
|
||||
self.assertEqual(size(tup1), 0)
|
||||
self.assertIs(type(tup1), tuple)
|
||||
tup2 = tuple_new(1)
|
||||
self.assertIs(type(tup2), tuple)
|
||||
self.assertEqual(size(tup2), 1)
|
||||
self.assertIsNot(tup2, tup1)
|
||||
self.assertTrue(checknull(tup2, 0))
|
||||
|
||||
self.assertRaises(SystemError, tuple_new, -1)
|
||||
self.assertRaises(SystemError, tuple_new, PY_SSIZE_T_MIN)
|
||||
self.assertRaises(MemoryError, tuple_new, PY_SSIZE_T_MAX)
|
||||
|
||||
def test_tuple_pack(self):
|
||||
# Test PyTuple_Pack()
|
||||
pack = _testlimitedcapi.tuple_pack
|
||||
|
||||
self.assertEqual(pack(0), ())
|
||||
self.assertEqual(pack(1, [1]), ([1],))
|
||||
self.assertEqual(pack(2, [1], [2]), ([1], [2]))
|
||||
|
||||
self.assertRaises(SystemError, pack, PY_SSIZE_T_MIN)
|
||||
self.assertRaises(SystemError, pack, -1)
|
||||
self.assertRaises(MemoryError, pack, PY_SSIZE_T_MAX)
|
||||
|
||||
# CRASHES pack(1, NULL)
|
||||
# CRASHES pack(2, [1])
|
||||
|
||||
def test_tuple_size(self):
|
||||
# Test PyTuple_Size()
|
||||
size = _testlimitedcapi.tuple_size
|
||||
|
||||
self.assertEqual(size(()), 0)
|
||||
self.assertEqual(size((1, 2)), 2)
|
||||
self.assertEqual(size(TupleSubclass((1, 2))), 2)
|
||||
|
||||
self.assertRaises(SystemError, size, [])
|
||||
self.assertRaises(SystemError, size, 42)
|
||||
self.assertRaises(SystemError, size, object())
|
||||
|
||||
# CRASHES size(NULL)
|
||||
|
||||
def test_tuple_get_size(self):
|
||||
# Test PyTuple_GET_SIZE()
|
||||
size = _testcapi.tuple_get_size
|
||||
|
||||
self.assertEqual(size(()), 0)
|
||||
self.assertEqual(size((1, 2)), 2)
|
||||
self.assertEqual(size(TupleSubclass((1, 2))), 2)
|
||||
|
||||
def test_tuple_getitem(self):
|
||||
# Test PyTuple_GetItem()
|
||||
getitem = _testlimitedcapi.tuple_getitem
|
||||
|
||||
tup = ([1], [2], [3])
|
||||
self.assertEqual(getitem(tup, 0), [1])
|
||||
self.assertEqual(getitem(tup, 2), [3])
|
||||
|
||||
tup2 = TupleSubclass(([1], [2], [3]))
|
||||
self.assertEqual(getitem(tup2, 0), [1])
|
||||
self.assertEqual(getitem(tup2, 2), [3])
|
||||
|
||||
self.assertRaises(IndexError, getitem, tup, PY_SSIZE_T_MIN)
|
||||
self.assertRaises(IndexError, getitem, tup, -1)
|
||||
self.assertRaises(IndexError, getitem, tup, len(tup))
|
||||
self.assertRaises(IndexError, getitem, tup, PY_SSIZE_T_MAX)
|
||||
self.assertRaises(SystemError, getitem, [1, 2, 3], 1)
|
||||
self.assertRaises(SystemError, getitem, 42, 1)
|
||||
|
||||
# CRASHES getitem(NULL, 0)
|
||||
|
||||
def test_tuple_get_item(self):
|
||||
# Test PyTuple_GET_ITEM()
|
||||
get_item = _testcapi.tuple_get_item
|
||||
|
||||
tup = ([1], [2], [3])
|
||||
self.assertEqual(get_item(tup, 0), [1])
|
||||
self.assertEqual(get_item(tup, 2), [3])
|
||||
|
||||
tup2 = TupleSubclass(([1], [2], [3]))
|
||||
self.assertEqual(get_item(tup2, 0), [1])
|
||||
self.assertEqual(get_item(tup2, 2), [3])
|
||||
|
||||
# CRASHES get_item(NULL, 0)
|
||||
|
||||
def test_tuple_getslice(self):
|
||||
# Test PyTuple_GetSlice()
|
||||
getslice = _testlimitedcapi.tuple_getslice
|
||||
|
||||
# empty
|
||||
tup = ([1], [2], [3])
|
||||
self.assertEqual(getslice(tup, PY_SSIZE_T_MIN, 0), ())
|
||||
self.assertEqual(getslice(tup, -1, 0), ())
|
||||
self.assertEqual(getslice(tup, 3, PY_SSIZE_T_MAX), ())
|
||||
self.assertEqual(getslice(tup, 1, 1), ())
|
||||
self.assertEqual(getslice(tup, 2, 1), ())
|
||||
tup = TupleSubclass(([1], [2], [3]))
|
||||
self.assertEqual(getslice(tup, PY_SSIZE_T_MIN, 0), ())
|
||||
self.assertEqual(getslice(tup, -1, 0), ())
|
||||
self.assertEqual(getslice(tup, 3, PY_SSIZE_T_MAX), ())
|
||||
self.assertEqual(getslice(tup, 1, 1), ())
|
||||
self.assertEqual(getslice(tup, 2, 1), ())
|
||||
|
||||
# slice
|
||||
tup = ([1], [2], [3], [4])
|
||||
self.assertEqual(getslice(tup, 1, 3), ([2], [3]))
|
||||
tup = TupleSubclass(([1], [2], [3], [4]))
|
||||
self.assertEqual(getslice(tup, 1, 3), ([2], [3]))
|
||||
|
||||
# whole
|
||||
tup = ([1], [2], [3])
|
||||
self.assertEqual(getslice(tup, 0, 3), tup)
|
||||
self.assertEqual(getslice(tup, 0, 100), tup)
|
||||
self.assertEqual(getslice(tup, -100, 100), tup)
|
||||
tup = TupleSubclass(([1], [2], [3]))
|
||||
self.assertEqual(getslice(tup, 0, 3), tup)
|
||||
self.assertEqual(getslice(tup, 0, 100), tup)
|
||||
self.assertEqual(getslice(tup, -100, 100), tup)
|
||||
|
||||
self.assertRaises(SystemError, getslice, [[1], [2], [3]], 0, 0)
|
||||
self.assertRaises(SystemError, getslice, 42, 0, 0)
|
||||
|
||||
# CRASHES getslice(NULL, 0, 0)
|
||||
|
||||
def test_tuple_setitem(self):
|
||||
# Test PyTuple_SetItem()
|
||||
setitem = _testlimitedcapi.tuple_setitem
|
||||
checknull = _testcapi._check_tuple_item_is_NULL
|
||||
|
||||
tup = ([1], [2])
|
||||
self.assertEqual(setitem(tup, 0, []), ([], [2]))
|
||||
self.assertEqual(setitem(tup, 1, []), ([1], []))
|
||||
|
||||
tup2 = setitem(tup, 1, NULL)
|
||||
self.assertTrue(checknull(tup2, 1))
|
||||
|
||||
tup2 = TupleSubclass(([1], [2]))
|
||||
self.assertRaises(SystemError, setitem, tup2, 0, [])
|
||||
|
||||
self.assertRaises(IndexError, setitem, tup, PY_SSIZE_T_MIN, [])
|
||||
self.assertRaises(IndexError, setitem, tup, -1, [])
|
||||
self.assertRaises(IndexError, setitem, tup, len(tup), [])
|
||||
self.assertRaises(IndexError, setitem, tup, PY_SSIZE_T_MAX, [])
|
||||
self.assertRaises(SystemError, setitem, [1], 0, [])
|
||||
self.assertRaises(SystemError, setitem, 42, 0, [])
|
||||
|
||||
# CRASHES setitem(NULL, 0, [])
|
||||
|
||||
def test_tuple_set_item(self):
|
||||
# Test PyTuple_SET_ITEM()
|
||||
set_item = _testcapi.tuple_set_item
|
||||
checknull = _testcapi._check_tuple_item_is_NULL
|
||||
|
||||
tup = ([1], [2])
|
||||
self.assertEqual(set_item(tup, 0, []), ([], [2]))
|
||||
self.assertEqual(set_item(tup, 1, []), ([1], []))
|
||||
|
||||
tup2 = set_item(tup, 1, NULL)
|
||||
self.assertTrue(checknull(tup2, 1))
|
||||
|
||||
tup2 = TupleSubclass(([1], [2]))
|
||||
self.assertIs(set_item(tup2, 0, []), tup2)
|
||||
self.assertEqual(tup2, ([], [2]))
|
||||
|
||||
# CRASHES set_item(tup, -1, [])
|
||||
# CRASHES set_item(tup, len(tup), [])
|
||||
# CRASHES set_item([1], 0, [])
|
||||
# CRASHES set_item(NULL, 0, [])
|
||||
|
||||
def test__tuple_resize(self):
|
||||
# Test _PyTuple_Resize()
|
||||
resize = _testcapi._tuple_resize
|
||||
checknull = _testcapi._check_tuple_item_is_NULL
|
||||
|
||||
a = ()
|
||||
b = resize(a, 0, False)
|
||||
self.assertEqual(len(a), 0)
|
||||
self.assertEqual(len(b), 0)
|
||||
b = resize(a, 2, False)
|
||||
self.assertEqual(len(a), 0)
|
||||
self.assertEqual(len(b), 2)
|
||||
self.assertTrue(checknull(b, 0))
|
||||
self.assertTrue(checknull(b, 1))
|
||||
|
||||
a = ([1], [2], [3])
|
||||
b = resize(a, 3)
|
||||
self.assertEqual(b, a)
|
||||
b = resize(a, 2)
|
||||
self.assertEqual(b, a[:2])
|
||||
b = resize(a, 5)
|
||||
self.assertEqual(len(b), 5)
|
||||
self.assertEqual(b[:3], a)
|
||||
self.assertTrue(checknull(b, 3))
|
||||
self.assertTrue(checknull(b, 4))
|
||||
|
||||
a = ()
|
||||
self.assertRaises(MemoryError, resize, a, PY_SSIZE_T_MAX)
|
||||
self.assertRaises(SystemError, resize, a, -1)
|
||||
self.assertRaises(SystemError, resize, a, PY_SSIZE_T_MIN)
|
||||
# refcount > 1
|
||||
a = (1, 2, 3)
|
||||
self.assertRaises(SystemError, resize, a, 3, False)
|
||||
self.assertRaises(SystemError, resize, a, 0, False)
|
||||
# non-tuple
|
||||
self.assertRaises(SystemError, resize, [1, 2, 3], 0, False)
|
||||
self.assertRaises(SystemError, resize, NULL, 0, False)
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
|
@ -163,7 +163,7 @@
|
|||
@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
|
||||
@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/monitoring.c
|
||||
@MODULE__TESTLIMITEDCAPI_TRUE@_testlimitedcapi _testlimitedcapi.c _testlimitedcapi/abstract.c _testlimitedcapi/bytearray.c _testlimitedcapi/bytes.c _testlimitedcapi/complex.c _testlimitedcapi/dict.c _testlimitedcapi/eval.c _testlimitedcapi/float.c _testlimitedcapi/heaptype_relative.c _testlimitedcapi/list.c _testlimitedcapi/long.c _testlimitedcapi/object.c _testlimitedcapi/pyos.c _testlimitedcapi/set.c _testlimitedcapi/sys.c _testlimitedcapi/unicode.c _testlimitedcapi/vectorcall_limited.c
|
||||
@MODULE__TESTLIMITEDCAPI_TRUE@_testlimitedcapi _testlimitedcapi.c _testlimitedcapi/abstract.c _testlimitedcapi/bytearray.c _testlimitedcapi/bytes.c _testlimitedcapi/complex.c _testlimitedcapi/dict.c _testlimitedcapi/eval.c _testlimitedcapi/float.c _testlimitedcapi/heaptype_relative.c _testlimitedcapi/list.c _testlimitedcapi/long.c _testlimitedcapi/object.c _testlimitedcapi/pyos.c _testlimitedcapi/set.c _testlimitedcapi/sys.c _testlimitedcapi/tuple.c _testlimitedcapi/unicode.c _testlimitedcapi/vectorcall_limited.c
|
||||
@MODULE__TESTCLINIC_TRUE@_testclinic _testclinic.c
|
||||
@MODULE__TESTCLINIC_LIMITED_TRUE@_testclinic_limited _testclinic_limited.c
|
||||
|
||||
|
|
|
@ -2,14 +2,121 @@
|
|||
#include "util.h"
|
||||
|
||||
|
||||
static PyObject *
|
||||
tuple_get_size(PyObject *Py_UNUSED(module), PyObject *obj)
|
||||
{
|
||||
NULLABLE(obj);
|
||||
RETURN_SIZE(PyTuple_GET_SIZE(obj));
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
tuple_get_item(PyObject *Py_UNUSED(module), PyObject *args)
|
||||
{
|
||||
PyObject *obj;
|
||||
Py_ssize_t i;
|
||||
if (!PyArg_ParseTuple(args, "On", &obj, &i)) {
|
||||
return NULL;
|
||||
}
|
||||
NULLABLE(obj);
|
||||
return Py_XNewRef(PyTuple_GET_ITEM(obj, i));
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
tuple_copy(PyObject *tuple)
|
||||
{
|
||||
Py_ssize_t size = PyTuple_GET_SIZE(tuple);
|
||||
PyObject *newtuple = PyTuple_New(size);
|
||||
if (!newtuple) {
|
||||
return NULL;
|
||||
}
|
||||
for (Py_ssize_t n = 0; n < size; n++) {
|
||||
PyTuple_SET_ITEM(newtuple, n, Py_XNewRef(PyTuple_GET_ITEM(tuple, n)));
|
||||
}
|
||||
return newtuple;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
tuple_set_item(PyObject *Py_UNUSED(module), PyObject *args)
|
||||
{
|
||||
PyObject *obj, *value, *newtuple;
|
||||
Py_ssize_t i;
|
||||
if (!PyArg_ParseTuple(args, "OnO", &obj, &i, &value)) {
|
||||
return NULL;
|
||||
}
|
||||
NULLABLE(value);
|
||||
if (PyTuple_CheckExact(obj)) {
|
||||
newtuple = tuple_copy(obj);
|
||||
if (!newtuple) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PyObject *val = PyTuple_GET_ITEM(newtuple, i);
|
||||
PyTuple_SET_ITEM(newtuple, i, Py_XNewRef(value));
|
||||
Py_DECREF(val);
|
||||
return newtuple;
|
||||
}
|
||||
else {
|
||||
NULLABLE(obj);
|
||||
|
||||
PyObject *val = PyTuple_GET_ITEM(obj, i);
|
||||
PyTuple_SET_ITEM(obj, i, Py_XNewRef(value));
|
||||
Py_DECREF(val);
|
||||
return Py_XNewRef(obj);
|
||||
}
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
_tuple_resize(PyObject *Py_UNUSED(module), PyObject *args)
|
||||
{
|
||||
PyObject *tup;
|
||||
Py_ssize_t newsize;
|
||||
int new = 1;
|
||||
if (!PyArg_ParseTuple(args, "On|p", &tup, &newsize, &new)) {
|
||||
return NULL;
|
||||
}
|
||||
if (new) {
|
||||
tup = tuple_copy(tup);
|
||||
if (!tup) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else {
|
||||
NULLABLE(tup);
|
||||
Py_XINCREF(tup);
|
||||
}
|
||||
int r = _PyTuple_Resize(&tup, newsize);
|
||||
if (r == -1) {
|
||||
assert(tup == NULL);
|
||||
return NULL;
|
||||
}
|
||||
return tup;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
_check_tuple_item_is_NULL(PyObject *Py_UNUSED(module), PyObject *args)
|
||||
{
|
||||
PyObject *obj;
|
||||
Py_ssize_t i;
|
||||
if (!PyArg_ParseTuple(args, "On", &obj, &i)) {
|
||||
return NULL;
|
||||
}
|
||||
return PyLong_FromLong(PyTuple_GET_ITEM(obj, i) == NULL);
|
||||
}
|
||||
|
||||
|
||||
static PyMethodDef test_methods[] = {
|
||||
{"tuple_get_size", tuple_get_size, METH_O},
|
||||
{"tuple_get_item", tuple_get_item, METH_VARARGS},
|
||||
{"tuple_set_item", tuple_set_item, METH_VARARGS},
|
||||
{"_tuple_resize", _tuple_resize, METH_VARARGS},
|
||||
{"_check_tuple_item_is_NULL", _check_tuple_item_is_NULL, METH_VARARGS},
|
||||
{NULL},
|
||||
};
|
||||
|
||||
int
|
||||
_PyTestCapi_Init_Tuple(PyObject *m)
|
||||
{
|
||||
if (PyModule_AddFunctions(m, test_methods) < 0){
|
||||
if (PyModule_AddFunctions(m, test_methods) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
|
|
@ -71,6 +71,9 @@ PyInit__testlimitedcapi(void)
|
|||
if (_PyTestLimitedCAPI_Init_Sys(mod) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
if (_PyTestLimitedCAPI_Init_Tuple(mod) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
if (_PyTestLimitedCAPI_Init_Unicode(mod) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -36,6 +36,7 @@ int _PyTestLimitedCAPI_Init_Long(PyObject *module);
|
|||
int _PyTestLimitedCAPI_Init_PyOS(PyObject *module);
|
||||
int _PyTestLimitedCAPI_Init_Set(PyObject *module);
|
||||
int _PyTestLimitedCAPI_Init_Sys(PyObject *module);
|
||||
int _PyTestLimitedCAPI_Init_Tuple(PyObject *module);
|
||||
int _PyTestLimitedCAPI_Init_Unicode(PyObject *module);
|
||||
int _PyTestLimitedCAPI_Init_VectorcallLimited(PyObject *module);
|
||||
|
||||
|
|
|
@ -0,0 +1,136 @@
|
|||
#include "parts.h"
|
||||
#include "util.h"
|
||||
|
||||
|
||||
static PyObject *
|
||||
tuple_check(PyObject* Py_UNUSED(module), PyObject *obj)
|
||||
{
|
||||
NULLABLE(obj);
|
||||
return PyLong_FromLong(PyTuple_Check(obj));
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
tuple_checkexact(PyObject* Py_UNUSED(module), PyObject *obj)
|
||||
{
|
||||
NULLABLE(obj);
|
||||
return PyLong_FromLong(PyTuple_CheckExact(obj));
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
tuple_new(PyObject* Py_UNUSED(module), PyObject *len)
|
||||
{
|
||||
return PyTuple_New(PyLong_AsSsize_t(len));
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
tuple_pack(PyObject *Py_UNUSED(module), PyObject *args)
|
||||
{
|
||||
PyObject *arg1 = NULL, *arg2 = NULL;
|
||||
Py_ssize_t size;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "n|OO", &size, &arg1, &arg2)) {
|
||||
return NULL;
|
||||
}
|
||||
if (arg1) {
|
||||
NULLABLE(arg1);
|
||||
if (arg2) {
|
||||
NULLABLE(arg2);
|
||||
return PyTuple_Pack(size, arg1, arg2);
|
||||
}
|
||||
return PyTuple_Pack(size, arg1);
|
||||
}
|
||||
return PyTuple_Pack(size);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
tuple_size(PyObject *Py_UNUSED(module), PyObject *obj)
|
||||
{
|
||||
NULLABLE(obj);
|
||||
RETURN_SIZE(PyTuple_Size(obj));
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
tuple_getitem(PyObject *Py_UNUSED(module), PyObject *args)
|
||||
{
|
||||
PyObject *obj;
|
||||
Py_ssize_t i;
|
||||
if (!PyArg_ParseTuple(args, "On", &obj, &i)) {
|
||||
return NULL;
|
||||
}
|
||||
NULLABLE(obj);
|
||||
return Py_XNewRef(PyTuple_GetItem(obj, i));
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
tuple_getslice(PyObject *Py_UNUSED(module), PyObject *args)
|
||||
{
|
||||
PyObject *obj;
|
||||
Py_ssize_t ilow, ihigh;
|
||||
if (!PyArg_ParseTuple(args, "Onn", &obj, &ilow, &ihigh)) {
|
||||
return NULL;
|
||||
}
|
||||
NULLABLE(obj);
|
||||
return PyTuple_GetSlice(obj, ilow, ihigh);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
tuple_setitem(PyObject *Py_UNUSED(module), PyObject *args)
|
||||
{
|
||||
PyObject *obj, *value, *newtuple = NULL;
|
||||
Py_ssize_t i;
|
||||
if (!PyArg_ParseTuple(args, "OnO", &obj, &i, &value)) {
|
||||
return NULL;
|
||||
}
|
||||
NULLABLE(value);
|
||||
if (PyTuple_CheckExact(obj)) {
|
||||
Py_ssize_t size = PyTuple_Size(obj);
|
||||
newtuple = PyTuple_New(size);
|
||||
if (!newtuple) {
|
||||
return NULL;
|
||||
}
|
||||
for (Py_ssize_t n = 0; n < size; n++) {
|
||||
if (PyTuple_SetItem(newtuple, n,
|
||||
Py_XNewRef(PyTuple_GetItem(obj, n))) == -1) {
|
||||
Py_DECREF(newtuple);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (PyTuple_SetItem(newtuple, i, Py_XNewRef(value)) == -1) {
|
||||
Py_DECREF(newtuple);
|
||||
return NULL;
|
||||
}
|
||||
return newtuple;
|
||||
}
|
||||
else {
|
||||
NULLABLE(obj);
|
||||
|
||||
if (PyTuple_SetItem(obj, i, Py_XNewRef(value)) == -1) {
|
||||
return NULL;
|
||||
}
|
||||
return Py_XNewRef(obj);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static PyMethodDef test_methods[] = {
|
||||
{"tuple_check", tuple_check, METH_O},
|
||||
{"tuple_checkexact", tuple_checkexact, METH_O},
|
||||
{"tuple_new", tuple_new, METH_O},
|
||||
{"tuple_pack", tuple_pack, METH_VARARGS},
|
||||
{"tuple_size", tuple_size, METH_O},
|
||||
{"tuple_getitem", tuple_getitem, METH_VARARGS},
|
||||
{"tuple_getslice", tuple_getslice, METH_VARARGS},
|
||||
{"tuple_setitem", tuple_setitem, METH_VARARGS},
|
||||
{NULL},
|
||||
};
|
||||
|
||||
int
|
||||
_PyTestLimitedCAPI_Init_Tuple(PyObject *m)
|
||||
{
|
||||
if (PyModule_AddFunctions(m, test_methods) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -108,6 +108,7 @@
|
|||
<ClCompile Include="..\Modules\_testlimitedcapi\pyos.c" />
|
||||
<ClCompile Include="..\Modules\_testlimitedcapi\set.c" />
|
||||
<ClCompile Include="..\Modules\_testlimitedcapi\sys.c" />
|
||||
<ClCompile Include="..\Modules\_testlimitedcapi\tuple.c" />
|
||||
<ClCompile Include="..\Modules\_testlimitedcapi\unicode.c" />
|
||||
<ClCompile Include="..\Modules\_testlimitedcapi\vectorcall_limited.c" />
|
||||
</ItemGroup>
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
<ClCompile Include="..\Modules\_testlimitedcapi\set.c" />
|
||||
<ClCompile Include="..\Modules\_testlimitedcapi\sys.c" />
|
||||
<ClCompile Include="..\Modules\_testlimitedcapi\testcapi_long.h" />
|
||||
<ClCompile Include="..\Modules\_testlimitedcapi\tuple.c" />
|
||||
<ClCompile Include="..\Modules\_testlimitedcapi\unicode.c" />
|
||||
<ClCompile Include="..\Modules\_testlimitedcapi\vectorcall_limited.c" />
|
||||
<ClCompile Include="..\Modules\_testlimitedcapi.c" />
|
||||
|
|
Loading…
Reference in New Issue