[3.12] gh-101100: Improve docs on exception attributes (GH-113057) (#113061)

gh-101100: Improve docs on exception attributes (GH-113057)

(cherry picked from commit d05a180350)

Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
This commit is contained in:
Miss Islington (bot) 2023-12-13 20:07:19 +01:00 committed by GitHub
parent 6601962530
commit 34714f4ac9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 110 additions and 62 deletions

View file

@ -528,7 +528,8 @@ Querying the error indicator
.. note::
This function *does not* implicitly set the ``__traceback__``
This function *does not* implicitly set the
:attr:`~BaseException.__traceback__`
attribute on the exception value. If setting the traceback
appropriately is desired, the following additional snippet is needed::
@ -740,7 +741,8 @@ Exception Objects
.. c:function:: PyObject* PyException_GetTraceback(PyObject *ex)
Return the traceback associated with the exception as a new reference, as
accessible from Python through :attr:`__traceback__`. If there is no
accessible from Python through the :attr:`~BaseException.__traceback__`
attribute. If there is no
traceback associated, this returns ``NULL``.
@ -754,8 +756,8 @@ Exception Objects
Return the context (another exception instance during whose handling *ex* was
raised) associated with the exception as a new reference, as accessible from
Python through :attr:`__context__`. If there is no context associated, this
returns ``NULL``.
Python through the :attr:`~BaseException.__context__` attribute.
If there is no context associated, this returns ``NULL``.
.. c:function:: void PyException_SetContext(PyObject *ex, PyObject *ctx)
@ -769,7 +771,8 @@ Exception Objects
Return the cause (either an exception instance, or ``None``,
set by ``raise ... from ...``) associated with the exception as a new
reference, as accessible from Python through :attr:`__cause__`.
reference, as accessible from Python through the
:attr:`~BaseException.__cause__` attribute.
.. c:function:: void PyException_SetCause(PyObject *ex, PyObject *cause)
@ -778,7 +781,8 @@ Exception Objects
it. There is no type check to make sure that *cause* is either an exception
instance or ``None``. This steals a reference to *cause*.
:attr:`__suppress_context__` is implicitly set to ``True`` by this function.
The :attr:`~BaseException.__suppress_context__` attribute is implicitly set
to ``True`` by this function.
.. c:function:: PyObject* PyException_GetArgs(PyObject *ex)

View file

@ -38,9 +38,21 @@ information on defining exceptions is available in the Python Tutorial under
Exception context
-----------------
.. index:: pair: exception; chaining
__cause__ (exception attribute)
__context__ (exception attribute)
__suppress_context__ (exception attribute)
Three attributes on exception objects provide information about the context in
which an the exception was raised:
.. attribute:: BaseException.__context__
BaseException.__cause__
BaseException.__suppress_context__
When raising a new exception while another exception
is already being handled, the new exception's
:attr:`__context__` attribute is automatically set to the handled
:attr:`!__context__` attribute is automatically set to the handled
exception. An exception may be handled when an :keyword:`except` or
:keyword:`finally` clause, or a :keyword:`with` statement, is used.
@ -51,19 +63,19 @@ supplemented with an explicit cause by using :keyword:`!from` with
raise new_exc from original_exc
The expression following :keyword:`from<raise>` must be an exception or ``None``. It
will be set as :attr:`__cause__` on the raised exception. Setting
:attr:`__cause__` also implicitly sets the :attr:`__suppress_context__`
will be set as :attr:`!__cause__` on the raised exception. Setting
:attr:`!__cause__` also implicitly sets the :attr:`!__suppress_context__`
attribute to ``True``, so that using ``raise new_exc from None``
effectively replaces the old exception with the new one for display
purposes (e.g. converting :exc:`KeyError` to :exc:`AttributeError`), while
leaving the old exception available in :attr:`__context__` for introspection
leaving the old exception available in :attr:`!__context__` for introspection
when debugging.
The default traceback display code shows these chained exceptions in
addition to the traceback for the exception itself. An explicitly chained
exception in :attr:`__cause__` is always shown when present. An implicitly
chained exception in :attr:`__context__` is shown only if :attr:`__cause__`
is :const:`None` and :attr:`__suppress_context__` is false.
exception in :attr:`!__cause__` is always shown when present. An implicitly
chained exception in :attr:`!__context__` is shown only if :attr:`!__cause__`
is :const:`None` and :attr:`!__suppress_context__` is false.
In either case, the exception itself is always shown after any chained
exceptions so that the final line of the traceback always shows the last
@ -126,6 +138,12 @@ The following exceptions are used mostly as base classes for other exceptions.
tb = sys.exception().__traceback__
raise OtherException(...).with_traceback(tb)
.. attribute:: __traceback__
A writable field that holds the
:ref:`traceback object <traceback-objects>` associated with this
exception. See also: :ref:`raise`.
.. method:: add_note(note)
Add the string ``note`` to the exception's notes which appear in the standard
@ -928,8 +946,10 @@ their subgroups based on the types of the contained exceptions.
same check that is used in an ``except`` clause.
The nesting structure of the current exception is preserved in the result,
as are the values of its :attr:`message`, :attr:`__traceback__`,
:attr:`__cause__`, :attr:`__context__` and :attr:`__notes__` fields.
as are the values of its :attr:`message`,
:attr:`~BaseException.__traceback__`, :attr:`~BaseException.__cause__`,
:attr:`~BaseException.__context__` and
:attr:`~BaseException.__notes__` fields.
Empty nested groups are omitted from the result.
The condition is checked for all exceptions in the nested exception group,
@ -952,10 +972,14 @@ their subgroups based on the types of the contained exceptions.
and :meth:`split` return instances of the subclass rather
than :exc:`ExceptionGroup`.
:meth:`subgroup` and :meth:`split` copy the :attr:`__traceback__`,
:attr:`__cause__`, :attr:`__context__` and :attr:`__notes__` fields from
:meth:`subgroup` and :meth:`split` copy the
:attr:`~BaseException.__traceback__`,
:attr:`~BaseException.__cause__`, :attr:`~BaseException.__context__` and
:attr:`~BaseException.__notes__` fields from
the original exception group to the one returned by :meth:`derive`, so
these fields do not need to be updated by :meth:`derive`. ::
these fields do not need to be updated by :meth:`derive`.
.. doctest::
>>> class MyGroup(ExceptionGroup):
... def derive(self, excs):

View file

@ -67,7 +67,8 @@ The module defines the following functions:
The optional *limit* argument has the same meaning as for :func:`print_tb`.
If *chain* is true (the default), then chained exceptions (the
:attr:`__cause__` or :attr:`__context__` attributes of the exception) will be
:attr:`~BaseException.__cause__` or :attr:`~BaseException.__context__`
attributes of the exception) will be
printed as well, like the interpreter itself does when printing an unhandled
exception.
@ -227,10 +228,11 @@ capture data for later printing in a lightweight fashion.
Capture an exception for later rendering. *limit*, *lookup_lines* and
*capture_locals* are as for the :class:`StackSummary` class.
If *compact* is true, only data that is required by :class:`TracebackException`'s
``format`` method is saved in the class attributes. In particular, the
``__context__`` field is calculated only if ``__cause__`` is ``None`` and
``__suppress_context__`` is false.
If *compact* is true, only data that is required by
:class:`!TracebackException`'s :meth:`format` method
is saved in the class attributes. In particular, the
:attr:`__context__` field is calculated only if :attr:`__cause__` is
``None`` and :attr:`__suppress_context__` is false.
Note that when locals are captured, they are also shown in the traceback.
@ -248,27 +250,31 @@ capture data for later printing in a lightweight fashion.
.. attribute:: __cause__
A :class:`TracebackException` of the original ``__cause__``.
A :class:`!TracebackException` of the original
:attr:`~BaseException.__cause__`.
.. attribute:: __context__
A :class:`TracebackException` of the original ``__context__``.
A :class:`!TracebackException` of the original
:attr:`~BaseException.__context__`.
.. attribute:: exceptions
If ``self`` represents an :exc:`ExceptionGroup`, this field holds a list of
:class:`TracebackException` instances representing the nested exceptions.
:class:`!TracebackException` instances representing the nested exceptions.
Otherwise it is ``None``.
.. versionadded:: 3.11
.. attribute:: __suppress_context__
The ``__suppress_context__`` value from the original exception.
The :attr:`~BaseException.__suppress_context__` value from the original
exception.
.. attribute:: __notes__
The ``__notes__`` value from the original exception, or ``None``
The :attr:`~BaseException.__notes__` value from the original exception,
or ``None``
if the exception does not have any notes. If it is not ``None``
is it formatted in the traceback after the exception string.
@ -334,8 +340,8 @@ capture data for later printing in a lightweight fashion.
Format the exception.
If *chain* is not ``True``, ``__cause__`` and ``__context__`` will not
be formatted.
If *chain* is not ``True``, :attr:`__cause__` and :attr:`__context__`
will not be formatted.
The return value is a generator of strings, each ending in a newline and
some containing internal newlines. :func:`~traceback.print_exception`

