mirror of
https://github.com/python/cpython.git
synced 2025-12-31 04:23:37 +00:00
gh-130947: Add again PySequence_Fast() to the limited C API (#130948)
Add again PySequence_Fast() to the limited C API. Add unit tests.
This commit is contained in:
parent
3a189af4b2
commit
10cbd1fe88
9 changed files with 90 additions and 13 deletions
1
Doc/data/stable_abi.dat
generated
1
Doc/data/stable_abi.dat
generated
|
|
@ -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,,
|
||||
|
|
|
|||
|
|
@ -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`.)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
||||
|
|
|
|||
|
|
@ -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) \
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -0,0 +1,2 @@
|
|||
Add again :c:func:`PySequence_Fast` to the limited C API.
|
||||
Patch by Victor Stinner.
|
||||
|
|
@ -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]
|
||||
|
|
|
|||
|
|
@ -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},
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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},
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue