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.
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 @@
/* 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 @@
}
+/* 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_list va;
+ PyObject *result;
- va_start(vargs, format);
+ va_start(va, format);
+ result = _PyObject_CallFunctionVa(callable, format, va, 0);
+ va_end(va);
- args = Py_VaBuildValue(format, vargs);
- va_end(vargs);
-
- if (args == NULL)
- return NULL;
-
- res = PyEval_CallObject(callable, args);
- Py_DECREF(args);
-
- return res;
+ return result;
}
@@ -1015,33 +1010,29 @@
}
+/* 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;
+ va_list va;
+ PyObject *callable, *retval;
- meth = PyObject_GetAttrString(obj, name);
- if (meth == NULL)
- return NULL;
-
- va_start(vargs, format);
-
- args = Py_VaBuildValue(format, vargs);
- va_end(vargs);
-
- if (args == NULL) {
- Py_DECREF(meth);
- return NULL;
+ if (obj == NULL || name == NULL) {
+ return null_error();
}
- res = PyEval_CallObject(meth, args);
- Py_DECREF(meth);
- Py_DECREF(args);
+ callable = PyObject_GetAttrString(obj, name);
+ if (callable == NULL)
+ return NULL;
- return res;
+ va_start(va, format);
+ retval = callmethod(callable, format, va, 0);
+ va_end(va);
+
+ Py_DECREF(callable);
+ return retval;
}