Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
added sys.exception()
  • Loading branch information
iritkatriel committed Jan 10, 2022
commit 3a125051cf0c739912ae38de74db40b48511ded9
45 changes: 30 additions & 15 deletions Doc/library/sys.rst
Original file line number Diff line number Diff line change
Expand Up @@ -378,26 +378,41 @@ always available.
.. versionadded:: 3.8
__unraisablehook__


.. function:: exception()

This function returns the exception that is currently being handled. This
Comment thread
tiran marked this conversation as resolved.
Outdated
exception is specific both to the current thread and to the current stack
frame. If the current stack frame is not handling an exception, the
exception is taken from the calling stack frame, or its caller, and so on
until a stack frame is found that is handling an 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

If no exception is being handled anywhere on the stack, ``None`` is
returned.

.. versionadded: 3.11


.. function:: exc_info()

This function returns a tuple of three values that give information about the
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
frame is not handling an exception, the information is taken from the calling
stack frame, or its caller, and so on until a stack frame is found that is
handling an exception. Here, "handling an exception" is defined as "executing
an except clause." For any stack frame, only information about the exception
being currently handled is accessible.
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, a tuple containing
three ``None`` values is returned. Otherwise, the values returned are
``(type, value, traceback)``. Their meaning is: *type* gets the type of the
exception being handled (a subclass of :exc:`BaseException`); *value* gets
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.
If no exception is being handled anywhere on the stack, this function
return a tuple containing three ``None`` values.

.. versionchanged:: 3.11
The ``type`` and ``traceback`` fields are now derived from the ``value``
Expand Down
2 changes: 1 addition & 1 deletion Doc/tutorial/errors.rst
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ then re-raise the exception (allowing a caller to handle the exception as well):
raise

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
clause*, which, when present, must follow all *except clauses*. It is useful
Expand Down
20 changes: 20 additions & 0 deletions Lib/test/test_sys.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,26 @@ def baddisplayhook(obj):
code = compile("42", "<string>", "single")
self.assertRaises(ValueError, eval, code)

class ExcInfoTest(unittest.TestCase):
def test_exc_info_no_exception(self):
self.assertEqual(sys.exc_info(), (None, None, None))
self.assertEqual(sys.exception(), None)

def test_exc_info_with_exception(self):
def f():
raise ValueError(42)
Comment thread
iritkatriel marked this conversation as resolved.

try:
f()
except Exception as e_:
e = e_
exc_info = sys.exc_info()
exc = sys.exception()

self.assertIs(exc, e)
self.assertIs(exc_info[0], type(e))
self.assertIs(exc_info[1], e)
self.assertIs(exc_info[2], e.__traceback__)

class ExceptHookTest(unittest.TestCase):

Expand Down
24 changes: 23 additions & 1 deletion Python/clinic/sysmodule.c.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

24 changes: 24 additions & 0 deletions Python/sysmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -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]
sys.exc_info

Expand Down Expand Up @@ -1963,6 +1985,7 @@ static PyMethodDef sys_methods[] = {
SYS__CURRENT_FRAMES_METHODDEF
SYS__CURRENT_EXCEPTIONS_METHODDEF
SYS_DISPLAYHOOK_METHODDEF
SYS_EXCEPTION_METHODDEF
SYS_EXC_INFO_METHODDEF
SYS_EXCEPTHOOK_METHODDEF
SYS_EXIT_METHODDEF
Expand Down Expand Up @@ -2457,6 +2480,7 @@ Functions:\n\
\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\
exception() -- return the current exception (thread safe)\n\
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is this "(thread safe)" note? It's not mentioned anywhere else.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The next line for exc_info mentions it's thread-safe, so I didn't want it to look like this isn't. But maybe I should remove it from both lines?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My concern is more that it's only in help(sys), but nowhere else. If it's thread safe and this information matters, it should be in the documentation as well. Maybe also in the function docstring.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don’t know if it matters. This info is thread specific anyway, so you would assume this is thread safe (this is mentioned in the doc).

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are the other functions in sys, like getrefcount, not thread safe?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it could be that the intention in the help line for exc_info was to say that it’s a thread-specific value, but it was worded incorrectly. I’d change both to say this instead of thread-safe.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Most functions implemented in C are thread-safe. I agree, remove the mention from both functions.

The exact behavior can be elaborated in the documentation, if needed.

Yeah, the current exception is per-thread.

exc_info() -- return thread-safe information about the current exception\n\
exit() -- exit the interpreter by raising SystemExit\n\
getdlopenflags() -- returns flags to be used for dlopen() calls\n\
Expand Down