From d90864e06afefd1dc10fe9f3ba7a1d8e9f821505 Mon Sep 17 00:00:00 2001 From: Zac Hatfield-Dodds Date: Wed, 8 Nov 2023 23:56:38 -0800 Subject: [PATCH 1/2] handle BaseExceptionGroup in contextlib.suppress() --- Doc/library/contextlib.rst | 8 ++++++-- Lib/contextlib.py | 2 +- Lib/test/test_contextlib.py | 4 ++++ .../2023-11-09-10-45-56.gh-issue-103791.sdfkja.rst | 3 +++ 4 files changed, 14 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-11-09-10-45-56.gh-issue-103791.sdfkja.rst diff --git a/Doc/library/contextlib.rst b/Doc/library/contextlib.rst index 66b9c137105223..0590642182ae66 100644 --- a/Doc/library/contextlib.rst +++ b/Doc/library/contextlib.rst @@ -304,8 +304,8 @@ Functions and classes provided: This context manager is :ref:`reentrant `. - 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 @@ -314,6 +314,10 @@ Functions and classes provided: ``suppress`` now supports suppressing exceptions raised as part of an :exc:`ExceptionGroup`. + .. versionchanged:: 3.12.1 + ``suppress`` now supports suppressing exceptions raised as + part of an :exc:`BaseExceptionGroup`. + .. function:: redirect_stdout(new_target) Context manager for temporarily redirecting :data:`sys.stdout` to diff --git a/Lib/contextlib.py b/Lib/contextlib.py index 6994690ebf7eb2..5b646fabca0225 100644 --- a/Lib/contextlib.py +++ b/Lib/contextlib.py @@ -461,7 +461,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 diff --git a/Lib/test/test_contextlib.py b/Lib/test/test_contextlib.py index e32a091fdd1c92..33ff7f125ae863 100644 --- a/Lib/test/test_contextlib.py +++ b/Lib/test/test_contextlib.py @@ -1297,6 +1297,10 @@ 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()]) class TestChdir(unittest.TestCase): diff --git a/Misc/NEWS.d/next/Library/2023-11-09-10-45-56.gh-issue-103791.sdfkja.rst b/Misc/NEWS.d/next/Library/2023-11-09-10-45-56.gh-issue-103791.sdfkja.rst new file mode 100644 index 00000000000000..5bfdd75ccc93e8 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-11-09-10-45-56.gh-issue-103791.sdfkja.rst @@ -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`. From b8bc1367a06bd5f350f406283c874cb4b252c0a7 Mon Sep 17 00:00:00 2001 From: Zac Hatfield-Dodds Date: Thu, 9 Nov 2023 20:39:58 -0800 Subject: [PATCH 2/2] address review comments --- Doc/library/contextlib.rst | 4 ---- Lib/test/test_contextlib.py | 14 ++++++++++++++ 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/Doc/library/contextlib.rst b/Doc/library/contextlib.rst index 0590642182ae66..f6ebbfacfba509 100644 --- a/Doc/library/contextlib.rst +++ b/Doc/library/contextlib.rst @@ -311,10 +311,6 @@ Functions and classes provided: .. versionadded:: 3.4 .. versionchanged:: 3.12 - ``suppress`` now supports suppressing exceptions raised as - part of an :exc:`ExceptionGroup`. - - .. versionchanged:: 3.12.1 ``suppress`` now supports suppressing exceptions raised as part of an :exc:`BaseExceptionGroup`. diff --git a/Lib/test/test_contextlib.py b/Lib/test/test_contextlib.py index 33ff7f125ae863..36c3abca80f894 100644 --- a/Lib/test/test_contextlib.py +++ b/Lib/test/test_contextlib.py @@ -1301,6 +1301,20 @@ def test_exception_groups(self): # 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):