Skip to content
This repository was archived by the owner on Apr 10, 2022. It is now read-only.

Commit 46a0584

Browse files
authored
fleshed out use cases (#17)
* fleshed out use cases * Update except_star.md * added mention of asyncio.gather()
1 parent 34ffa5d commit 46a0584

File tree

1 file changed

+56
-13
lines changed

1 file changed

+56
-13
lines changed

except_star.md

Lines changed: 56 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -14,20 +14,63 @@ group of unrelated exceptions being propagated together.
1414
## Motivation
1515

1616
The interpreter is currently able to propagate at most one exception at a
17-
time. The chaining features introduced in PEP3134 [reference] link together
18-
exceptions that are related to each other as the cause or context, but there
19-
are situations where there are multiple unrelated exceptions that need to be
20-
propagated together as the stack unwinds. Several real world use cases are
21-
listed below.
17+
time. The chaining features introduced in
18+
[PEP 3134](https://www.python.org/dev/peps/pep-3134/) link together exceptions that are
19+
related to each other as the cause or context, but there are situations where
20+
multiple unrelated exceptions need to be propagated together as the stack
21+
unwinds. Several real world use cases are listed below.
22+
23+
* **Concurrent errors**. Libraries for async concurrency provide APIs to invoke
24+
multiple tasks and return their results in aggregate. There isn't currently
25+
a good way for such libraries to handle situations where multiple tasks
26+
raise exceptions. The Python standard library's
27+
[`asyncio.gather()`](https://docs.python.org/3/library/asyncio-task.html#asyncio.gather)
28+
function provides two options: raise the first exception, or return the
29+
exceptions in the results list. The [Trio](https://trio.readthedocs.io/en/stable/)
30+
library has a `MultiError` exception type which it raises to report a
31+
collection of errors. Work on this PEP was initially motivated by the
32+
difficulties in handling `MultiError`s, which are detailed in a design
33+
document for an
34+
[improved version, `MultiError2`]([https://github.com/python-trio/trio/issues/611).
35+
That document demonstrates how difficult it is to create an effective API
36+
for reporting and handling multiple errors without the language changes we
37+
are proposing.
38+
39+
* **Multiple failures when retrying an operation.** The Python standard library's
40+
`socket.create_connection` may attempt to connect to different addresses,
41+
and if all attempts fail it needs to report that to the user. It is an open
42+
issue how to aggregate these errors, particularly when they are different
43+
[[Python issue 29980](https://bugs.python.org/issue29980)].
44+
45+
* **Multiple user callbacks fail.** The pytest library allows users to register
46+
finalizers which are executed at teardown. If more than one of these
47+
finalizers raises an exception, only the first is reported to the user. This
48+
can be improved with `ExceptionGroup`s, as explained in this issue by pytest
49+
developer Ran Benita [[Pytest issue 8217](https://github.com/pytest-dev/pytest/issues/8217)]
50+
51+
* **Multiple errors in a complex calculation.** The Hypothesis library performs
52+
automatic bug reduction (simplifying code that demonstrates a bug). In the
53+
process it may find variations that generate different errors, and
54+
(optionally) reports all of them
55+
[[Hypothesis documentation](https://hypothesis.readthedocs.io/en/latest/settings.html#hypothesis.settings.report_multiple_bugs)].
56+
An `ExceptionGroup` mechanism as we are proposing here can resolve some of
57+
the difficulties with debugging that are mentioned in the link above, and
58+
which are due to the loss of context/cause information (communicated
59+
by Hypothesis Core Developer Zac Hatfield-Dodds).
60+
61+
* **Errors in wrapper code.** The Python standard library's
62+
`tempfile.TemporaryDirectory` context manager
63+
had an issue where an exception raised during cleanup in `__exit__`
64+
effectively masked an exception that the user's code raised inside the context
65+
manager scope. While the user's exception was chained as the context of the
66+
cleanup error, it was not caught by the user's except clause
67+
[[Python issue 40857](https://bugs.python.org/issue40857)].
68+
The issue was resolved by making the cleanup code ignore errors, thus
69+
sidestepping the multiple exception problem. With the features we propose
70+
here, it would be possible for `__exit__` to raise an `ExceptionGroup`
71+
containing its own errors as well as the user's errors as unrelated errors,
72+
and this would allow the user to catch their own exceptions by their types.
2273

23-
[TODO: flesh these out]
24-
* asyncio programs, trio, etc
25-
26-
* Multiple errors from separate retries of an operation [https://bugs.python.org/issue29980]
27-
28-
* Situations where multiple unrelated exceptions may be of interest to calling code [https://bugs.python.org/issue40857]
29-
30-
* Multiple teardowns in pytest raising exceptions [https://github.com/pytest-dev/pytest/issues/8217]
3174

3275
## Rationale
3376

0 commit comments

Comments
 (0)