View file

@ -1385,7 +1385,8 @@ unwinds the execution stack, at each unwound level a traceback object is
inserted in front of the current traceback. When an exception handler is
entered, the stack trace is made available to the program. (See section
:ref:`try`.) It is accessible as the third item of the
tuple returned by :func:`sys.exc_info`, and as the ``__traceback__`` attribute
tuple returned by :func:`sys.exc_info`, and as the
:attr:`~BaseException.__traceback__` attribute
of the caught exception.
When the program contains no suitable

View file

@ -578,7 +578,7 @@ The :dfn:`type` of the exception is the exception instance's class, the
.. index:: pair: object; traceback
A traceback object is normally created automatically when an exception is raised
and attached to it as the :attr:`__traceback__` attribute, which is writable.
and attached to it as the :attr:`~BaseException.__traceback__` attribute.
You can create an exception and set your own traceback in one step using the
:meth:`~BaseException.with_traceback` exception method (which returns the
same exception instance, with its traceback set to its argument), like so::
@ -592,11 +592,13 @@ same exception instance, with its traceback set to its argument), like so::
The ``from`` clause is used for exception chaining: if given, the second
*expression* must be another exception class or instance. If the second
expression is an exception instance, it will be attached to the raised
exception as the :attr:`__cause__` attribute (which is writable). If the
exception as the :attr:`~BaseException.__cause__` attribute (which is writable). If the
expression is an exception class, the class will be instantiated and the
resulting exception instance will be attached to the raised exception as the
:attr:`__cause__` attribute. If the raised exception is not handled, both
exceptions will be printed::
:attr:`!__cause__` attribute. If the raised exception is not handled, both
exceptions will be printed:
.. code-block:: pycon
>>> try:
... print(1 / 0)
@ -605,19 +607,24 @@ exceptions will be printed::
...
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
print(1 / 0)
~~^~~
ZeroDivisionError: division by zero
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "<stdin>", line 4, in <module>
raise RuntimeError("Something bad happened") from exc
RuntimeError: Something bad happened
A similar mechanism works implicitly if a new exception is raised when
an exception is already being handled. An exception may be handled
when an :keyword:`except` or :keyword:`finally` clause, or a
:keyword:`with` statement, is used. The previous exception is then
attached as the new exception's :attr:`__context__` attribute::
attached as the new exception's :attr:`~BaseException.__context__` attribute:
.. code-block:: pycon
>>> try:
... print(1 / 0)
@ -626,16 +633,21 @@ attached as the new exception's :attr:`__context__` attribute::
...
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
print(1 / 0)
~~^~~
ZeroDivisionError: division by zero
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "<stdin>", line 4, in <module>
raise RuntimeError("Something bad happened")
RuntimeError: Something bad happened
Exception chaining can be explicitly suppressed by specifying :const:`None` in
the ``from`` clause::
the ``from`` clause:
.. doctest::
>>> try:
... print(1 / 0)
@ -653,8 +665,8 @@ and information about handling exceptions is in section :ref:`try`.
:const:`None` is now permitted as ``Y`` in ``raise X from Y``.
.. versionadded:: 3.3
The ``__suppress_context__`` attribute to suppress automatic display of the
exception context.
The :attr:`~BaseException.__suppress_context__` attribute to suppress
automatic display of the exception context.
.. versionchanged:: 3.11
If the traceback of the active exception is modified in an :keyword:`except`

