Skip to content

Commit 34714f4

Browse files
[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 d05a180) Co-authored-by: Alex Waygood <[email protected]>
1 parent 6601962 commit 34714f4

File tree

6 files changed

+115
-67
lines changed

6 files changed

+115
-67
lines changed

Doc/c-api/exceptions.rst

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -528,7 +528,8 @@ Querying the error indicator
528528
529529
.. note::
530530
531-
This function *does not* implicitly set the ``__traceback__``
531+
This function *does not* implicitly set the
532+
:attr:`~BaseException.__traceback__`
532533
attribute on the exception value. If setting the traceback
533534
appropriately is desired, the following additional snippet is needed::
534535
@@ -740,7 +741,8 @@ Exception Objects
740741
.. c:function:: PyObject* PyException_GetTraceback(PyObject *ex)
741742
742743
Return the traceback associated with the exception as a new reference, as
743-
accessible from Python through :attr:`__traceback__`. If there is no
744+
accessible from Python through the :attr:`~BaseException.__traceback__`
745+
attribute. If there is no
744746
traceback associated, this returns ``NULL``.
745747
746748
@@ -754,8 +756,8 @@ Exception Objects
754756
755757
Return the context (another exception instance during whose handling *ex* was
756758
raised) associated with the exception as a new reference, as accessible from
757-
Python through :attr:`__context__`. If there is no context associated, this
758-
returns ``NULL``.
759+
Python through the :attr:`~BaseException.__context__` attribute.
760+
If there is no context associated, this returns ``NULL``.
759761
760762
761763
.. c:function:: void PyException_SetContext(PyObject *ex, PyObject *ctx)
@@ -769,7 +771,8 @@ Exception Objects
769771
770772
Return the cause (either an exception instance, or ``None``,
771773
set by ``raise ... from ...``) associated with the exception as a new
772-
reference, as accessible from Python through :attr:`__cause__`.
774+
reference, as accessible from Python through the
775+
:attr:`~BaseException.__cause__` attribute.
773776
774777
775778
.. c:function:: void PyException_SetCause(PyObject *ex, PyObject *cause)
@@ -778,7 +781,8 @@ Exception Objects
778781
it. There is no type check to make sure that *cause* is either an exception
779782
instance or ``None``. This steals a reference to *cause*.
780783
781-
:attr:`__suppress_context__` is implicitly set to ``True`` by this function.
784+
The :attr:`~BaseException.__suppress_context__` attribute is implicitly set
785+
to ``True`` by this function.
782786
783787
784788
.. c:function:: PyObject* PyException_GetArgs(PyObject *ex)

Doc/library/exceptions.rst

Lines changed: 59 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -38,36 +38,48 @@ information on defining exceptions is available in the Python Tutorial under
3838
Exception context
3939
-----------------
4040

