https://github.com/python/cpython/commit/10cbd1fe88d1095a03cce24fb126d479668a67c3
commit: 10cbd1fe88d1095a03cce24fb126d479668a67c3
branch: main
author: Victor Stinner <[email protected]>
committer: vstinner <[email protected]>
date: 2025-03-13T13:00:57+01:00
summary:
gh-130947: Add again PySequence_Fast() to the limited C API (#130948)
Add again PySequence_Fast() to the limited C API.
Add unit tests.
files:
A Misc/NEWS.d/next/C_API/2025-03-07-14-49-06.gh-issue-130947._Pw0IX.rst
M Doc/data/stable_abi.dat
M Doc/whatsnew/3.14.rst
M Include/abstract.h
M Include/cpython/abstract.h
M Lib/test/test_capi/test_abstract.py
M Misc/stable_abi.toml
M Modules/_testcapi/abstract.c
M Modules/_testlimitedcapi/abstract.c
diff --git a/Doc/data/stable_abi.dat b/Doc/data/stable_abi.dat
index 59e7a31bc2ef06..c15f82603aa944 100644
--- a/Doc/data/stable_abi.dat
+++ b/Doc/data/stable_abi.dat
@@ -582,6 +582,7 @@ func,PySequence_Contains,3.2,,
func,PySequence_Count,3.2,,
func,PySequence_DelItem,3.2,,
func,PySequence_DelSlice,3.2,,
+func,PySequence_Fast,3.2,,
func,PySequence_GetItem,3.2,,
func,PySequence_GetSlice,3.2,,
func,PySequence_In,3.2,,
diff --git a/Doc/whatsnew/3.14.rst b/Doc/whatsnew/3.14.rst
index 28879c4a4b5fed..8f58901b28e1b0 100644
--- a/Doc/whatsnew/3.14.rst
+++ b/Doc/whatsnew/3.14.rst
@@ -1598,9 +1598,10 @@ Limited C API changes
implementation details.
(Contributed by Victor Stinner in :gh:`120600` and :gh:`124127`.)
-* Remove :c:func:`PySequence_Fast` from the limited C API, since this function
- has to be used with :c:macro:`PySequence_Fast_GET_ITEM` which never worked
- in the limited C API.
+* Remove the :c:macro:`PySequence_Fast_GET_SIZE`,
+ :c:macro:`PySequence_Fast_GET_ITEM` and :c:macro:`PySequence_Fast_ITEMS`
+ macros from the limited C API, since these macros never worked in the limited
+ C API. Keep :c:func:`PySequence_Fast` in the limited C API.
(Contributed by Victor Stinner in :gh:`91417`.)
diff --git a/Include/abstract.h b/Include/abstract.h
index 4efe4fcb014903..b9199fc03a399a 100644
--- a/Include/abstract.h
+++ b/Include/abstract.h
@@ -726,6 +726,15 @@ PyAPI_FUNC(PyObject *) PySequence_Tuple(PyObject *o);
This is equivalent to the Python expression: list(o) */
PyAPI_FUNC(PyObject *) PySequence_List(PyObject *o);
+/* Return the sequence 'o' as a list, unless it's already a tuple or list.
+
+ Use PySequence_Fast_GET_ITEM to access the members of this list, and
+ PySequence_Fast_GET_SIZE to get its length.
+
+ Returns NULL on failure. If the object does not support iteration, raises a
+ TypeError exception with 'm' as the message text. */
+PyAPI_FUNC(PyObject *) PySequence_Fast(PyObject *o, const char* m);
+
/* Return the number of occurrences on value on 'o', that is, return
the number of keys for which o[key] == value.
diff --git a/Include/cpython/abstract.h b/Include/cpython/abstract.h
index 8fed1d3110988b..ffd19ccd3500fa 100644
--- a/Include/cpython/abstract.h
+++ b/Include/cpython/abstract.h
@@ -86,15 +86,6 @@ PyAPI_FUNC(Py_ssize_t) PyObject_LengthHint(PyObject *o,
Py_ssize_t);
#define PySequence_ITEM(o, i)\
( Py_TYPE(o)->tp_as_sequence->sq_item((o), (i)) )
-/* Return the sequence 'o' as a list, unless it's already a tuple or list.
-
- Use PySequence_Fast_GET_ITEM to access the members of this list, and
- PySequence_Fast_GET_SIZE to get its length.
-
- Returns NULL on failure. If the object does not support iteration, raises a
- TypeError exception with 'm' as the message text. */
-PyAPI_FUNC(PyObject *) PySequence_Fast(PyObject *o, const char* m);
-
/* Return the size of the sequence 'o', assuming that 'o' was returned by
PySequence_Fast and is not NULL. */
#define PySequence_Fast_GET_SIZE(o) \
diff --git a/Lib/test/test_capi/test_abstract.py
b/Lib/test/test_capi/test_abstract.py
index 3de251bc5c241e..912c2de2b69930 100644
--- a/Lib/test/test_capi/test_abstract.py
+++ b/Lib/test/test_capi/test_abstract.py
@@ -994,6 +994,42 @@ def test_sequence_tuple(self):
self.assertRaises(TypeError, xtuple, 42)
self.assertRaises(SystemError, xtuple, NULL)
+ def test_sequence_fast(self):
+ # Test PySequence_Fast()
+ sequence_fast = _testlimitedcapi.sequence_fast
+ sequence_fast_get_size = _testcapi.sequence_fast_get_size
+ sequence_fast_get_item = _testcapi.sequence_fast_get_item
+
+ tpl = ('a', 'b', 'c')
+ fast = sequence_fast(tpl, "err_msg")
+ self.assertIs(fast, tpl)
+ self.assertEqual(sequence_fast_get_size(fast), 3)
+ self.assertEqual(sequence_fast_get_item(fast, 2), 'c')
+
+ lst = ['a', 'b', 'c']
+ fast = sequence_fast(lst, "err_msg")
+ self.assertIs(fast, lst)
+ self.assertEqual(sequence_fast_get_size(fast), 3)
+ self.assertEqual(sequence_fast_get_item(fast, 2), 'c')
+
+ it = iter(['A', 'B'])
+ fast = sequence_fast(it, "err_msg")
+ self.assertEqual(fast, ['A', 'B'])
+ self.assertEqual(sequence_fast_get_size(fast), 2)
+ self.assertEqual(sequence_fast_get_item(fast, 1), 'B')
+
+ text = 'fast'
+ fast = sequence_fast(text, "err_msg")
+ self.assertEqual(fast, ['f', 'a', 's', 't'])
+ self.assertEqual(sequence_fast_get_size(fast), 4)
+ self.assertEqual(sequence_fast_get_item(fast, 0), 'f')
+
+ self.assertRaises(TypeError, sequence_fast, 42, "err_msg")
+ self.assertRaises(SystemError, sequence_fast, NULL, "err_msg")
+
+ # CRASHES sequence_fast_get_size(NULL)
+ # CRASHES sequence_fast_get_item(NULL, 0)
+
def test_object_generichash(self):
# Test PyObject_GenericHash()
generichash = _testcapi.object_generichash
diff --git
a/Misc/NEWS.d/next/C_API/2025-03-07-14-49-06.gh-issue-130947._Pw0IX.rst
b/Misc/NEWS.d/next/C_API/2025-03-07-14-49-06.gh-issue-130947._Pw0IX.rst
new file mode 100644
index 00000000000000..ff983d4a180f57
--- /dev/null
+++ b/Misc/NEWS.d/next/C_API/2025-03-07-14-49-06.gh-issue-130947._Pw0IX.rst
@@ -0,0 +1,2 @@
+Add again :c:func:`PySequence_Fast` to the limited C API.
+Patch by Victor Stinner.
diff --git a/Misc/stable_abi.toml b/Misc/stable_abi.toml
index 9317be605f0065..276526a1b6908e 100644
--- a/Misc/stable_abi.toml
+++ b/Misc/stable_abi.toml
@@ -1253,7 +1253,6 @@
added = '3.2'
[function.PySequence_Fast]
added = '3.2'
- abi_only = true
[function.PySequence_GetItem]
added = '3.2'
[function.PySequence_GetSlice]
diff --git a/Modules/_testcapi/abstract.c b/Modules/_testcapi/abstract.c
index 8c2c7137cdce40..d4045afd515909 100644
--- a/Modules/_testcapi/abstract.c
+++ b/Modules/_testcapi/abstract.c
@@ -157,6 +157,27 @@ pyiter_nextitem(PyObject *self, PyObject *iter)
}
+static PyObject *
+sequence_fast_get_size(PyObject *self, PyObject *obj)
+{
+ NULLABLE(obj);
+ return PyLong_FromSsize_t(PySequence_Fast_GET_SIZE(obj));
+}
+
+
+static PyObject *
+sequence_fast_get_item(PyObject *self, PyObject *args)
+{
+ PyObject *obj;
+ Py_ssize_t index;
+ if (!PyArg_ParseTuple(args, "On", &obj, &index)) {
+ return NULL;
+ }
+ NULLABLE(obj);
+ return PySequence_Fast_GET_ITEM(obj, index);
+}
+
+
static PyMethodDef test_methods[] = {
{"object_getoptionalattr", object_getoptionalattr, METH_VARARGS},
{"object_getoptionalattrstring", object_getoptionalattrstring,
METH_VARARGS},
@@ -167,6 +188,9 @@ static PyMethodDef test_methods[] = {
{"PyIter_Next", pyiter_next, METH_O},
{"PyIter_NextItem", pyiter_nextitem, METH_O},
+
+ {"sequence_fast_get_size", sequence_fast_get_size, METH_O},
+ {"sequence_fast_get_item", sequence_fast_get_item, METH_VARARGS},
{NULL},
};
diff --git a/Modules/_testlimitedcapi/abstract.c
b/Modules/_testlimitedcapi/abstract.c
index 6056dd100d6069..e107e53fea8c33 100644
--- a/Modules/_testlimitedcapi/abstract.c
+++ b/Modules/_testlimitedcapi/abstract.c
@@ -516,6 +516,19 @@ sequence_tuple(PyObject *self, PyObject *obj)
}
+static PyObject *
+sequence_fast(PyObject *self, PyObject *args)
+{
+ PyObject *obj;
+ const char *err_msg;
+ if (!PyArg_ParseTuple(args, "Os", &obj, &err_msg)) {
+ return NULL;
+ }
+ NULLABLE(obj);
+ return PySequence_Fast(obj, err_msg);
+}
+
+
static PyMethodDef test_methods[] = {
{"object_repr", object_repr, METH_O},
{"object_ascii", object_ascii, METH_O},
@@ -567,6 +580,7 @@ static PyMethodDef test_methods[] = {
{"sequence_index", sequence_index, METH_VARARGS},
{"sequence_list", sequence_list, METH_O},
{"sequence_tuple", sequence_tuple, METH_O},
+ {"sequence_fast", sequence_fast, METH_VARARGS},
{NULL},
};
_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: [email protected]