Skip to content

Commit

Permalink
[3.12] gh-103791: handle BaseExceptionGroup in `contextlib.suppress…
Browse files Browse the repository at this point in the history
…()` (GH-111910) (#111955)

gh-103791: handle `BaseExceptionGroup` in `contextlib.suppress()` (GH-111910)
(cherry picked from commit d61313b)

Co-authored-by: Zac Hatfield-Dodds <zac.hatfield.dodds@gmail.com>
  • Loading branch information
miss-islington and Zac-HD authored Nov 10, 2023
1 parent 4b0c875 commit 3780414
Show file tree
Hide file tree
Showing 4 changed files with 25 additions and 4 deletions.
6 changes: 3 additions & 3 deletions Doc/library/contextlib.rst
Original file line number Diff line number Diff line change
Expand Up @@ -304,15 +304,15 @@ Functions and classes provided:

This context manager is :ref:`reentrant <reentrant-cms>`.

If the code within the :keyword:`!with` block raises an
:exc:`ExceptionGroup`, suppressed exceptions are removed from the
If the code within the :keyword:`!with` block raises a
:exc:`BaseExceptionGroup`, suppressed exceptions are removed from the
group. If any exceptions in the group are not suppressed, a group containing them is re-raised.

.. versionadded:: 3.4

.. versionchanged:: 3.12
``suppress`` now supports suppressing exceptions raised as
part of an :exc:`ExceptionGroup`.
part of an :exc:`BaseExceptionGroup`.

.. function:: redirect_stdout(new_target)

Expand Down
2 changes: 1 addition & 1 deletion Lib/contextlib.py
Original file line number Diff line number Diff line change
Expand Up @@ -457,7 +457,7 @@ def __exit__(self, exctype, excinst, exctb):
return
if issubclass(exctype, self._exceptions):
return True
if issubclass(exctype, ExceptionGroup):
if issubclass(exctype, BaseExceptionGroup):
match, rest = excinst.split(self._exceptions)
if rest is None:
return True
Expand Down
18 changes: 18 additions & 0 deletions Lib/test/test_contextlib.py
Original file line number Diff line number Diff line change
Expand Up @@ -1287,6 +1287,24 @@ def test_exception_groups(self):
[KeyError("ke1"), KeyError("ke2")],
),
)
# Check handling of BaseExceptionGroup, using GeneratorExit so that
# we don't accidentally discard a ctrl-c with KeyboardInterrupt.
with suppress(GeneratorExit):
raise BaseExceptionGroup("message", [GeneratorExit()])
# If we raise a BaseException group, we can still suppress parts
with self.assertRaises(BaseExceptionGroup) as eg1:
with suppress(KeyError):
raise BaseExceptionGroup("message", [GeneratorExit("g"), KeyError("k")])
self.assertExceptionIsLike(
eg1.exception, BaseExceptionGroup("message", [GeneratorExit("g")]),
)
# If we suppress all the leaf BaseExceptions, we get a non-base ExceptionGroup
with self.assertRaises(ExceptionGroup) as eg1:
with suppress(GeneratorExit):
raise BaseExceptionGroup("message", [GeneratorExit("g"), KeyError("k")])
self.assertExceptionIsLike(
eg1.exception, ExceptionGroup("message", [KeyError("k")]),
)


class TestChdir(unittest.TestCase):
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
:class:`contextlib.suppress` now supports suppressing exceptions raised as
part of a :exc:`BaseExceptionGroup`, in addition to the recent support for
:exc:`ExceptionGroup`.

0 comments on commit 3780414

Please sign in to comment.