From 9023e576b75ac630835d9140f2a2b60ec2e00c04 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Mon, 22 Aug 2016 23:59:08 +0200 Subject: Add _PyErr_CreateException() Issue #27809: Helper function optimized to create an exception: use fastcall whenever possible. --- Python/errors.c | 59 ++++++++++++++++++++++++++++----------------------------- 1 file changed, 29 insertions(+), 30 deletions(-) (limited to 'Python/errors.c') diff --git a/Python/errors.c b/Python/errors.c index e151cab17c..956e4fa583 100644 --- a/Python/errors.c +++ b/Python/errors.c @@ -52,6 +52,20 @@ PyErr_Restore(PyObject *type, PyObject *value, PyObject *traceback) Py_XDECREF(oldtraceback); } +static PyObject* +_PyErr_CreateException(PyObject *exception, PyObject *value) +{ + if (value == NULL || value == Py_None) { + return _PyObject_CallNoArg(exception); + } + else if (PyTuple_Check(value)) { + return PyObject_Call(exception, value, NULL); + } + else { + return _PyObject_CallArg1(exception, value); + } +} + void PyErr_SetObject(PyObject *exception, PyObject *value) { @@ -66,6 +80,7 @@ PyErr_SetObject(PyObject *exception, PyObject *value) exception); return; } + Py_XINCREF(value); exc_value = tstate->exc_value; if (exc_value != NULL && exc_value != Py_None) { @@ -73,28 +88,21 @@ PyErr_SetObject(PyObject *exception, PyObject *value) Py_INCREF(exc_value); if (value == NULL || !PyExceptionInstance_Check(value)) { /* We must normalize the value right now */ - PyObject *args, *fixed_value; + PyObject *fixed_value; - /* Issue #23571: PyEval_CallObject() must not be called with an + /* Issue #23571: functions must not be called with an exception set */ PyErr_Clear(); - if (value == NULL || value == Py_None) - args = PyTuple_New(0); - else if (PyTuple_Check(value)) { - Py_INCREF(value); - args = value; - } - else - args = PyTuple_Pack(1, value); - fixed_value = args ? - PyEval_CallObject(exception, args) : NULL; - Py_XDECREF(args); + fixed_value = _PyErr_CreateException(exception, value); Py_XDECREF(value); - if (fixed_value == NULL) + if (fixed_value == NULL) { return; + } + value = fixed_value; } + /* Avoid reference cycles through the context chain. This is O(chain length) but context chains are usually very short. Sensitive readers may try @@ -110,7 +118,8 @@ PyErr_SetObject(PyObject *exception, PyObject *value) o = context; } PyException_SetContext(value, exc_value); - } else { + } + else { Py_DECREF(exc_value); } } @@ -258,25 +267,15 @@ PyErr_NormalizeException(PyObject **exc, PyObject **val, PyObject **tb) class. */ if (!inclass || !is_subclass) { - PyObject *args, *res; + PyObject *fixed_value; - if (value == Py_None) - args = PyTuple_New(0); - else if (PyTuple_Check(value)) { - Py_INCREF(value); - args = value; + fixed_value = _PyErr_CreateException(type, value); + if (fixed_value == NULL) { + goto finally; } - else - args = PyTuple_Pack(1, value); - if (args == NULL) - goto finally; - res = PyEval_CallObject(type, args); - Py_DECREF(args); - if (res == NULL) - goto finally; Py_DECREF(value); - value = res; + value = fixed_value; } /* if the class of the instance doesn't exactly match the class of the type, believe the instance -- cgit v1.2.1 From b35603f9f15c1060eb903181324a26ce20336cc4 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Tue, 23 Aug 2016 00:04:41 +0200 Subject: Issue #27809: PyErr_SetImportError() uses fast call --- Python/errors.c | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) (limited to 'Python/errors.c') diff --git a/Python/errors.c b/Python/errors.c index 956e4fa583..e6285e8b3b 100644 --- a/Python/errors.c +++ b/Python/errors.c @@ -699,18 +699,14 @@ PyObject *PyErr_SetFromWindowsErrWithUnicodeFilename( PyObject * PyErr_SetImportError(PyObject *msg, PyObject *name, PyObject *path) { - PyObject *args, *kwargs, *error; + PyObject *kwargs, *error; - if (msg == NULL) - return NULL; - - args = PyTuple_New(1); - if (args == NULL) + if (msg == NULL) { return NULL; + } kwargs = PyDict_New(); if (kwargs == NULL) { - Py_DECREF(args); return NULL; } @@ -722,22 +718,20 @@ PyErr_SetImportError(PyObject *msg, PyObject *name, PyObject *path) path = Py_None; } - Py_INCREF(msg); - PyTuple_SET_ITEM(args, 0, msg); - - if (PyDict_SetItemString(kwargs, "name", name) < 0) + if (PyDict_SetItemString(kwargs, "name", name) < 0) { goto done; - if (PyDict_SetItemString(kwargs, "path", path) < 0) + } + if (PyDict_SetItemString(kwargs, "path", path) < 0) { goto done; + } - error = PyObject_Call(PyExc_ImportError, args, kwargs); + error = _PyObject_FastCallDict(PyExc_ImportError, &msg, 1, kwargs); if (error != NULL) { PyErr_SetObject((PyObject *)Py_TYPE(error), error); Py_DECREF(error); } done: - Py_DECREF(args); Py_DECREF(kwargs); return NULL; } -- cgit v1.2.1 From 54dc09e399e40109e5b61f0ed2e94558cc07aaa8 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Wed, 7 Sep 2016 16:56:15 -0700 Subject: Issue #15767: Use ModuleNotFoundError. --- Python/errors.c | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) (limited to 'Python/errors.c') diff --git a/Python/errors.c b/Python/errors.c index e6285e8b3b..13ae6b4561 100644 --- a/Python/errors.c +++ b/Python/errors.c @@ -697,27 +697,37 @@ PyObject *PyErr_SetFromWindowsErrWithUnicodeFilename( #endif /* MS_WINDOWS */ PyObject * -PyErr_SetImportError(PyObject *msg, PyObject *name, PyObject *path) +PyErr_SetImportErrorSubclass(PyObject *exception, PyObject *msg, + PyObject *name, PyObject *path) { + int issubclass; PyObject *kwargs, *error; - if (msg == NULL) { + issubclass = PyObject_IsSubclass(exception, PyExc_ImportError); + if (issubclass < 0) { + return NULL; + } + else if (!issubclass) { + PyErr_SetString(PyExc_TypeError, "expected a subclass of ImportError"); return NULL; } - kwargs = PyDict_New(); - if (kwargs == NULL) { + if (msg == NULL) { + PyErr_SetString(PyExc_TypeError, "expected a message argument"); return NULL; } if (name == NULL) { name = Py_None; } - if (path == NULL) { path = Py_None; } + kwargs = PyDict_New(); + if (kwargs == NULL) { + return NULL; + } if (PyDict_SetItemString(kwargs, "name", name) < 0) { goto done; } @@ -725,7 +735,7 @@ PyErr_SetImportError(PyObject *msg, PyObject *name, PyObject *path) goto done; } - error = _PyObject_FastCallDict(PyExc_ImportError, &msg, 1, kwargs); + error = _PyObject_FastCallDict(exception, &msg, 1, kwargs); if (error != NULL) { PyErr_SetObject((PyObject *)Py_TYPE(error), error); Py_DECREF(error); @@ -736,6 +746,12 @@ done: return NULL; } +PyObject * +PyErr_SetImportError(PyObject *msg, PyObject *name, PyObject *path) +{ + return PyErr_SetImportErrorSubclass(PyExc_ImportError, msg, name, path); +} + void _PyErr_BadInternalCall(const char *filename, int lineno) { -- cgit v1.2.1 From 3888fec2a7d9d5688a9ada16652bdbc11449869f Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Fri, 21 Oct 2016 17:09:17 +0300 Subject: Issue #28410: Added _PyErr_FormatFromCause() -- the helper for raising new exception with setting current exception as __cause__. _PyErr_FormatFromCause(exception, format, args...) is equivalent to Python raise exception(format % args) from sys.exc_info()[1] --- Python/errors.c | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) (limited to 'Python/errors.c') diff --git a/Python/errors.c b/Python/errors.c index 12bde287df..918f4dffab 100644 --- a/Python/errors.c +++ b/Python/errors.c @@ -401,6 +401,47 @@ _PyErr_ChainExceptions(PyObject *exc, PyObject *val, PyObject *tb) } } +static PyObject * +_PyErr_FormatVFromCause(PyObject *exception, const char *format, va_list vargs) +{ + PyObject *exc, *val, *val2, *tb; + + assert(PyErr_Occurred()); + PyErr_Fetch(&exc, &val, &tb); + PyErr_NormalizeException(&exc, &val, &tb); + if (tb != NULL) { + PyException_SetTraceback(val, tb); + Py_DECREF(tb); + } + Py_DECREF(exc); + assert(!PyErr_Occurred()); + + PyErr_FormatV(exception, format, vargs); + + PyErr_Fetch(&exc, &val2, &tb); + PyErr_NormalizeException(&exc, &val2, &tb); + Py_INCREF(val); + PyException_SetCause(val2, val); + PyException_SetContext(val2, val); + PyErr_Restore(exc, val2, tb); + + return NULL; +} + +PyObject * +_PyErr_FormatFromCause(PyObject *exception, const char *format, ...) +{ + va_list vargs; +#ifdef HAVE_STDARG_PROTOTYPES + va_start(vargs, format); +#else + va_start(vargs); +#endif + _PyErr_FormatVFromCause(exception, format, vargs); + va_end(vargs); + return NULL; +} + /* Convenience functions to set a type error exception and return 0 */ int -- cgit v1.2.1