41-
When raising a new exception while another exception
42-
is already being handled, the new exception's
43-
:attr:`__context__` attribute is automatically set to the handled
44-
exception. An exception may be handled when an :keyword:`except` or
45-
:keyword:`finally` clause, or a :keyword:`with` statement, is used.
46-
47-
This implicit exception context can be
48-
supplemented with an explicit cause by using :keyword:`!from` with
49-
:keyword:`raise`::
50-
51-
raise new_exc from original_exc
52-
53-
The expression following :keyword:`from<raise>` must be an exception or ``None``. It
54-
will be set as :attr:`__cause__` on the raised exception. Setting
55-
:attr:`__cause__` also implicitly sets the :attr:`__suppress_context__`
56-
attribute to ``True``, so that using ``raise new_exc from None``
57-
effectively replaces the old exception with the new one for display
58-
purposes (e.g. converting :exc:`KeyError` to :exc:`AttributeError`), while
59-
leaving the old exception available in :attr:`__context__` for introspection
60-
when debugging.
61-
62-
The default traceback display code shows these chained exceptions in
63-
addition to the traceback for the exception itself. An explicitly chained
64-
exception in :attr:`__cause__` is always shown when present. An implicitly
65-
chained exception in :attr:`__context__` is shown only if :attr:`__cause__`
66-
is :const:`None` and :attr:`__suppress_context__` is false.
67-
68-
In either case, the exception itself is always shown after any chained
69-
exceptions so that the final line of the traceback always shows the last
70-
exception that was raised.
41+
.. index:: pair: exception; chaining
42+
__cause__ (exception attribute)
43+
__context__ (exception attribute)
44+
__suppress_context__ (exception attribute)
45+
46+
Three attributes on exception objects provide information about the context in
47+
which an the exception was raised:
48+
49+
.. attribute:: BaseException.__context__
50+
BaseException.__cause__
51+
BaseException.__suppress_context__
52+
53+
When raising a new exception while another exception
54+
is already being handled, the new exception's
55+
:attr:`!__context__` attribute is automatically set to the handled
56+
exception. An exception may be handled when an :keyword:`except` or
57+
:keyword:`finally` clause, or a :keyword:`with` statement, is used.
58+
59+
This implicit exception context can be
60+
supplemented with an explicit cause by using :keyword:`!from` with
61+
:keyword:`raise`::
62+
63+
raise new_exc from original_exc
64+
65+
The expression following :keyword:`from<raise>` must be an exception or ``None``. It
66+
will be set as :attr:`!__cause__` on the raised exception. Setting
67+
:attr:`!__cause__` also implicitly sets the :attr:`!__suppress_context__`
68+
attribute to ``True``, so that using ``raise new_exc from None``
69+
effectively replaces the old exception with the new one for display
70+
purposes (e.g. converting :exc:`KeyError` to :exc:`AttributeError`), while
71+
leaving the old exception available in :attr:`!__context__` for introspection
72+
when debugging.
73+
74+
The default traceback display code shows these chained exceptions in
75+
addition to the traceback for the exception itself. An explicitly chained
76+
exception in :attr:`!__cause__` is always shown when present. An implicitly
77+
chained exception in :attr:`!__context__` is shown only if :attr:`!__cause__`
78+
is :const:`None` and :attr:`!__suppress_context__` is false.
79+
80+
In either case, the exception itself is always shown after any chained
81+
exceptions so that the final line of the traceback always shows the last
82+
exception that was raised.
7183

7284

7385
Inheriting from built-in exceptions
@@ -126,6 +138,12 @@ The following exceptions are used mostly as base classes for other exceptions.
126138
tb = sys.exception().__traceback__
127139
raise OtherException(...).with_traceback(tb)
128140

141+
.. attribute:: __traceback__
142+
143+
A writable field that holds the
144+
:ref:`traceback object <traceback-objects>` associated with this
145+
exception. See also: :ref:`raise`.
146+
129147
.. method:: add_note(note)
130148

131149
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.
928946
same check that is used in an ``except`` clause.
929947

930948
The nesting structure of the current exception is preserved in the result,
931-
as are the values of its :attr:`message`, :attr:`__traceback__`,
932-
:attr:`__cause__`, :attr:`__context__` and :attr:`__notes__` fields.
949+
as are the values of its :attr:`message`,
950+
:attr:`~BaseException.__traceback__`, :attr:`~BaseException.__cause__`,
951+
:attr:`~BaseException.__context__` and
952+
:attr:`~BaseException.__notes__` fields.
933953
Empty nested groups are omitted from the result.
934954

935955
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.
952972
and :meth:`split` return instances of the subclass rather
953973
than :exc:`ExceptionGroup`.
954974

955-
:meth:`subgroup` and :meth:`split` copy the :attr:`__traceback__`,
956-
:attr:`__cause__`, :attr:`__context__` and :attr:`__notes__` fields from
975+
:meth:`subgroup` and :meth:`split` copy the
976+
:attr:`~BaseException.__traceback__`,
977+
:attr:`~BaseException.__cause__`, :attr:`~BaseException.__context__` and
978+
:attr:`~BaseException.__notes__` fields from
957979
the original exception group to the one returned by :meth:`derive`, so
958-
these fields do not need to be updated by :meth:`derive`. ::
980+
these fields do not need to be updated by :meth:`derive`.
981+
982+
.. doctest::
959983

960984
>>> class MyGroup(ExceptionGroup):
961985
... def derive(self, excs):

Doc/library/traceback.rst

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,8 @@ The module defines the following functions:
6767

6868
The optional *limit* argument has the same meaning as for :func:`print_tb`.
6969
If *chain* is true (the default), then chained exceptions (the
70-
:attr:`__cause__` or :attr:`__context__` attributes of the exception) will be
70+
:attr:`~BaseException.__cause__` or :attr:`~BaseException.__context__`
71+
attributes of the exception) will be
7172
printed as well, like the interpreter itself does when printing an unhandled
7273
exception.
7374

@@ -227,10 +228,11 @@ capture data for later printing in a lightweight fashion.
227228
Capture an exception for later rendering. *limit*, *lookup_lines* and
228229
*capture_locals* are as for the :class:`StackSummary` class.
229230

