diff --git a/Doc/data/stable_abi.dat b/Doc/data/stable_abi.dat index 17b291fd4d0fa4..84523525e2631e 100644 --- a/Doc/data/stable_abi.dat +++ b/Doc/data/stable_abi.dat @@ -43,7 +43,6 @@ function,PyBytes_Size,3.2,, var,PyBytes_Type,3.2,, type,PyCFunction,3.2,, type,PyCFunctionWithKeywords,3.2,, -function,PyCFunction_Call,3.2,, function,PyCFunction_GetFlags,3.2,, function,PyCFunction_GetFunction,3.2,, function,PyCFunction_GetSelf,3.2,, diff --git a/Doc/whatsnew/3.13.rst b/Doc/whatsnew/3.13.rst index cdc48a547ce267..1f1172493cb232 100644 --- a/Doc/whatsnew/3.13.rst +++ b/Doc/whatsnew/3.13.rst @@ -373,6 +373,7 @@ Removed :c:func:`PyTuple_New(0) `. * ``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`.) diff --git a/Include/methodobject.h b/Include/methodobject.h index 72af5ad933df7f..2381e8482b82a8 100644 --- a/Include/methodobject.h +++ b/Include/methodobject.h @@ -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 */ diff --git a/Lib/test/test_call.py b/Lib/test/test_call.py index 12759c53bb662c..5410131a7dfd89 100644 --- a/Lib/test/test_call.py +++ b/Lib/test/test_call.py @@ -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): @@ -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() diff --git a/Misc/NEWS.d/next/C API/2023-05-30-19-11-09.gh-issue-105107.YQwMnm.rst b/Misc/NEWS.d/next/C API/2023-05-30-19-11-09.gh-issue-105107.YQwMnm.rst index 8423f4742ce2e9..6cc758cb83962b 100644 --- a/Misc/NEWS.d/next/C API/2023-05-30-19-11-09.gh-issue-105107.YQwMnm.rst +++ b/Misc/NEWS.d/next/C API/2023-05-30-19-11-09.gh-issue-105107.YQwMnm.rst @@ -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. diff --git a/Misc/stable_abi.toml b/Misc/stable_abi.toml index 7ff4da9a1f7b6a..fac59c97f4bf9f 100644 --- a/Misc/stable_abi.toml +++ b/Misc/stable_abi.toml @@ -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] diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index 86b6dc3b36fe7d..d7c89f48f792ed 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -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) { @@ -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}, diff --git a/Objects/call.c b/Objects/call.c index 4658cf1f56bb7d..40eccefb4a6c8d 100644 --- a/Objects/call.c +++ b/Objects/call.c @@ -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); }