PEP 678: `del err.__notes__`, and why we're not just using a list (#2360)
Co-authored-by: CAM Gerlach <CAM.Gerlach@Gerlach.CAM>
This commit is contained in:
parent
e846b706bb
commit
7d3a7b9ebe
68
pep-0678.rst
68
pep-0678.rst
|
@ -17,7 +17,7 @@ Abstract
|
|||
Exception objects are typically initialized with a message that describes the
|
||||
error which has occurred. Because further information may be available when
|
||||
the exception is caught and re-raised, or included in an ``ExceptionGroup``,
|
||||
this PEP proposes to add ``BaseException.add_note(note, *, replace=False)``, a
|
||||
this PEP proposes to add ``BaseException.add_note(note)``, a
|
||||
``.__notes__`` attribute holding a tuple of zero or more notes so added, and to
|
||||
update the builtin traceback formatting code to include notes in the formatted
|
||||
traceback following the exception string.
|
||||
|
@ -50,8 +50,8 @@ exceptions. This is already error-prone, and made more difficult by :pep:`654`
|
|||
``ExceptionGroup``\ s, so the time is right for a built-in solution. We
|
||||
therefore propose to add:
|
||||
|
||||
- a new method ``BaseException.add_note(note, *, replace=False)``,
|
||||
- ``BaseException.__notes__``, a read-only field which is a tuple of zero or
|
||||
- a new method ``BaseException.add_note(note)``,
|
||||
- ``BaseException.__notes__``, a read-only attribute which is a tuple of zero or
|
||||
more note strings, and
|
||||
- support in the builtin traceback formatting code such that notes are
|
||||
displayed in the formatted traceback following the exception string.
|
||||
|
@ -141,12 +141,15 @@ Specification
|
|||
=============
|
||||
|
||||
``BaseException`` gains a new read-only attribute ``__notes__``, an initially
|
||||
empty tuple, and a new method ``.add_note(note: str | None, *, replace:
|
||||
bool=False)``. If ``note`` is not ``None``, it is added to the exception's
|
||||
notes which appear in the standard traceback after the exception string. If
|
||||
``replace`` is true, all previously existing notes are removed before the new
|
||||
one is added. To clear all notes, use ``add_note(None, replace=True)``. A
|
||||
``TypeError`` is raised if ``note`` is neither a string nor ``None``.
|
||||
empty tuple, and a new method ``.add_note(note: str)``. ``note`` is added to
|
||||
the exception's notes, which appear in the standard traceback after the
|
||||
exception string. A ``TypeError`` is raised if ``note`` is not a string.
|
||||
|
||||
``del err.__notes__`` clears the contents of the ``__notes__`` attribute,
|
||||
leaving it an empty tuple as if ``.add_note()`` had never been called. This
|
||||
allows libraries full control over the attached notes, by re-adding whatever
|
||||
they wish, without overly complicating the API or adding multiple names to
|
||||
``BaseException.__dict__``.
|
||||
|
||||
When an exception is displayed by the interpreter's builtin traceback-rendering code,
|
||||
its notes (if there are any) appear immediately after the exception message, in the order
|
||||
|
@ -261,8 +264,8 @@ exception chaining, and are unnecessary with ``BaseException.add_note()``:
|
|||
chaining rather than** ``__notes__``.
|
||||
|
||||
|
||||
A mutable ``__note__`` attribute
|
||||
--------------------------------
|
||||
An assignable ``__note__`` attribute
|
||||
------------------------------------
|
||||
The first draft and implementation of this PEP defined a single attribute
|
||||
``__note__``, which defaulted to ``None`` but could have a string assigned.
|
||||
This is substantially simpler if, and only if, there is at most one note.
|
||||
|
@ -272,6 +275,37 @@ libraries such as ``friendly-traceback``, without resorting to dubious parsing
|
|||
heuristics, we therefore settled on the ``.add_note()``-and-``__notes__`` API.
|
||||
|
||||
|
||||
Allow any object, and convert to string for display
|
||||
---------------------------------------------------
|
||||
We have not identified any scenario where libraries would want to do anything
|
||||
but either concatenate or replace notes, and so the additional complexity and
|
||||
interoperability challenges do not seem justified.
|
||||
|
||||
We also note that converting an object to a string may raise an exception.
|
||||
It's more helpful for the traceback to point to the location where the note is
|
||||
attached to the exception, rather than where the exception and note are being
|
||||
formatted for display after propagation.
|
||||
|
||||
|
||||
Just make ``__notes__`` mutable
|
||||
-------------------------------
|
||||
If ``__notes__`` was mutable (e.g. a list) or even assignable, there would be
|
||||
no need for explicit methods to add and remove notes separate from e.g.
|
||||
``ex.__notes__.append(note)`` or ``ex.__notes__.clear()``. While we like the
|
||||
simplicity of this approach, it cannot guarantee that ``__notes__`` is a
|
||||
sequence of strings, and thus risks failing at traceback-display time like
|
||||
the proposal above.
|
||||
|
||||
|
||||
Separate methods for e.g. ``.clear_notes()``
|
||||
--------------------------------------------
|
||||
We expect that clearing or replacing notes will be extremely rare, so while
|
||||
we wish to make this *possible*, we do not consider these APIs worth the cost.
|
||||
The ``del err.__notes__`` pattern has precedent in e.g. invalidation of an
|
||||
``@functools.cached_property``, or any other descriptor with a deleter, and
|
||||
is sufficient for library code to implement whatever pattern is desired.
|
||||
|
||||
|
||||
Subclass Exception and add note support downstream
|
||||
--------------------------------------------------
|
||||
Traceback printing is built into the C code, and reimplemented in pure Python
|
||||
|
@ -305,18 +339,6 @@ which we believe should be deferred to a future version, when we have more
|
|||
experience with the uses (and perhaps misuses) of ``__notes__``.
|
||||
|
||||
|
||||
Allow any object, and convert to string for display
|
||||
---------------------------------------------------
|
||||
We have not identified any scenario where libraries would want to do anything
|
||||
but either concatenate or replace notes, and so the additional complexity and
|
||||
interoperability challenges do not seem justified.
|
||||
|
||||
We also note that converting an object to a string may raise an exception.
|
||||
It's more helpful for the traceback to point to the location where the note is
|
||||
attached to the exception, rather than where the exception and note are being
|
||||
formatted for display after propagation.
|
||||
|
||||
|
||||
Add a helper function ``contextlib.add_exc_note()``
|
||||
---------------------------------------------------
|
||||
It `was suggested
|
||||
|
|
Loading…
Reference in New Issue