230-
If *compact* is true, only data that is required by :class:`TracebackException`'s
231-
``format`` method is saved in the class attributes. In particular, the
232-
``__context__`` field is calculated only if ``__cause__`` is ``None`` and
233-
``__suppress_context__`` is false.
231+
If *compact* is true, only data that is required by
232+
:class:`!TracebackException`'s :meth:`format` method
233+
is saved in the class attributes. In particular, the
234+
:attr:`__context__` field is calculated only if :attr:`__cause__` is
235+
``None`` and :attr:`__suppress_context__` is false.
234236

235237
Note that when locals are captured, they are also shown in the traceback.
236238

@@ -248,27 +250,31 @@ capture data for later printing in a lightweight fashion.
248250

249251
.. attribute:: __cause__
250252

251-
A :class:`TracebackException` of the original ``__cause__``.
253+
A :class:`!TracebackException` of the original
254+
:attr:`~BaseException.__cause__`.
252255

253256
.. attribute:: __context__
254257

255-
A :class:`TracebackException` of the original ``__context__``.
258+
A :class:`!TracebackException` of the original
259+
:attr:`~BaseException.__context__`.
256260

257261
.. attribute:: exceptions
258262

259263
If ``self`` represents an :exc:`ExceptionGroup`, this field holds a list of
260-
:class:`TracebackException` instances representing the nested exceptions.
264+
:class:`!TracebackException` instances representing the nested exceptions.
261265
Otherwise it is ``None``.
262266

263267
.. versionadded:: 3.11
264268

265269
.. attribute:: __suppress_context__
266270

267-
The ``__suppress_context__`` value from the original exception.
271+
The :attr:`~BaseException.__suppress_context__` value from the original
272+
exception.
268273

269274
.. attribute:: __notes__
270275

271-
The ``__notes__`` value from the original exception, or ``None``
276+
The :attr:`~BaseException.__notes__` value from the original exception,
277+
or ``None``
272278
if the exception does not have any notes. If it is not ``None``
273279
is it formatted in the traceback after the exception string.
274280

@@ -334,8 +340,8 @@ capture data for later printing in a lightweight fashion.
334340

335341
Format the exception.
336342

337-
If *chain* is not ``True``, ``__cause__`` and ``__context__`` will not
338-
be formatted.
343+
If *chain* is not ``True``, :attr:`__cause__` and :attr:`__context__`
344+
will not be formatted.
339345

340346
The return value is a generator of strings, each ending in a newline and
341347
some containing internal newlines. :func:`~traceback.print_exception`

Doc/reference/datamodel.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1385,7 +1385,8 @@ unwinds the execution stack, at each unwound level a traceback object is
13851385
inserted in front of the current traceback. When an exception handler is
13861386
entered, the stack trace is made available to the program. (See section
13871387
:ref:`try`.) It is accessible as the third item of the
1388-
tuple returned by :func:`sys.exc_info`, and as the ``__traceback__`` attribute
1388+
tuple returned by :func:`sys.exc_info`, and as the
1389+
:attr:`~BaseException.__traceback__` attribute
13891390
of the caught exception.
13901391

13911392
When the program contains no suitable

Doc/reference/simple_stmts.rst

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -578,7 +578,7 @@ The :dfn:`type` of the exception is the exception instance's class, the
578578
.. index:: pair: object; traceback
579579

