diff --git a/Doc/c-api/exceptions.rst b/Doc/c-api/exceptions.rst index b0b1e43b05a..98bb152764d 100644 --- a/Doc/c-api/exceptions.rst +++ b/Doc/c-api/exceptions.rst @@ -197,6 +197,14 @@ in various ways. There is a separate error indicator for each thread. string. +.. c:function:: PyObject* PyErr_FormatV(PyObject *exception, const char *format, va_list vargs) + + Same as :c:func:`PyErr_Format`, but taking a `va_list` argument rather + than a variable number of arguments. + + .. versionadded:: 3.5 + + .. c:function:: void PyErr_SetNone(PyObject *type) This is a shorthand for ``PyErr_SetObject(type, Py_None)``. diff --git a/Doc/data/refcounts.dat b/Doc/data/refcounts.dat index 6025617a1be..d1c24e5fcac 100644 --- a/Doc/data/refcounts.dat +++ b/Doc/data/refcounts.dat @@ -349,6 +349,11 @@ PyErr_Format:PyObject*:exception:+1: PyErr_Format:const char*:format:: PyErr_Format::...:: +PyErr_FormatV:PyObject*::null: +PyErr_FormatV:PyObject*:exception:+1: +PyErr_FormatV:const char*:format:: +PyErr_FormatV:va_list:vargs:: + PyErr_WarnEx:int::: PyErr_WarnEx:PyObject*:category:0: PyErr_WarnEx:const char*:message:: diff --git a/Include/pyerrors.h b/Include/pyerrors.h index e44fb5f0ebf..24bc2b7a8d5 100644 --- a/Include/pyerrors.h +++ b/Include/pyerrors.h @@ -242,6 +242,12 @@ PyAPI_FUNC(PyObject *) PyErr_Format( const char *format, /* ASCII-encoded string */ ... ); +#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03050000 +PyAPI_FUNC(PyObject *) PyErr_FormatV( + PyObject *exception, + const char *format, + va_list vargs); +#endif #ifdef MS_WINDOWS PyAPI_FUNC(PyObject *) PyErr_SetFromWindowsErrWithFilename( diff --git a/Misc/NEWS b/Misc/NEWS index 3a5e635326b..12d34ef7e5b 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Release date: TBA Core and Builtins ----------------- +- Issue #18711: Add a new `PyErr_FormatV` function, similar to `PyErr_Format` + but accepting a `va_list` argument. + - Issue #22520: Fix overflow checking when generating the repr of a unicode object. diff --git a/PC/python3.def b/PC/python3.def index fad6448928f..5257d5e48e3 100644 --- a/PC/python3.def +++ b/PC/python3.def @@ -120,6 +120,7 @@ EXPORTS PyErr_ExceptionMatches=python35.PyErr_ExceptionMatches PyErr_Fetch=python35.PyErr_Fetch PyErr_Format=python35.PyErr_Format + PyErr_FormatV=python35.PyErr_FormatV PyErr_GivenExceptionMatches=python35.PyErr_GivenExceptionMatches PyErr_NewException=python35.PyErr_NewException PyErr_NewExceptionWithDoc=python35.PyErr_NewExceptionWithDoc diff --git a/PC/python35stub.def b/PC/python35stub.def index 8736ffb1fa4..6501da0adb9 100644 --- a/PC/python35stub.def +++ b/PC/python35stub.def @@ -119,6 +119,7 @@ PyErr_Display PyErr_ExceptionMatches PyErr_Fetch PyErr_Format +PyErr_FormatV PyErr_GivenExceptionMatches PyErr_NewException PyErr_NewExceptionWithDoc diff --git a/Python/errors.c b/Python/errors.c index 996292a0447..fd551425250 100644 --- a/Python/errors.c +++ b/Python/errors.c @@ -749,19 +749,11 @@ PyErr_BadInternalCall(void) #define PyErr_BadInternalCall() _PyErr_BadInternalCall(__FILE__, __LINE__) - PyObject * -PyErr_Format(PyObject *exception, const char *format, ...) +PyErr_FormatV(PyObject *exception, const char *format, va_list vargs) { - va_list vargs; PyObject* string; -#ifdef HAVE_STDARG_PROTOTYPES - va_start(vargs, format); -#else - va_start(vargs); -#endif - #ifdef Py_DEBUG /* in debug mode, PyEval_EvalFrameEx() fails with an assertion error if an exception is set when it is called */ @@ -771,11 +763,24 @@ PyErr_Format(PyObject *exception, const char *format, ...) string = PyUnicode_FromFormatV(format, vargs); PyErr_SetObject(exception, string); Py_XDECREF(string); - va_end(vargs); return NULL; } +PyObject * +PyErr_Format(PyObject *exception, const char *format, ...) +{ + va_list vargs; +#ifdef HAVE_STDARG_PROTOTYPES + va_start(vargs, format); +#else + va_start(vargs); +#endif + PyErr_FormatV(exception, format, vargs); + va_end(vargs); + return NULL; +} + PyObject * PyErr_NewException(const char *name, PyObject *base, PyObject *dict)