bpo-46328: Add sys.exception() (GH-30514)

This commit is contained in:
Irit Katriel 2022-01-13 12:35:58 +00:00 committed by GitHub
parent 9c2ebb906d
commit c590b581bb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 147 additions and 19 deletions

View File

@ -378,26 +378,41 @@ always available.
.. versionadded:: 3.8 .. versionadded:: 3.8
__unraisablehook__ __unraisablehook__
.. function:: exc_info()
This function returns a tuple of three values that give information about the .. function:: exception()
exception that is currently being handled. The information returned is specific
both to the current thread and to the current stack frame. If the current stack This function returns the exception instance that is currently being
frame is not handling an exception, the information is taken from the calling handled. This exception is specific both to the current thread and
stack frame, or its caller, and so on until a stack frame is found that is to the current stack frame. If the current stack frame is not handling
handling an exception. Here, "handling an exception" is defined as "executing an exception, the exception is taken from the calling stack frame, or its
an except clause." For any stack frame, only information about the exception caller, and so on until a stack frame is found that is handling an
being currently handled is accessible. exception. Here, "handling an exception" is defined as "executing an
except clause." For any stack frame, only the exception being currently
handled is accessible.
.. index:: object: traceback .. index:: object: traceback
If no exception is being handled anywhere on the stack, a tuple containing If no exception is being handled anywhere on the stack, ``None`` is
three ``None`` values is returned. Otherwise, the values returned are returned.
``(type, value, traceback)``. Their meaning is: *type* gets the type of the
exception being handled (a subclass of :exc:`BaseException`); *value* gets .. versionadded:: 3.11
the exception instance (an instance of the exception type); *traceback* gets
a :ref:`traceback object <traceback-objects>` which typically encapsulates
the call stack at the point where the exception last occurred. .. function:: exc_info()
This function returns the old-style representation of the handled
exception. If an exception ``e`` is currently handled (so
:func:`exception` would return ``e``), :func:`exc_info` returns the
tuple ``(type(e), e, e.__traceback__)``.
That is, a tuple containing the type of the exception (a subclass of
:exc:`BaseException`), the exception itself, and a :ref:`traceback
object <traceback-objects>` which typically encapsulates the call
stack at the point where the exception last occurred.
.. index:: object: traceback
If no exception is being handled anywhere on the stack, this function
return a tuple containing three ``None`` values.
.. versionchanged:: 3.11 .. versionchanged:: 3.11
The ``type`` and ``traceback`` fields are now derived from the ``value`` The ``type`` and ``traceback`` fields are now derived from the ``value``

View File

@ -167,7 +167,7 @@ then re-raise the exception (allowing a caller to handle the exception as well):
raise raise
Alternatively the last except clause may omit the exception name(s), however the exception Alternatively the last except clause may omit the exception name(s), however the exception
value must then be retrieved from ``sys.exc_info()[1]``. value must then be retrieved with ``sys.exception()``.
The :keyword:`try` ... :keyword:`except` statement has an optional *else The :keyword:`try` ... :keyword:`except` statement has an optional *else
clause*, which, when present, must follow all *except clauses*. It is useful clause*, which, when present, must follow all *except clauses*. It is useful

View File

@ -305,6 +305,9 @@ sys
the results of subsequent calls to :func:`exc_info`. the results of subsequent calls to :func:`exc_info`.
(Contributed by Irit Katriel in :issue:`45711`.) (Contributed by Irit Katriel in :issue:`45711`.)
* Add :func:`sys.exception` which returns the active exception instance
(equivalent to ``sys.exc_info()[1]``).
(Contributed by Irit Katriel in :issue:`46328`.)
threading threading
--------- ---------

View File

@ -71,6 +71,69 @@ class DisplayHookTest(unittest.TestCase):
code = compile("42", "<string>", "single") code = compile("42", "<string>", "single")
self.assertRaises(ValueError, eval, code) self.assertRaises(ValueError, eval, code)
class ActiveExceptionTests(unittest.TestCase):
def test_exc_info_no_exception(self):
self.assertEqual(sys.exc_info(), (None, None, None))
def test_sys_exception_no_exception(self):
self.assertEqual(sys.exception(), None)
def test_exc_info_with_exception_instance(self):
def f():
raise ValueError(42)
try:
f()
except Exception as e_:
e = e_
exc_info = sys.exc_info()
self.assertIsInstance(e, ValueError)
self.assertIs(exc_info[0], ValueError)
self.assertIs(exc_info[1], e)
self.assertIs(exc_info[2], e.__traceback__)
def test_exc_info_with_exception_type(self):
def f():
raise ValueError
try:
f()
except Exception as e_:
e = e_
exc_info = sys.exc_info()
self.assertIsInstance(e, ValueError)
self.assertIs(exc_info[0], ValueError)
self.assertIs(exc_info[1], e)
self.assertIs(exc_info[2], e.__traceback__)
def test_sys_exception_with_exception_instance(self):
def f():
raise ValueError(42)
try:
f()
except Exception as e_:
e = e_
exc = sys.exception()
self.assertIsInstance(e, ValueError)
self.assertIs(exc, e)
def test_sys_exception_with_exception_type(self):
def f():
raise ValueError
try:
f()
except Exception as e_:
e = e_
exc = sys.exception()
self.assertIsInstance(e, ValueError)
self.assertIs(exc, e)
class ExceptHookTest(unittest.TestCase): class ExceptHookTest(unittest.TestCase):

