mirror of https://github.com/python/cpython
gh-114329: Add `PyList_GetItemRef` function (GH-114504)
The new `PyList_GetItemRef` is similar to `PyList_GetItem`, but returns a strong reference instead of a borrowed reference. Additionally, if the passed "list" object is not a list, the function sets a `TypeError` instead of calling `PyErr_BadInternalCall()`.
This commit is contained in:
parent
0e71a295e9
commit
d0f1307580
|
@ -56,13 +56,21 @@ List Objects
|
||||||
Similar to :c:func:`PyList_Size`, but without error checking.
|
Similar to :c:func:`PyList_Size`, but without error checking.
|
||||||
|
|
||||||
|
|
||||||
.. c:function:: PyObject* PyList_GetItem(PyObject *list, Py_ssize_t index)
|
.. c:function:: PyObject* PyList_GetItemRef(PyObject *list, Py_ssize_t index)
|
||||||
|
|
||||||
Return the object at position *index* in the list pointed to by *list*. The
|
Return the object at position *index* in the list pointed to by *list*. The
|
||||||
position must be non-negative; indexing from the end of the list is not
|
position must be non-negative; indexing from the end of the list is not
|
||||||
supported. If *index* is out of bounds (<0 or >=len(list)),
|
supported. If *index* is out of bounds (:code:`<0 or >=len(list)`),
|
||||||
return ``NULL`` and set an :exc:`IndexError` exception.
|
return ``NULL`` and set an :exc:`IndexError` exception.
|
||||||
|
|
||||||
|
.. versionadded:: 3.13
|
||||||
|
|
||||||
|
|
||||||
|
.. c:function:: PyObject* PyList_GetItem(PyObject *list, Py_ssize_t index)
|
||||||
|
|
||||||
|
Like :c:func:`PyList_GetItemRef`, but returns a
|
||||||
|
:term:`borrowed reference` instead of a :term:`strong reference`.
|
||||||
|
|
||||||
|
|
||||||
.. c:function:: PyObject* PyList_GET_ITEM(PyObject *list, Py_ssize_t i)
|
.. c:function:: PyObject* PyList_GET_ITEM(PyObject *list, Py_ssize_t i)
|
||||||
|
|
||||||
|
|
|
@ -1133,6 +1133,10 @@ PyList_GetItem:PyObject*::0:
|
||||||
PyList_GetItem:PyObject*:list:0:
|
PyList_GetItem:PyObject*:list:0:
|
||||||
PyList_GetItem:Py_ssize_t:index::
|
PyList_GetItem:Py_ssize_t:index::
|
||||||
|
|
||||||
|
PyList_GetItemRef:PyObject*::+1:
|
||||||
|
PyList_GetItemRef:PyObject*:list:0:
|
||||||
|
PyList_GetItemRef:Py_ssize_t:index::
|
||||||
|
|
||||||
PyList_GetSlice:PyObject*::+1:
|
PyList_GetSlice:PyObject*::+1:
|
||||||
PyList_GetSlice:PyObject*:list:0:
|
PyList_GetSlice:PyObject*:list:0:
|
||||||
PyList_GetSlice:Py_ssize_t:low::
|
PyList_GetSlice:Py_ssize_t:low::
|
||||||
|
|
|
@ -336,6 +336,7 @@ var,PyListRevIter_Type,3.2,,
|
||||||
function,PyList_Append,3.2,,
|
function,PyList_Append,3.2,,
|
||||||
function,PyList_AsTuple,3.2,,
|
function,PyList_AsTuple,3.2,,
|
||||||
function,PyList_GetItem,3.2,,
|
function,PyList_GetItem,3.2,,
|
||||||
|
function,PyList_GetItemRef,3.13,,
|
||||||
function,PyList_GetSlice,3.2,,
|
function,PyList_GetSlice,3.2,,
|
||||||
function,PyList_Insert,3.2,,
|
function,PyList_Insert,3.2,,
|
||||||
function,PyList_New,3.2,,
|
function,PyList_New,3.2,,
|
||||||
|
|
|
@ -1376,6 +1376,10 @@ New Features
|
||||||
UTF-8 encoded bytes string, rather than a :c:expr:`PyObject*`.
|
UTF-8 encoded bytes string, rather than a :c:expr:`PyObject*`.
|
||||||
(Contributed by Victor Stinner in :gh:`108314`.)
|
(Contributed by Victor Stinner in :gh:`108314`.)
|
||||||
|
|
||||||
|
* Added :c:func:`PyList_GetItemRef` function: similar to
|
||||||
|
:c:func:`PyList_GetItem` but returns a :term:`strong reference` instead of
|
||||||
|
a :term:`borrowed reference`.
|
||||||
|
|
||||||
* Add :c:func:`Py_IsFinalizing` function: check if the main Python interpreter is
|
* Add :c:func:`Py_IsFinalizing` function: check if the main Python interpreter is
|
||||||
:term:`shutting down <interpreter shutdown>`.
|
:term:`shutting down <interpreter shutdown>`.
|
||||||
(Contributed by Victor Stinner in :gh:`108014`.)
|
(Contributed by Victor Stinner in :gh:`108014`.)
|
||||||
|
|
|
@ -29,6 +29,7 @@ PyAPI_FUNC(PyObject *) PyList_New(Py_ssize_t size);
|
||||||
PyAPI_FUNC(Py_ssize_t) PyList_Size(PyObject *);
|
PyAPI_FUNC(Py_ssize_t) PyList_Size(PyObject *);
|
||||||
|
|
||||||
PyAPI_FUNC(PyObject *) PyList_GetItem(PyObject *, Py_ssize_t);
|
PyAPI_FUNC(PyObject *) PyList_GetItem(PyObject *, Py_ssize_t);
|
||||||
|
PyAPI_FUNC(PyObject *) PyList_GetItemRef(PyObject *, Py_ssize_t);
|
||||||
PyAPI_FUNC(int) PyList_SetItem(PyObject *, Py_ssize_t, PyObject *);
|
PyAPI_FUNC(int) PyList_SetItem(PyObject *, Py_ssize_t, PyObject *);
|
||||||
PyAPI_FUNC(int) PyList_Insert(PyObject *, Py_ssize_t, PyObject *);
|
PyAPI_FUNC(int) PyList_Insert(PyObject *, Py_ssize_t, PyObject *);
|
||||||
PyAPI_FUNC(int) PyList_Append(PyObject *, PyObject *);
|
PyAPI_FUNC(int) PyList_Append(PyObject *, PyObject *);
|
||||||
|
|
|
@ -82,10 +82,8 @@ class CAPITest(unittest.TestCase):
|
||||||
# CRASHES size(UserList())
|
# CRASHES size(UserList())
|
||||||
# CRASHES size(NULL)
|
# CRASHES size(NULL)
|
||||||
|
|
||||||
|
def check_list_get_item(self, getitem, exctype):
|
||||||
def test_list_getitem(self):
|
# Common test cases for PyList_GetItem() and PyList_GetItemRef()
|
||||||
# Test PyList_GetItem()
|
|
||||||
getitem = _testcapi.list_getitem
|
|
||||||
lst = [1, 2, 3]
|
lst = [1, 2, 3]
|
||||||
self.assertEqual(getitem(lst, 0), 1)
|
self.assertEqual(getitem(lst, 0), 1)
|
||||||
self.assertEqual(getitem(lst, 2), 3)
|
self.assertEqual(getitem(lst, 2), 3)
|
||||||
|
@ -93,12 +91,19 @@ class CAPITest(unittest.TestCase):
|
||||||
self.assertRaises(IndexError, getitem, lst, -1)
|
self.assertRaises(IndexError, getitem, lst, -1)
|
||||||
self.assertRaises(IndexError, getitem, lst, PY_SSIZE_T_MIN)
|
self.assertRaises(IndexError, getitem, lst, PY_SSIZE_T_MIN)
|
||||||
self.assertRaises(IndexError, getitem, lst, PY_SSIZE_T_MAX)
|
self.assertRaises(IndexError, getitem, lst, PY_SSIZE_T_MAX)
|
||||||
self.assertRaises(SystemError, getitem, 42, 1)
|
self.assertRaises(exctype, getitem, 42, 1)
|
||||||
self.assertRaises(SystemError, getitem, (1, 2, 3), 1)
|
self.assertRaises(exctype, getitem, (1, 2, 3), 1)
|
||||||
self.assertRaises(SystemError, getitem, {1: 2}, 1)
|
self.assertRaises(exctype, getitem, {1: 2}, 1)
|
||||||
|
|
||||||
# CRASHES getitem(NULL, 1)
|
# CRASHES getitem(NULL, 1)
|
||||||
|
|
||||||
|
def test_list_getitem(self):
|
||||||
|
# Test PyList_GetItem()
|
||||||
|
self.check_list_get_item(_testcapi.list_getitem, SystemError)
|
||||||
|
|
||||||
|
def test_list_get_item_ref(self):
|
||||||
|
# Test PyList_GetItemRef()
|
||||||
|
self.check_list_get_item(_testcapi.list_get_item_ref, TypeError)
|
||||||
|
|
||||||
def test_list_get_item(self):
|
def test_list_get_item(self):
|
||||||
# Test PyList_GET_ITEM()
|
# Test PyList_GET_ITEM()
|
||||||
get_item = _testcapi.list_get_item
|
get_item = _testcapi.list_get_item
|
||||||
|
@ -112,7 +117,6 @@ class CAPITest(unittest.TestCase):
|
||||||
# CRASHES get_item(21, 2)
|
# CRASHES get_item(21, 2)
|
||||||
# CRASHES get_item(NULL, 1)
|
# CRASHES get_item(NULL, 1)
|
||||||
|
|
||||||
|
|
||||||
def test_list_setitem(self):
|
def test_list_setitem(self):
|
||||||
# Test PyList_SetItem()
|
# Test PyList_SetItem()
|
||||||
setitem = _testcapi.list_setitem
|
setitem = _testcapi.list_setitem
|
||||||
|
|
|
@ -372,6 +372,7 @@ SYMBOL_NAMES = (
|
||||||
"PyList_Append",
|
"PyList_Append",
|
||||||
"PyList_AsTuple",
|
"PyList_AsTuple",
|
||||||
"PyList_GetItem",
|
"PyList_GetItem",
|
||||||
|
"PyList_GetItemRef",
|
||||||
"PyList_GetSlice",
|
"PyList_GetSlice",
|
||||||
"PyList_Insert",
|
"PyList_Insert",
|
||||||
"PyList_New",
|
"PyList_New",
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
Add :c:func:`PyList_GetItemRef`, which is similar to
|
||||||
|
:c:func:`PyList_GetItem` but returns a :term:`strong reference` instead of a
|
||||||
|
:term:`borrowed reference`.
|
|
@ -2487,3 +2487,5 @@
|
||||||
abi_only = true
|
abi_only = true
|
||||||
[data.PyExc_IncompleteInputError]
|
[data.PyExc_IncompleteInputError]
|
||||||
added = '3.13'
|
added = '3.13'
|
||||||
|
[function.PyList_GetItemRef]
|
||||||
|
added = '3.13'
|
||||||
|
|
|
@ -59,6 +59,18 @@ list_get_item(PyObject *Py_UNUSED(module), PyObject *args)
|
||||||
return Py_XNewRef(PyList_GET_ITEM(obj, i));
|
return Py_XNewRef(PyList_GET_ITEM(obj, i));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
list_get_item_ref(PyObject *Py_UNUSED(module), PyObject *args)
|
||||||
|
{
|
||||||
|
PyObject *obj;
|
||||||
|
Py_ssize_t i;
|
||||||
|
if (!PyArg_ParseTuple(args, "On", &obj, &i)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
NULLABLE(obj);
|
||||||
|
return PyList_GetItemRef(obj, i);
|
||||||
|
}
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
list_setitem(PyObject *Py_UNUSED(module), PyObject *args)
|
list_setitem(PyObject *Py_UNUSED(module), PyObject *args)
|
||||||
{
|
{
|
||||||
|
@ -191,6 +203,7 @@ static PyMethodDef test_methods[] = {
|
||||||
{"list_get_size", list_get_size, METH_O},
|
{"list_get_size", list_get_size, METH_O},
|
||||||
{"list_getitem", list_getitem, METH_VARARGS},
|
{"list_getitem", list_getitem, METH_VARARGS},
|
||||||
{"list_get_item", list_get_item, METH_VARARGS},
|
{"list_get_item", list_get_item, METH_VARARGS},
|
||||||
|
{"list_get_item_ref", list_get_item_ref, METH_VARARGS},
|
||||||
{"list_setitem", list_setitem, METH_VARARGS},
|
{"list_setitem", list_setitem, METH_VARARGS},
|
||||||
{"list_set_item", list_set_item, METH_VARARGS},
|
{"list_set_item", list_set_item, METH_VARARGS},
|
||||||
{"list_insert", list_insert, METH_VARARGS},
|
{"list_insert", list_insert, METH_VARARGS},
|
||||||
|
|
|
@ -257,6 +257,21 @@ PyList_GetItem(PyObject *op, Py_ssize_t i)
|
||||||
return ((PyListObject *)op) -> ob_item[i];
|
return ((PyListObject *)op) -> ob_item[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PyObject *
|
||||||
|
PyList_GetItemRef(PyObject *op, Py_ssize_t i)
|
||||||
|
{
|
||||||
|
if (!PyList_Check(op)) {
|
||||||
|
PyErr_SetString(PyExc_TypeError, "expected a list");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (!valid_index(i, Py_SIZE(op))) {
|
||||||
|
_Py_DECLARE_STR(list_err, "list index out of range");
|
||||||
|
PyErr_SetObject(PyExc_IndexError, &_Py_STR(list_err));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return Py_NewRef(PyList_GET_ITEM(op, i));
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
PyList_SetItem(PyObject *op, Py_ssize_t i,
|
PyList_SetItem(PyObject *op, Py_ssize_t i,
|
||||||
PyObject *newitem)
|
PyObject *newitem)
|
||||||
|
|
|
@ -324,6 +324,7 @@ EXPORT_FUNC(PyIter_Send)
|
||||||
EXPORT_FUNC(PyList_Append)
|
EXPORT_FUNC(PyList_Append)
|
||||||
EXPORT_FUNC(PyList_AsTuple)
|
EXPORT_FUNC(PyList_AsTuple)
|
||||||
EXPORT_FUNC(PyList_GetItem)
|
EXPORT_FUNC(PyList_GetItem)
|
||||||
|
EXPORT_FUNC(PyList_GetItemRef)
|
||||||
EXPORT_FUNC(PyList_GetSlice)
|
EXPORT_FUNC(PyList_GetSlice)
|
||||||
EXPORT_FUNC(PyList_Insert)
|
EXPORT_FUNC(PyList_Insert)
|
||||||
EXPORT_FUNC(PyList_New)
|
EXPORT_FUNC(PyList_New)
|
||||||
|
|
Loading…
Reference in New Issue