From aa289a59ff6398110e1122877c073c9354ee53db Mon Sep 17 00:00:00 2001 From: INADA Naoki Date: Tue, 14 Mar 2017 18:00:59 +0900 Subject: bpo-29548: Recommend PyObject_Call APIs over PyEval_Call APIs. (GH-75) PyEval_Call* APIs are not documented and they doesn't respect PY_SSIZE_T_CLEAN. So add comment block which recommends PyObject_Call* APIs to ceval.h. This commit also changes PyEval_CallMethod and PyEval_CallFunction implementation same to PyObject_CallMethod and PyObject_CallFunction to reduce future maintenance cost. Optimization to avoid temporary tuple are copied too. PyEval_CallFunction(callable, "i", (int)i) now calls callable(i) instead of raising TypeError. But accepting this edge case is backward compatible. --- Include/ceval.h | 6 ++++++ Objects/call.c | 57 ++++++++++++++++++++++++--------------------------------- 2 files changed, 30 insertions(+), 33 deletions(-) diff --git a/Include/ceval.h b/Include/ceval.h index e4be595..8760fe5 100644 --- a/Include/ceval.h +++ b/Include/ceval.h @@ -7,6 +7,12 @@ extern "C" { /* Interface to random parts in ceval.c */ +/* PyEval_CallObjectWithKeywords(), PyEval_CallObject(), PyEval_CallFunction + * and PyEval_CallMethod are kept for backward compatibility: PyObject_Call(), + * PyObject_CallFunction() and PyObject_CallMethod() are recommended to call + * a callable object. + */ + PyAPI_FUNC(PyObject *) PyEval_CallObjectWithKeywords( PyObject *callable, PyObject *args, diff --git a/Objects/call.c b/Objects/call.c index a4af816..f1b1408 100644 --- a/Objects/call.c +++ b/Objects/call.c @@ -940,25 +940,20 @@ PyObject_CallFunction(PyObject *callable, const char *format, ...) } +/* PyEval_CallFunction is exact copy of PyObject_CallFunction. + * This function is kept for backward compatibility. + */ PyObject * PyEval_CallFunction(PyObject *callable, const char *format, ...) { - va_list vargs; - PyObject *args; - PyObject *res; - - va_start(vargs, format); - - args = Py_VaBuildValue(format, vargs); - va_end(vargs); - - if (args == NULL) - return NULL; + va_list va; + PyObject *result; - res = PyEval_CallObject(callable, args); - Py_DECREF(args); + va_start(va, format); + result = _PyObject_CallFunctionVa(callable, format, va, 0); + va_end(va); - return res; + return result; } @@ -1015,33 +1010,29 @@ PyObject_CallMethod(PyObject *obj, const char *name, const char *format, ...) } +/* PyEval_CallMethod is exact copy of PyObject_CallMethod. + * This function is kept for backward compatibility. + */ PyObject * PyEval_CallMethod(PyObject *obj, const char *name, const char *format, ...) { - va_list vargs; - PyObject *meth; - PyObject *args; - PyObject *res; - - meth = PyObject_GetAttrString(obj, name); - if (meth == NULL) - return NULL; - - va_start(vargs, format); + va_list va; + PyObject *callable, *retval; - args = Py_VaBuildValue(format, vargs); - va_end(vargs); + if (obj == NULL || name == NULL) { + return null_error(); + } - if (args == NULL) { - Py_DECREF(meth); + callable = PyObject_GetAttrString(obj, name); + if (callable == NULL) return NULL; - } - res = PyEval_CallObject(meth, args); - Py_DECREF(meth); - Py_DECREF(args); + va_start(va, format); + retval = callmethod(callable, format, va, 0); + va_end(va); - return res; + Py_DECREF(callable); + return retval; } -- cgit v0.12