Add again PySequence_Fast() to the limited C API.
Add unit tests.
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,,
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`.)
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.
#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) \
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
--- /dev/null
+Add again :c:func:`PySequence_Fast` to the limited C API.
+Patch by Victor Stinner.
added = '3.2'
[function.PySequence_Fast]
added = '3.2'
- abi_only = true
[function.PySequence_GetItem]
added = '3.2'
[function.PySequence_GetSlice]
}
+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},
{"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},
};
}
+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},
{"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},
};