Skip to content

Commit

Permalink
pythongh-111138: Add PyList_Extend() and PyList_Clear() functions
Browse files Browse the repository at this point in the history
* Split list_extend() into two sub-functions: list_extend_fast() and
  list_extend_iter().
* list_inplace_concat() no longer has to call Py_DECREF() on the
  list_extend() result, since list_extend() now returns an int.
  • Loading branch information
vstinner committed Nov 9, 2023
1 parent b9f814c commit 218fe30
Show file tree
Hide file tree
Showing 8 changed files with 262 additions and 118 deletions.
22 changes: 22 additions & 0 deletions Doc/c-api/list.rst
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,17 @@ List Objects
``len(list)`` on a list object.
.. c:function:: int PyList_Clear(PyObject *list)
Remove all items from *list*. Similar to:
``PyList_SetSlice(L, 0, PY_SSIZE_T_MAX, NULL)``.
Raise an exception and return ``-1`` if *list* is not a :class:`list`
object. Return 0 on success.
.. versionadded:: 3.13
.. c:function:: Py_ssize_t PyList_GET_SIZE(PyObject *list)
Similar to :c:func:`PyList_Size`, but without error checking.
Expand Down Expand Up @@ -112,6 +123,17 @@ List Objects
to ``list.append(item)``.
.. c:function:: int PyList_Extend(PyObject *self, PyObject *iterable)
Extend *list* with the contents of *iterable*. Similar to:
``PyList_SetSlice(L, PY_SSIZE_T_MAX, PY_SSIZE_T_MAX, iterable)``.
Raise an exception and return ``-1`` if *list* is not a :class:`list`
object. Return 0 on success.
.. versionadded:: 3.13
.. c:function:: PyObject* PyList_GetSlice(PyObject *list, Py_ssize_t low, Py_ssize_t high)
Return a list of the objects in *list* containing the objects *between* *low*
Expand Down
4 changes: 4 additions & 0 deletions Doc/whatsnew/3.13.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1164,6 +1164,10 @@ New Features
:c:func:`PyErr_WriteUnraisable`, but allow to customize the warning mesage.
(Contributed by Serhiy Storchaka in :gh:`108082`.)

* Add :c:func:`PyList_Extend` and :c:func:`PyList_Clear` functions: similar to
Python ``list.extend()`` and ``list.clear()`` methods.
(Contributed by Victor Stinner in :gh:`111138`.)


Porting to Python 3.13
----------------------
Expand Down
2 changes: 2 additions & 0 deletions Include/listobject.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ PyAPI_FUNC(int) PyList_Append(PyObject *, PyObject *);

PyAPI_FUNC(PyObject *) PyList_GetSlice(PyObject *, Py_ssize_t, Py_ssize_t);
PyAPI_FUNC(int) PyList_SetSlice(PyObject *, Py_ssize_t, Py_ssize_t, PyObject *);
PyAPI_FUNC(int) PyList_Extend(PyObject *self, PyObject *iterable);
PyAPI_FUNC(int) PyList_Clear(PyObject *self);

PyAPI_FUNC(int) PyList_Sort(PyObject *);
PyAPI_FUNC(int) PyList_Reverse(PyObject *);
Expand Down
36 changes: 36 additions & 0 deletions Lib/test/test_capi/test_list.py
Original file line number Diff line number Diff line change
Expand Up @@ -275,3 +275,39 @@ def test_list_astuple(self):
self.assertRaises(SystemError, astuple, ())
self.assertRaises(SystemError, astuple, object())
self.assertRaises(SystemError, astuple, NULL)

def test_list_clear(self):
# Test PyList_Clear()
list_clear = _testcapi.list_clear

lst = [1, 2, 3]
self.assertEqual(list_clear(lst), 0)
self.assertEqual(lst, [])

lst = []
self.assertEqual(list_clear(lst), 0)
self.assertEqual(lst, [])

self.assertRaises(TypeError, list_clear, ())
self.assertRaises(TypeError, list_clear, object())

# CRASHES list_clear(NULL)

def test_list_extend(self):
# Test PyList_Extend()
list_extend = _testcapi.list_extend

lst = [1]
arg = [2, 3]
self.assertEqual(list_extend(lst, arg), 0)
self.assertEqual(lst, [1, 2, 3])

lst = []
arg = (2, 3)
self.assertEqual(list_extend(lst, arg), 0)
self.assertEqual(lst, [2, 3])

self.assertRaises(TypeError, list_extend, [], object())

# CRASHES list_extend(NULL, [])
# CRASHES list_extend([], NULL)
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Add :c:func:`PyList_Extend` and :c:func:`PyList_Clear` functions: similar to
Python ``list.extend()`` and ``list.clear()`` methods. Patch by Victor Stinner.
21 changes: 21 additions & 0 deletions Modules/_testcapi/list.c
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,25 @@ list_astuple(PyObject* Py_UNUSED(module), PyObject *obj)
}


static PyObject *
list_clear(PyObject* Py_UNUSED(module), PyObject *obj)
{
NULLABLE(obj);
RETURN_INT(PyList_Clear(obj));
}


static PyObject *
list_extend(PyObject* Py_UNUSED(module), PyObject *args)
{
PyObject *obj, *arg;
if (!PyArg_ParseTuple(args, "OO", &obj, &arg)) {
return NULL;
}
NULLABLE(obj);
NULLABLE(arg);
RETURN_INT(PyList_Extend(obj, arg));
}


static PyMethodDef test_methods[] = {
Expand All @@ -181,6 +200,8 @@ static PyMethodDef test_methods[] = {
{"list_sort", list_sort, METH_O},
{"list_reverse", list_reverse, METH_O},
{"list_astuple", list_astuple, METH_O},
{"list_clear", list_clear, METH_O},
{"list_extend", list_extend, METH_VARARGS},
{NULL},
};

Expand Down
20 changes: 10 additions & 10 deletions Objects/clinic/listobject.c.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 218fe30

Please sign in to comment.