View File

@ -0,0 +1 @@
Added the :meth:`sys.exception` method which returns the active exception instance.

View File

@ -76,6 +76,28 @@ exit:
return return_value; return return_value;
} }
PyDoc_STRVAR(sys_exception__doc__,
"exception($module, /)\n"
"--\n"
"\n"
"Return the current exception.\n"
"\n"
"Return the most recent exception caught by an except clause\n"
"in the current stack frame or in an older stack frame, or None\n"
"if no such exception exists.");
#define SYS_EXCEPTION_METHODDEF \
{"exception", (PyCFunction)sys_exception, METH_NOARGS, sys_exception__doc__},
static PyObject *
sys_exception_impl(PyObject *module);
static PyObject *
sys_exception(PyObject *module, PyObject *Py_UNUSED(ignored))
{
return sys_exception_impl(module);
}
PyDoc_STRVAR(sys_exc_info__doc__, PyDoc_STRVAR(sys_exc_info__doc__,
"exc_info($module, /)\n" "exc_info($module, /)\n"
"--\n" "--\n"
@ -992,4 +1014,4 @@ sys_getandroidapilevel(PyObject *module, PyObject *Py_UNUSED(ignored))
#ifndef SYS_GETANDROIDAPILEVEL_METHODDEF #ifndef SYS_GETANDROIDAPILEVEL_METHODDEF
#define SYS_GETANDROIDAPILEVEL_METHODDEF #define SYS_GETANDROIDAPILEVEL_METHODDEF
#endif /* !defined(SYS_GETANDROIDAPILEVEL_METHODDEF) */ #endif /* !defined(SYS_GETANDROIDAPILEVEL_METHODDEF) */
/*[clinic end generated code: output=855fc93b2347710b input=a9049054013a1b77]*/ /*[clinic end generated code: output=60756bc6f683e0c8 input=a9049054013a1b77]*/

View File

@ -771,6 +771,28 @@ sys_excepthook_impl(PyObject *module, PyObject *exctype, PyObject *value,
} }
/*[clinic input]
sys.exception
Return the current exception.
Return the most recent exception caught by an except clause
in the current stack frame or in an older stack frame, or None
if no such exception exists.
[clinic start generated code]*/
static PyObject *
sys_exception_impl(PyObject *module)
/*[clinic end generated code: output=2381ee2f25953e40 input=c88fbb94b6287431]*/
{
_PyErr_StackItem *err_info = _PyErr_GetTopmostException(_PyThreadState_GET());
if (err_info->exc_value != NULL) {
return Py_NewRef(err_info->exc_value);
}
Py_RETURN_NONE;
}
/*[clinic input] /*[clinic input]
sys.exc_info sys.exc_info
@ -1963,6 +1985,7 @@ static PyMethodDef sys_methods[] = {
SYS__CURRENT_FRAMES_METHODDEF SYS__CURRENT_FRAMES_METHODDEF
SYS__CURRENT_EXCEPTIONS_METHODDEF SYS__CURRENT_EXCEPTIONS_METHODDEF
SYS_DISPLAYHOOK_METHODDEF SYS_DISPLAYHOOK_METHODDEF
SYS_EXCEPTION_METHODDEF
SYS_EXC_INFO_METHODDEF SYS_EXC_INFO_METHODDEF
SYS_EXCEPTHOOK_METHODDEF SYS_EXCEPTHOOK_METHODDEF
SYS_EXIT_METHODDEF SYS_EXIT_METHODDEF
@ -2457,7 +2480,8 @@ Functions:\n\
\n\ \n\
displayhook() -- print an object to the screen, and save it in builtins._\n\ displayhook() -- print an object to the screen, and save it in builtins._\n\
excepthook() -- print an exception and its traceback to sys.stderr\n\ excepthook() -- print an exception and its traceback to sys.stderr\n\
exc_info() -- return thread-safe information about the current exception\n\ exception() -- return the current thread's active exception\n\
exc_info() -- return information about the current thread's active exception\n\
exit() -- exit the interpreter by raising SystemExit\n\ exit() -- exit the interpreter by raising SystemExit\n\
getdlopenflags() -- returns flags to be used for dlopen() calls\n\ getdlopenflags() -- returns flags to be used for dlopen() calls\n\
getprofile() -- get the global profiling function\n\ getprofile() -- get the global profiling function\n\