1from __future__ import annotations
2
3import sys
4from contextlib import AbstractContextManager
5from types import TracebackType
6from typing import TYPE_CHECKING, Optional, Type, cast
7
8if sys.version_info < (3, 11):
9 from ._exceptions import BaseExceptionGroup
10
11if TYPE_CHECKING:
12 # requires python 3.9
13 BaseClass = AbstractContextManager[None]
14else:
15 BaseClass = AbstractContextManager
16
17
18class suppress(BaseClass):
19 """Backport of :class:`contextlib.suppress` from Python 3.12.1."""
20
21 def __init__(self, *exceptions: type[BaseException]):
22 self._exceptions = exceptions
23
24 def __enter__(self) -> None:
25 pass
26
27 def __exit__(
28 self,
29 exctype: Optional[Type[BaseException]],
30 excinst: Optional[BaseException],
31 exctb: Optional[TracebackType],
32 ) -> bool:
33 # Unlike isinstance and issubclass, CPython exception handling
34 # currently only looks at the concrete type hierarchy (ignoring
35 # the instance and subclass checking hooks). While Guido considers
36 # that a bug rather than a feature, it's a fairly hard one to fix
37 # due to various internal implementation details. suppress provides
38 # the simpler issubclass based semantics, rather than trying to
39 # exactly reproduce the limitations of the CPython interpreter.
40 #
41 # See http://bugs.python.org/issue12029 for more details
42 if exctype is None:
43 return False
44
45 if issubclass(exctype, self._exceptions):
46 return True
47
48 if issubclass(exctype, BaseExceptionGroup):
49 match, rest = cast(BaseExceptionGroup, excinst).split(self._exceptions)
50 if rest is None:
51 return True
52
53 raise rest
54
55 return False