Skip to content

Commit

Permalink
pythongh-105107: Remove PyCFunction_Call() function (python#105181)
Browse files Browse the repository at this point in the history
* Keep the function in the stable ABI.
* Add unit tests on PyCFunction_Call() since it remains supported in
  the stable ABI.
  • Loading branch information
vstinner authored Jun 1, 2023
1 parent 7f5afec commit 27f9491
Show file tree
Hide file tree
Showing 8 changed files with 40 additions and 6 deletions.
1 change: 0 additions & 1 deletion Doc/data/stable_abi.dat

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

1 change: 1 addition & 0 deletions Doc/whatsnew/3.13.rst
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,7 @@ Removed
:c:func:`PyTuple_New(0) <PyTuple_New>`.
* ``PyEval_CallFunction()``: use :c:func:`PyObject_CallFunction` instead.
* ``PyEval_CallMethod()``: use :c:func:`PyObject_CallMethod` instead.
* ``PyCFunction_Call()``: use :c:func:`PyObject_Call` instead.

(Contributed by Victor Stinner in :gh:`105107`.)

Expand Down
2 changes: 0 additions & 2 deletions Include/methodobject.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,6 @@ PyAPI_FUNC(PyCFunction) PyCFunction_GetFunction(PyObject *);
PyAPI_FUNC(PyObject *) PyCFunction_GetSelf(PyObject *);
PyAPI_FUNC(int) PyCFunction_GetFlags(PyObject *);

Py_DEPRECATED(3.9) PyAPI_FUNC(PyObject *) PyCFunction_Call(PyObject *, PyObject *, PyObject *);

struct PyMethodDef {
const char *ml_name; /* The name of the built-in function/method */
PyCFunction ml_meth; /* The C function that implements it */
Expand Down
20 changes: 20 additions & 0 deletions Lib/test/test_call.py
Original file line number Diff line number Diff line change
Expand Up @@ -966,6 +966,7 @@ def c_py_recurse(m):
finally:
sys.setrecursionlimit(depth)


class TestFunctionWithManyArgs(unittest.TestCase):
def test_function_with_many_args(self):
for N in (10, 500, 1000):
Expand All @@ -977,5 +978,24 @@ def test_function_with_many_args(self):
self.assertEqual(l['f'](*range(N)), N//2)


@unittest.skipIf(_testcapi is None, 'need _testcapi')
class TestCAPI(unittest.TestCase):
def test_cfunction_call(self):
def func(*args, **kwargs):
return (args, kwargs)

# PyCFunction_Call() was removed in Python 3.13 API, but was kept in
# the stable ABI.
def PyCFunction_Call(func, *args, **kwargs):
if kwargs:
return _testcapi.pycfunction_call(func, args, kwargs)
else:
return _testcapi.pycfunction_call(func, args)

self.assertEqual(PyCFunction_Call(func), ((), {}))
self.assertEqual(PyCFunction_Call(func, 1, 2, 3), ((1, 2, 3), {}))
self.assertEqual(PyCFunction_Call(func, "arg", num=5), (("arg",), {'num': 5}))


if __name__ == "__main__":
unittest.main()
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@ Remove functions deprecated in Python 3.9.
arguments must not be *NULL*) instead.
* ``PyEval_CallFunction()``: use :c:func:`PyObject_CallFunction` instead.
* ``PyEval_CallMethod()``: use :c:func:`PyObject_CallMethod` instead.
* ``PyCFunction_Call()``: use :c:func:`PyObject_Call` instead.

Patch by Victor Stinner.
1 change: 1 addition & 0 deletions Misc/stable_abi.toml
Original file line number Diff line number Diff line change
Expand Up @@ -447,6 +447,7 @@
added = '3.2'
[function.PyCFunction_Call]
added = '3.2'
abi_only = true
[function.PyCFunction_GetFlags]
added = '3.2'
[function.PyCFunction_GetFunction]
Expand Down
14 changes: 14 additions & 0 deletions Modules/_testcapimodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -2362,6 +2362,19 @@ meth_fastcall_keywords(PyObject* self, PyObject* const* args,
return Py_BuildValue("NNN", _null_to_none(self), pyargs, pykwargs);
}

static PyObject*
test_pycfunction_call(PyObject *module, PyObject *args)
{
// Function removed in the Python 3.13 API but was kept in the stable ABI.
extern PyObject* PyCFunction_Call(PyObject *callable, PyObject *args, PyObject *kwargs);

PyObject *func, *pos_args, *kwargs = NULL;
if (!PyArg_ParseTuple(args, "OO!|O!", &func, &PyTuple_Type, &pos_args, &PyDict_Type, &kwargs)) {
return NULL;
}
return PyCFunction_Call(func, pos_args, kwargs);
}

static PyObject*
pynumber_tobase(PyObject *module, PyObject *args)
{
Expand Down Expand Up @@ -3369,6 +3382,7 @@ static PyMethodDef TestMethods[] = {
{"meth_noargs", meth_noargs, METH_NOARGS},
{"meth_fastcall", _PyCFunction_CAST(meth_fastcall), METH_FASTCALL},
{"meth_fastcall_keywords", _PyCFunction_CAST(meth_fastcall_keywords), METH_FASTCALL|METH_KEYWORDS},
{"pycfunction_call", test_pycfunction_call, METH_VARARGS},
{"pynumber_tobase", pynumber_tobase, METH_VARARGS},
{"test_set_type_size", test_set_type_size, METH_NOARGS},
{"test_py_clear", test_py_clear, METH_NOARGS},
Expand Down
6 changes: 3 additions & 3 deletions Objects/call.c
Original file line number Diff line number Diff line change
Expand Up @@ -380,11 +380,11 @@ PyObject_Call(PyObject *callable, PyObject *args, PyObject *kwargs)
}


PyObject *
/* Function removed in the Python 3.13 API but kept in the stable ABI. */
PyAPI_FUNC(PyObject *)
PyCFunction_Call(PyObject *callable, PyObject *args, PyObject *kwargs)
{
PyThreadState *tstate = _PyThreadState_GET();
return _PyObject_Call(tstate, callable, args, kwargs);
return PyObject_Call(callable, args, kwargs);
}


Expand Down

0 comments on commit 27f9491

Please sign in to comment.