summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSam Gross <colesbury@gmail.com>2024-02-02 13:03:15 (GMT)
committerGitHub <noreply@github.com>2024-02-02 13:03:15 (GMT)
commitd0f1307580a69372611d27b04bbf2551dc85a1ef (patch)
treec690e6915eb44d57fc8af1623dc57babe3eca3ab
parent0e71a295e9530c939a5efcb45db23cf31e0303b4 (diff)
downloadcpython-d0f1307580a69372611d27b04bbf2551dc85a1ef.zip
cpython-d0f1307580a69372611d27b04bbf2551dc85a1ef.tar.gz
cpython-d0f1307580a69372611d27b04bbf2551dc85a1ef.tar.bz2
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()`.
-rw-r--r--Doc/c-api/list.rst12
-rw-r--r--Doc/data/refcounts.dat4
-rw-r--r--Doc/data/stable_abi.dat1
-rw-r--r--Doc/whatsnew/3.13.rst4
-rw-r--r--Include/listobject.h1
-rw-r--r--Lib/test/test_capi/test_list.py22
-rw-r--r--Lib/test/test_stable_abi_ctypes.py1
-rw-r--r--Misc/NEWS.d/next/C API/2024-01-23-21-45-02.gh-issue-114329.YRaBoe.rst3
-rw-r--r--Misc/stable_abi.toml2
-rw-r--r--Modules/_testcapi/list.c13
-rw-r--r--Objects/listobject.c15
-rwxr-xr-xPC/python3dll.c1
12 files changed, 68 insertions, 11 deletions
diff --git a/Doc/c-api/list.rst b/Doc/c-api/list.rst
index c8b64ba..53eb54d 100644
--- a/Doc/c-api/list.rst
+++ b/Doc/c-api/list.rst
@@ -56,13 +56,21 @@ List Objects
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
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.
+ .. 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)
diff --git a/Doc/data/refcounts.dat b/Doc/data/refcounts.dat
index f719ce1..62a9614 100644
--- a/Doc/data/refcounts.dat
+++ b/Doc/data/refcounts.dat
@@ -1133,6 +1133,10 @@ PyList_GetItem:PyObject*::0:
PyList_GetItem:PyObject*:list:0:
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*:list:0:
PyList_GetSlice:Py_ssize_t:low::
diff --git a/Doc/data/stable_abi.dat b/Doc/data/stable_abi.dat
index da28a2b..def1903 100644
--- a/Doc/data/stable_abi.dat
+++ b/Doc/data/stable_abi.dat
@@ -336,6 +336,7 @@ var,PyListRevIter_Type,3.2,,
function,PyList_Append,3.2,,
function,PyList_AsTuple,3.2,,
function,PyList_GetItem,3.2,,
+function,PyList_GetItemRef,3.13,,
function,PyList_GetSlice,3.2,,
function,PyList_Insert,3.2,,
function,PyList_New,3.2,,
diff --git a/Doc/whatsnew/3.13.rst b/Doc/whatsnew/3.13.rst
index 887c300..f17c6ec 100644
--- a/Doc/whatsnew/3.13.rst
+++ b/Doc/whatsnew/3.13.rst
@@ -1376,6 +1376,10 @@ New Features
UTF-8 encoded bytes string, rather than a :c:expr:`PyObject*`.
(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
:term:`shutting down <interpreter shutdown>`.
(Contributed by Victor Stinner in :gh:`108014`.)
diff --git a/Include/listobject.h b/Include/listobject.h
index 6b7041b..4e4084b 100644
--- a/Include/listobject.h
+++ b/Include/listobject.h
@@ -29,6 +29,7 @@ PyAPI_FUNC(PyObject *) PyList_New(Py_ssize_t size);
PyAPI_FUNC(Py_ssize_t) PyList_Size(PyObject *);
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_Insert(PyObject *, Py_ssize_t, PyObject *);
PyAPI_FUNC(int) PyList_Append(PyObject *, PyObject *);
diff --git a/Lib/test/test_capi/test_list.py b/Lib/test/test_capi/test_list.py
index eb03d51..dceb4fc 100644
--- a/Lib/test/test_capi/test_list.py
+++ b/Lib/test/test_capi/test_list.py
@@ -82,10 +82,8 @@ class CAPITest(unittest.TestCase):
# CRASHES size(UserList())
# CRASHES size(NULL)
-
- def test_list_getitem(self):
- # Test PyList_GetItem()
- getitem = _testcapi.list_getitem
+ def check_list_get_item(self, getitem, exctype):
+ # Common test cases for PyList_GetItem() and PyList_GetItemRef()
lst = [1, 2, 3]
self.assertEqual(getitem(lst, 0), 1)
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, PY_SSIZE_T_MIN)
self.assertRaises(IndexError, getitem, lst, PY_SSIZE_T_MAX)
- self.assertRaises(SystemError, getitem, 42, 1)
- self.assertRaises(SystemError, getitem, (1, 2, 3), 1)
- self.assertRaises(SystemError, getitem, {1: 2}, 1)
-
+ self.assertRaises(exctype, getitem, 42, 1)
+ self.assertRaises(exctype, getitem, (1, 2, 3), 1)
+ self.assertRaises(exctype, getitem, {1: 2}, 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):
# Test PyList_GET_ITEM()
get_item = _testcapi.list_get_item
@@ -112,7 +117,6 @@ class CAPITest(unittest.TestCase):
# CRASHES get_item(21, 2)
# CRASHES get_item(NULL, 1)
-
def test_list_setitem(self):
# Test PyList_SetItem()
setitem = _testcapi.list_setitem
diff --git a/Lib/test/test_stable_abi_ctypes.py b/Lib/test/test_stable_abi_ctypes.py
index 054e7f0..8bd3739 100644
--- a/Lib/test/test_stable_abi_ctypes.py
+++ b/Lib/test/test_stable_abi_ctypes.py
@@ -372,6 +372,7 @@ SYMBOL_NAMES = (
"PyList_Append",
"PyList_AsTuple",
"PyList_GetItem",
+ "PyList_GetItemRef",
"PyList_GetSlice",
"PyList_Insert",
"PyList_New",
diff --git a/Misc/NEWS.d/next/C API/2024-01-23-21-45-02.gh-issue-114329.YRaBoe.rst b/Misc/NEWS.d/next/C API/2024-01-23-21-45-02.gh-issue-114329.YRaBoe.rst
new file mode 100644
index 0000000..62d4ce0
--- /dev/null
+++ b/Misc/NEWS.d/next/C API/2024-01-23-21-45-02.gh-issue-114329.YRaBoe.rst
@@ -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`.
diff --git a/Misc/stable_abi.toml b/Misc/stable_abi.toml
index ae19d25..a9875f6 100644
--- a/Misc/stable_abi.toml
+++ b/Misc/stable_abi.toml
@@ -2487,3 +2487,5 @@
abi_only = true
[data.PyExc_IncompleteInputError]
added = '3.13'
+[function.PyList_GetItemRef]
+ added = '3.13'
diff --git a/Modules/_testcapi/list.c b/Modules/_testcapi/list.c
index 10e1869..2cb6499 100644
--- a/Modules/_testcapi/list.c
+++ b/Modules/_testcapi/list.c
@@ -60,6 +60,18 @@ list_get_item(PyObject *Py_UNUSED(module), PyObject *args)
}
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 *
list_setitem(PyObject *Py_UNUSED(module), PyObject *args)
{
PyObject *obj, *value;
@@ -191,6 +203,7 @@ static PyMethodDef test_methods[] = {
{"list_get_size", list_get_size, METH_O},
{"list_getitem", list_getitem, 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_set_item", list_set_item, METH_VARARGS},
{"list_insert", list_insert, METH_VARARGS},
diff --git a/Objects/listobject.c b/Objects/listobject.c
index da2b9cc..82a4ba9 100644
--- a/Objects/listobject.c
+++ b/Objects/listobject.c
@@ -257,6 +257,21 @@ PyList_GetItem(PyObject *op, Py_ssize_t 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
PyList_SetItem(PyObject *op, Py_ssize_t i,
PyObject *newitem)
diff --git a/PC/python3dll.c b/PC/python3dll.c
index 09ecf98..aa6bfe2 100755
--- a/PC/python3dll.c
+++ b/PC/python3dll.c
@@ -324,6 +324,7 @@ EXPORT_FUNC(PyIter_Send)
EXPORT_FUNC(PyList_Append)
EXPORT_FUNC(PyList_AsTuple)
EXPORT_FUNC(PyList_GetItem)
+EXPORT_FUNC(PyList_GetItemRef)
EXPORT_FUNC(PyList_GetSlice)
EXPORT_FUNC(PyList_Insert)
EXPORT_FUNC(PyList_New)