[3.12] gh-103791: handle BaseExceptionGroup in contextlib.suppress() (GH-111910) (#111955)

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

Co-authored-by: Zac Hatfield-Dodds <zac.hatfield.dodds@gmail.com>
This commit is contained in:
Miss Islington (bot) 2023-11-10 15:00:48 +01:00 committed by GitHub
parent 4b0c875d91
commit 37804149ec
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 25 additions and 4 deletions

View file

@ -304,15 +304,15 @@ Functions and classes provided:
This context manager is :ref:`reentrant <reentrant-cms>`. This context manager is :ref:`reentrant <reentrant-cms>`.
If the code within the :keyword:`!with` block raises an If the code within the :keyword:`!with` block raises a
:exc:`ExceptionGroup`, suppressed exceptions are removed from the :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. group. If any exceptions in the group are not suppressed, a group containing them is re-raised.
.. versionadded:: 3.4 .. versionadded:: 3.4
.. versionchanged:: 3.12 .. versionchanged:: 3.12
``suppress`` now supports suppressing exceptions raised as ``suppress`` now supports suppressing exceptions raised as
part of an :exc:`ExceptionGroup`. part of an :exc:`BaseExceptionGroup`.
.. function:: redirect_stdout(new_target) .. function:: redirect_stdout(new_target)

View file

@ -457,7 +457,7 @@ class suppress(AbstractContextManager):
return return
if issubclass(exctype, self._exceptions): if issubclass(exctype, self._exceptions):
return True return True
if issubclass(exctype, ExceptionGroup): if issubclass(exctype, BaseExceptionGroup):
match, rest = excinst.split(self._exceptions) match, rest = excinst.split(self._exceptions)
if rest is None: if rest is None:
return True return True

View file

@ -1287,6 +1287,24 @@ class TestSuppress(ExceptionIsLikeMixin, unittest.TestCase):
[KeyError("ke1"), KeyError("ke2")], [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): class TestChdir(unittest.TestCase):

View file

@ -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`.