View file

@ -711,7 +711,7 @@ new powerful features added:
{Exception}({args})` instead of :samp:`raise {Exception}, {args}`.
Additionally, you can no longer explicitly specify a traceback;
instead, if you *have* to do this, you can assign directly to the
:attr:`__traceback__` attribute (see below).
:attr:`~BaseException.__traceback__` attribute (see below).
* :pep:`3110`: Catching exceptions. You must now use
:samp:`except {SomeException} as {variable}` instead
@ -725,7 +725,7 @@ new powerful features added:
handler block. This usually happens due to a bug in the handler
block; we call this a *secondary* exception. In this case, the
original exception (that was being handled) is saved as the
:attr:`__context__` attribute of the secondary exception.
:attr:`~BaseException.__context__` attribute of the secondary exception.
Explicit chaining is invoked with this syntax::
raise SecondaryException() from primary_exception
@ -733,14 +733,15 @@ new powerful features added:
(where *primary_exception* is any expression that produces an
exception object, probably an exception that was previously caught).
In this case, the primary exception is stored on the
:attr:`__cause__` attribute of the secondary exception. The
:attr:`~BaseException.__cause__` attribute of the secondary exception. The
traceback printed when an unhandled exception occurs walks the chain
of :attr:`__cause__` and :attr:`__context__` attributes and prints a
of :attr:`!__cause__` and :attr:`~BaseException.__context__` attributes and
prints a
separate traceback for each component of the chain, with the primary
exception at the top. (Java users may recognize this behavior.)
* :pep:`3134`: Exception objects now store their traceback as the
:attr:`__traceback__` attribute. This means that an exception
:attr:`~BaseException.__traceback__` attribute. This means that an exception
object now contains all the information pertaining to an exception,
and there are fewer reasons to use :func:`sys.exc_info` (though the
latter is not removed).