]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-103791: handle `BaseExceptionGroup` in `contextlib.suppress()` (#111910)
authorZac Hatfield-Dodds <zac.hatfield.dodds@gmail.com>
Fri, 10 Nov 2023 13:32:36 +0000 (08:32 -0500)
committerGitHub <noreply@github.com>
Fri, 10 Nov 2023 13:32:36 +0000 (13:32 +0000)
Doc/library/contextlib.rst
Lib/contextlib.py
Lib/test/test_contextlib.py
Misc/NEWS.d/next/Library/2023-11-09-10-45-56.gh-issue-103791.sdfkja.rst [new file with mode: 0644]

index 66b9c13710522350d1661146cd34ad5abdfbb236..f6ebbfacfba509f4927ea6129b00dd082a2c6fd4 100644 (file)
@@ -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)
 
index 6994690ebf7eb2a8c87ac6092cbe7cc0c1330e70..5b646fabca0225b4bb2cecec065f6861e7ed12ae 100644 (file)
@@ -461,7 +461,7 @@ class suppress(AbstractContextManager):
             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
index e32a091fdd1c92a6529de11801878090bf584b85..36c3abca80f8943bc523b0feb5741579d8f45e5e 100644 (file)
@@ -1297,6 +1297,24 @@ class TestSuppress(ExceptionIsLikeMixin, unittest.TestCase):
                 [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):
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 (file)
index 0000000..5bfdd75
--- /dev/null
@@ -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`.