580580
A traceback object is normally created automatically when an exception is raised
581-
and attached to it as the :attr:`__traceback__` attribute, which is writable.
581+
and attached to it as the :attr:`~BaseException.__traceback__` attribute.
582582
You can create an exception and set your own traceback in one step using the
583583
:meth:`~BaseException.with_traceback` exception method (which returns the
584584
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::
592592
The ``from`` clause is used for exception chaining: if given, the second
593593
*expression* must be another exception class or instance. If the second
594594
expression is an exception instance, it will be attached to the raised
595-
exception as the :attr:`__cause__` attribute (which is writable). If the
595+
exception as the :attr:`~BaseException.__cause__` attribute (which is writable). If the
596596
expression is an exception class, the class will be instantiated and the
597597
resulting exception instance will be attached to the raised exception as the
598-
:attr:`__cause__` attribute. If the raised exception is not handled, both
599-
exceptions will be printed::
598+
:attr:`!__cause__` attribute. If the raised exception is not handled, both
599+
exceptions will be printed:
600+
601+
.. code-block:: pycon
600602
601603
>>> try:
602604
... print(1 / 0)
@@ -605,19 +607,24 @@ exceptions will be printed::
605607
...
606608
Traceback (most recent call last):
607609
File "<stdin>", line 2, in <module>
610+
print(1 / 0)
611+
~~^~~
608612
ZeroDivisionError: division by zero
609613
610614
The above exception was the direct cause of the following exception:
611615
612616
Traceback (most recent call last):
613617
File "<stdin>", line 4, in <module>
618+
raise RuntimeError("Something bad happened") from exc
614619
RuntimeError: Something bad happened
615620
616621
A similar mechanism works implicitly if a new exception is raised when
617622
an exception is already being handled. An exception may be handled
618623
when an :keyword:`except` or :keyword:`finally` clause, or a
619624
:keyword:`with` statement, is used. The previous exception is then
620-
attached as the new exception's :attr:`__context__` attribute::
625+
attached as the new exception's :attr:`~BaseException.__context__` attribute:
626+
627+
.. code-block:: pycon
621628
622629
>>> try:
623630
... print(1 / 0)
@@ -626,16 +633,21 @@ attached as the new exception's :attr:`__context__` attribute::
626633
...
627634
Traceback (most recent call last):
628635
File "<stdin>", line 2, in <module>
636+
print(1 / 0)
637+
~~^~~
629638
ZeroDivisionError: division by zero
630639
631640
During handling of the above exception, another exception occurred:
632641
633642
Traceback (most recent call last):
634643
File "<stdin>", line 4, in <module>
644+
raise RuntimeError("Something bad happened")
635645
RuntimeError: Something bad happened
636646
637647
Exception chaining can be explicitly suppressed by specifying :const:`None` in
638-
the ``from`` clause::
648+
the ``from`` clause:
649+
650+
.. doctest::
639651

640652
>>> try:
641653
... print(1 / 0)
@@ -653,8 +665,8 @@ and information about handling exceptions is in section :ref:`try`.
653665
:const:`None` is now permitted as ``Y`` in ``raise X from Y``.
654666

655667
.. versionadded:: 3.3
656-
The ``__suppress_context__`` attribute to suppress automatic display of the
657-
exception context.
668+
The :attr:`~BaseException.__suppress_context__` attribute to suppress
669+
automatic display of the exception context.
658670

659671
.. versionchanged:: 3.11
660672
If the traceback of the active exception is modified in an :keyword:`except`

Doc/whatsnew/3.0.rst

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -711,7 +711,7 @@ new powerful features added:
711711
{Exception}({args})` instead of :samp:`raise {Exception}, {args}`.
712712
Additionally, you can no longer explicitly specify a traceback;
713713
instead, if you *have* to do this, you can assign directly to the
714-
:attr:`__traceback__` attribute (see below).
714+
:attr:`~BaseException.__traceback__` attribute (see below).
715715

716716
* :pep:`3110`: Catching exceptions. You must now use
717717
:samp:`except {SomeException} as {variable}` instead
@@ -725,22 +725,23 @@ new powerful features added:
725725
handler block. This usually happens due to a bug in the handler
726726
block; we call this a *secondary* exception. In this case, the
727727
original exception (that was being handled) is saved as the
728-
:attr:`__context__` attribute of the secondary exception.
728+
:attr:`~BaseException.__context__` attribute of the secondary exception.
729729
Explicit chaining is invoked with this syntax::
730730

731731
raise SecondaryException() from primary_exception
732732

733733
(where *primary_exception* is any expression that produces an
734734
exception object, probably an exception that was previously caught).
735735
In this case, the primary exception is stored on the
736-
:attr:`__cause__` attribute of the secondary exception. The
736+
:attr:`~BaseException.__cause__` attribute of the secondary exception. The
737737
traceback printed when an unhandled exception occurs walks the chain
738-
of :attr:`__cause__` and :attr:`__context__` attributes and prints a
738+
of :attr:`!__cause__` and :attr:`~BaseException.__context__` attributes and
739+
prints a
739740
separate traceback for each component of the chain, with the primary
740741
exception at the top. (Java users may recognize this behavior.)
741742

742743
* :pep:`3134`: Exception objects now store their traceback as the
743-
:attr:`__traceback__` attribute. This means that an exception
744+
:attr:`~BaseException.__traceback__` attribute. This means that an exception
744745
object now contains all the information pertaining to an exception,
745746
and there are fewer reasons to use :func:`sys.exc_info` (though the
746747
latter is not removed).

0 commit comments

Comments
 (0)