From 3412cdd801f2ae1853106b6d8a2c47e761af6fb4 Mon Sep 17 00:00:00 2001 From: sobolevn Date: Sun, 20 Nov 2022 17:05:59 +0300 Subject: [PATCH 01/11] Fix typings of `ExceptionGroup` and `BaseExceptionGroup` --- stdlib/builtins.pyi | 39 +- .../stdlib/builtins/check_exception_group.py | 369 ++++++++++++++++++ 2 files changed, 399 insertions(+), 9 deletions(-) create mode 100644 test_cases/stdlib/builtins/check_exception_group.py diff --git a/stdlib/builtins.pyi b/stdlib/builtins.pyi index f25777eeacd2..df74a00a42bc 100644 --- a/stdlib/builtins.pyi +++ b/stdlib/builtins.pyi @@ -1938,6 +1938,7 @@ if sys.version_info >= (3, 11): _ExceptionT_co = TypeVar("_ExceptionT_co", bound=Exception, covariant=True) _ExceptionT = TypeVar("_ExceptionT", bound=Exception) + # See `check_exception_group.py` for use-cases and comments. class BaseExceptionGroup(BaseException, Generic[_BaseExceptionT_co]): def __new__(cls: type[Self], __message: str, __exceptions: Sequence[_BaseExceptionT_co]) -> Self: ... @property @@ -1945,18 +1946,34 @@ if sys.version_info >= (3, 11): @property def exceptions(self) -> tuple[_BaseExceptionT_co | BaseExceptionGroup[_BaseExceptionT_co], ...]: ... @overload + def subgroup( + self, __condition: type[_ExceptionT] | tuple[type[_ExceptionT], ...] + ) -> ExceptionGroup[_ExceptionT] | None: ... + @overload def subgroup( self, __condition: type[_BaseExceptionT] | tuple[type[_BaseExceptionT], ...] ) -> BaseExceptionGroup[_BaseExceptionT] | None: ... @overload - def subgroup(self: Self, __condition: Callable[[_BaseExceptionT_co], bool]) -> Self | None: ... + def subgroup( + self: Self, __condition: Callable[[_BaseExceptionT_co | Self], bool] + ) -> BaseExceptionGroup[_BaseExceptionT_co] | None: ... @overload def split( - self: Self, __condition: type[_BaseExceptionT] | tuple[type[_BaseExceptionT], ...] - ) -> tuple[BaseExceptionGroup[_BaseExceptionT] | None, Self | None]: ... + self, __condition: type[_ExceptionT] | tuple[type[_ExceptionT], ...] + ) -> tuple[ExceptionGroup[_ExceptionT] | None, BaseExceptionGroup[_BaseExceptionT_co] | None]: ... @overload - def split(self: Self, __condition: Callable[[_BaseExceptionT_co], bool]) -> tuple[Self | None, Self | None]: ... - def derive(self: Self, __excs: Sequence[_BaseExceptionT_co]) -> Self: ... + def split( + self, __condition: type[_BaseExceptionT] | tuple[type[_BaseExceptionT], ...] + ) -> tuple[BaseExceptionGroup[_BaseExceptionT] | None, BaseExceptionGroup[_BaseExceptionT_co] | None]: ... + @overload + def split( + self: Self, __condition: Callable[[_BaseExceptionT_co | Self], bool] + ) -> tuple[BaseExceptionGroup[_BaseExceptionT_co] | None, BaseExceptionGroup[_BaseExceptionT_co] | None]: ... + # In reality it is `NonEmptySequence`: + @overload + def derive(self, __excs: Sequence[_ExceptionT]) -> ExceptionGroup[_ExceptionT]: ... + @overload + def derive(self, __excs: Sequence[_BaseExceptionT]) -> BaseExceptionGroup[_BaseExceptionT]: ... def __class_getitem__(cls, __item: Any) -> GenericAlias: ... class ExceptionGroup(BaseExceptionGroup[_ExceptionT_co], Exception): @@ -1969,10 +1986,14 @@ if sys.version_info >= (3, 11): self, __condition: type[_ExceptionT] | tuple[type[_ExceptionT], ...] ) -> ExceptionGroup[_ExceptionT] | None: ... @overload - def subgroup(self: Self, __condition: Callable[[_ExceptionT_co], bool]) -> Self | None: ... + def subgroup( + self: Self, __condition: Callable[[_ExceptionT_co | Self], bool] + ) -> ExceptionGroup[_ExceptionT_co] | None: ... @overload # type: ignore[override] def split( - self: Self, __condition: type[_ExceptionT] | tuple[type[_ExceptionT], ...] - ) -> tuple[ExceptionGroup[_ExceptionT] | None, Self | None]: ... + self, __condition: type[_ExceptionT] | tuple[type[_ExceptionT], ...] + ) -> tuple[ExceptionGroup[_ExceptionT] | None, ExceptionGroup[_ExceptionT_co] | None]: ... @overload - def split(self: Self, __condition: Callable[[_ExceptionT_co], bool]) -> tuple[Self | None, Self | None]: ... + def split( + self: Self, __condition: Callable[[_ExceptionT_co | Self], bool] + ) -> tuple[ExceptionGroup[_ExceptionT_co] | None, ExceptionGroup[_ExceptionT_co] | None]: ... diff --git a/test_cases/stdlib/builtins/check_exception_group.py b/test_cases/stdlib/builtins/check_exception_group.py new file mode 100644 index 000000000000..c30e3aa1f7f5 --- /dev/null +++ b/test_cases/stdlib/builtins/check_exception_group.py @@ -0,0 +1,369 @@ +from __future__ import annotations + +from typing import TypeVar +from typing_extensions import assert_type + + +# BaseExceptionGroup +# ================== + +# `BaseExceptionGroup` can work with `BaseException`: +beg = BaseExceptionGroup("x", [SystemExit(), SystemExit()]) +assert_type(beg, BaseExceptionGroup[SystemExit]) +assert_type(beg.exceptions, tuple[SystemExit | BaseExceptionGroup[SystemExit], ...]) + +# Covariance works: +_beg1: BaseExceptionGroup[BaseException] = beg + +# `BaseExceptionGroup` can work with `Exception`: +beg2 = BaseExceptionGroup("x", [ValueError()]) +# FIXME: this is not right, runtime returns `ExceptionGroup` instance instead, +# but I am unable to represent this with types right now. +assert_type(beg2, BaseExceptionGroup[ValueError]) + + +# .subgroup() +# ----------- + +assert_type(beg.subgroup(KeyboardInterrupt), BaseExceptionGroup[KeyboardInterrupt] | None) +assert_type(beg.subgroup((KeyboardInterrupt, SystemExit)), BaseExceptionGroup[BaseException] | None) + + +def is_base_exc(exc: BaseException) -> bool: + return isinstance(exc, BaseException) + + +def is_specific(exc: SystemExit | BaseExceptionGroup[SystemExit]) -> bool: + return isinstance(exc, SystemExit) + + +# This one does not have `BaseExceptionGroup` part, +# this is why we treat as an error. +def is_system_exit(exc: SystemExit) -> bool: + return isinstance(exc, SystemExit) + + +def unrelated_subgroup(exc: KeyboardInterrupt) -> bool: + return False + + +assert_type(beg.subgroup(is_base_exc), BaseExceptionGroup[SystemExit] | None) +assert_type(beg.subgroup(is_specific), BaseExceptionGroup[SystemExit] | None) +beg.subgroup(is_system_exit) # type: ignore +beg.subgroup(unrelated_subgroup) # type: ignore + +# This might be strange at first, `ValueError` is not listed in the generic params. +# But, this seems practical. Some exception types can be down-casted. +assert_type(beg.subgroup(ValueError), ExceptionGroup[ValueError] | None) +assert_type(beg.subgroup((ValueError, KeyError)), ExceptionGroup[Exception] | None) + +# Callable are harder, we don't support cast to `ExceptionGroup` here. +# Because callables might return `True` the first time. And `BaseExceptionGroup` +# will stick, no matter what arguments are. + + +def is_exception(exc: Exception) -> bool: + return isinstance(exc, Exception) + + +def is_exception_or_beg(exc: Exception | BaseExceptionGroup[SystemError]) -> bool: + return isinstance(exc, Exception) + + +# This is an error because of the `Exception` argument type, +# while `SystemError` is needed. +beg.subgroup(is_exception_or_beg) # type: ignore + +# This is an error, because `BaseExceptionGroup` is not an `Exception` +# subclass. It is required. +beg.subgroup(is_exception) # type: ignore + + +# .split() +# -------- + +assert_type( + beg.split(KeyboardInterrupt), tuple[BaseExceptionGroup[KeyboardInterrupt] | None, BaseExceptionGroup[SystemExit] | None] +) +assert_type( + beg.split((KeyboardInterrupt, SystemExit)), + tuple[BaseExceptionGroup[BaseException] | None, BaseExceptionGroup[SystemExit] | None], +) +assert_type( + beg.split(ValueError), # there are no `ValueError` items in there, but anyway + tuple[ExceptionGroup[ValueError] | None, BaseExceptionGroup[SystemExit] | None], +) + +excs_to_split: list[ValueError | KeyError | SystemExit] = [ValueError(), KeyError(), SystemExit()] +to_split = BaseExceptionGroup("x", excs_to_split) +assert_type(to_split, BaseExceptionGroup[ValueError | KeyError | SystemExit]) + +# Ideally the first part should be `ExceptionGroup[ValueError]` (done) +# and the second part should be `BaseExceptionGroup[KeyError | SystemExit]`, +# but we cannot substract type from a union. +# We also cannot change `BaseExceptionGroup` to `ExceptionGroup` even if needed +# in the second part here because of that. +assert_type( + to_split.split(ValueError), + tuple[ExceptionGroup[ValueError] | None, BaseExceptionGroup[ValueError | KeyError | SystemExit] | None,], +) + + +def split_callable1(exc: ValueError | KeyError | SystemExit | BaseExceptionGroup[ValueError | KeyError | SystemExit]) -> bool: + return True + + +assert_type( + to_split.split(split_callable1), # Concrete type is ok + tuple[ + BaseExceptionGroup[ValueError | KeyError | SystemExit] | None, + BaseExceptionGroup[ValueError | KeyError | SystemExit] | None, + ], +) +assert_type( + to_split.split(is_base_exc), # Base class is ok + tuple[ + BaseExceptionGroup[ValueError | KeyError | SystemExit] | None, + BaseExceptionGroup[ValueError | KeyError | SystemExit] | None, + ], +) +# `Exception` cannot be used: `BaseExceptionGroup` is not a subtype of it. +to_split.split(is_exception) # type: ignore + + +# .derive() +# --------- + +assert_type(beg.derive([ValueError()]), ExceptionGroup[ValueError]) +assert_type(beg.derive([KeyboardInterrupt()]), BaseExceptionGroup[KeyboardInterrupt]) + + +# ExceptionGroup +# ============== + +# `ExceptionGroup` can work with `Exception`: +excs: list[ValueError | KeyError] = [ValueError(), KeyError()] +eg = ExceptionGroup("x", excs) +assert_type(eg, ExceptionGroup[ValueError | KeyError]) +assert_type(eg.exceptions, tuple[ValueError | KeyError | ExceptionGroup[ValueError | KeyError], ...]) + +# Covariance works: +_eg1: ExceptionGroup[Exception] = eg + +# `ExceptionGroup` cannot work with `BaseException`: +ExceptionGroup("x", [SystemExit()]) # type: ignore + + +# .subgroup() +# ----------- + +# Our decision is to ban cases like:: +# +# >>> eg = ExceptionGroup('x', [ValueError()]) +# >>> eg.subgroup(BaseException) +# ExceptionGroup('e', [ValueError()]) +# +# are possible in runtime. +# We do it because, it does not make sense for all other base exception types. +# Supporting just `BaseException` looks like an overkill. +eg.subgroup(BaseException) # type: ignore +eg.subgroup((KeyboardInterrupt, SystemExit)) # type: ignore + +assert_type(eg.subgroup(Exception), ExceptionGroup[Exception] | None) +assert_type(eg.subgroup(ValueError), ExceptionGroup[ValueError] | None) +assert_type(eg.subgroup((ValueError, KeyError)), ExceptionGroup[Exception] | None) + + +def subgroup_eg1(exc: ValueError | KeyError | ExceptionGroup[ValueError | KeyError]) -> bool: + return True + + +def subgroup_eg2(exc: ValueError | KeyError) -> bool: + return True + + +assert_type(eg.subgroup(subgroup_eg1), ExceptionGroup[ValueError | KeyError] | None) +assert_type(eg.subgroup(is_exception), ExceptionGroup[ValueError | KeyError] | None) +assert_type(eg.subgroup(is_base_exc), ExceptionGroup[ValueError | KeyError] | None) +assert_type(eg.subgroup(is_base_exc), ExceptionGroup[ValueError | KeyError] | None) + +# Does not have `ExceptionGroup` part: +eg.subgroup(subgroup_eg2) # type: ignore + + +# .split() +# -------- + +assert_type(eg.split(TypeError), tuple[ExceptionGroup[TypeError] | None, ExceptionGroup[ValueError | KeyError] | None]) +assert_type( + eg.split((TypeError, IndexError)), tuple[ExceptionGroup[Exception] | None, ExceptionGroup[ValueError | KeyError] | None] +) +assert_type( + eg.split(is_exception), tuple[ExceptionGroup[ValueError | KeyError] | None, ExceptionGroup[ValueError | KeyError] | None] +) +assert_type( + eg.split(is_base_exc), + # is not converted, because `ExceptionGroup` cannot have + # direct `BaseException` subclasses inside. + tuple[ExceptionGroup[ValueError | KeyError] | None, ExceptionGroup[ValueError | KeyError] | None], +) + +# It does not include `ExceptionGroup` itself, so it will fail: +def value_or_key_error(exc: ValueError | KeyError) -> bool: + return isinstance(exc, (ValueError, KeyError)) + + +eg.split(value_or_key_error) # type: ignore + +# `ExceptionGroup` cannot have direct `BaseException` subclasses inside. +eg.split(BaseException) # type: ignore +eg.split((SystemExit, GeneratorExit)) # type: ignore + + +# .derive() +# --------- + +assert_type(eg.derive([ValueError()]), ExceptionGroup[ValueError]) +assert_type(eg.derive([KeyboardInterrupt()]), BaseExceptionGroup[KeyboardInterrupt]) + + +# BaseExceptionGroup Custom Subclass +# ================================== +# In some cases `Self` type can be preserved in runtime, +# but it is impossible to express. That's why we always fallback to +# `BaseExceptionGroup` and `ExceptionGroup`. + +_BE = TypeVar("_BE", bound=BaseException) + + +class CustomBaseGroup(BaseExceptionGroup[_BE]): + ... + + +cb1 = CustomBaseGroup("x", [SystemExit()]) +assert_type(cb1, CustomBaseGroup[SystemExit]) +cb2 = CustomBaseGroup("x", [ValueError()]) +assert_type(cb2, CustomBaseGroup[ValueError]) + + +# .subgroup() +# ----------- + +assert_type(cb1.subgroup(KeyboardInterrupt), BaseExceptionGroup[KeyboardInterrupt] | None) +assert_type(cb2.subgroup((KeyboardInterrupt, SystemExit)), BaseExceptionGroup[BaseException] | None) + +assert_type(cb1.subgroup(ValueError), ExceptionGroup[ValueError] | None) +assert_type(cb2.subgroup((KeyError, TypeError)), ExceptionGroup[Exception] | None) + + +def cb_subgroup1(exc: SystemExit | CustomBaseGroup[SystemExit]) -> bool: + return True + + +def cb_subgroup2(exc: ValueError | CustomBaseGroup[ValueError]) -> bool: + return True + + +assert_type(cb1.subgroup(cb_subgroup1), BaseExceptionGroup[SystemExit] | None) +assert_type(cb2.subgroup(cb_subgroup2), BaseExceptionGroup[ValueError] | None) +cb1.subgroup(cb_subgroup2) # type: ignore +cb2.subgroup(cb_subgroup1) # type: ignore + + +# .split() +# -------- + +assert_type( + cb1.split(KeyboardInterrupt), tuple[BaseExceptionGroup[KeyboardInterrupt] | None, BaseExceptionGroup[SystemExit] | None] +) +assert_type(cb1.split(TypeError), tuple[ExceptionGroup[TypeError] | None, BaseExceptionGroup[SystemExit] | None]) +assert_type(cb2.split((TypeError, IndexError)), tuple[ExceptionGroup[Exception] | None, BaseExceptionGroup[ValueError] | None]) + + +def cb_split1(exc: SystemExit | CustomBaseGroup[SystemExit]) -> bool: + return True + + +def cb_split2(exc: ValueError | CustomBaseGroup[ValueError]) -> bool: + return True + + +assert_type(cb1.split(cb_split1), tuple[BaseExceptionGroup[SystemExit] | None, BaseExceptionGroup[SystemExit] | None]) +assert_type(cb2.split(cb_split2), tuple[BaseExceptionGroup[ValueError] | None, BaseExceptionGroup[ValueError] | None]) +cb1.split(cb_split2) # type: ignore +cb2.split(cb_split1) # type: ignore + + +# .derive() +# --------- + +# Note, that `Self` type is not preserved in runtime. +assert_type(cb1.derive([ValueError()]), ExceptionGroup[ValueError]) +assert_type(cb1.derive([KeyboardInterrupt()]), BaseExceptionGroup[KeyboardInterrupt]) +assert_type(cb2.derive([ValueError()]), ExceptionGroup[ValueError]) +assert_type(cb2.derive([KeyboardInterrupt()]), BaseExceptionGroup[KeyboardInterrupt]) + + +# ExceptionGroup Custom Subclass +# ============================== + +_E = TypeVar("_E", bound=Exception) + + +class CustomGroup(ExceptionGroup[_E]): + ... + + +CustomGroup("x", [SystemExit()]) # type: ignore +cg1 = CustomGroup("x", [ValueError()]) +assert_type(cg1, CustomGroup[ValueError]) + + +# .subgroup() +# ----------- + +cg1.subgroup(BaseException) # type: ignore +cg1.subgroup((KeyboardInterrupt, SystemExit)) # type: ignore + +assert_type(cg1.subgroup(ValueError), ExceptionGroup[ValueError] | None) +assert_type(cg1.subgroup((KeyError, TypeError)), ExceptionGroup[Exception] | None) + + +def cg_subgroup1(exc: ValueError | CustomGroup[ValueError]) -> bool: + return True + + +def cg_subgroup2(exc: ValueError) -> bool: + return True + + +assert_type(cg1.subgroup(cg_subgroup1), ExceptionGroup[ValueError] | None) +cg1.subgroup(cb_subgroup2) # type: ignore + + +# .split() +# -------- + +assert_type(cg1.split(TypeError), tuple[ExceptionGroup[TypeError] | None, ExceptionGroup[ValueError] | None]) +assert_type(cg1.split((TypeError, IndexError)), tuple[ExceptionGroup[Exception] | None, ExceptionGroup[ValueError] | None]) +cg1.split(BaseException) # type: ignore + + +def cg_split1(exc: ValueError | CustomGroup[ValueError]) -> bool: + return True + + +def cg_split2(exc: ValueError) -> bool: + return True + + +assert_type(cg1.split(cg_split1), tuple[ExceptionGroup[ValueError] | None, ExceptionGroup[ValueError] | None]) +cg1.split(cg_split2) # type: ignore + + +# .derive() +# --------- + +# Note, that `Self` type is not preserved in runtime. +assert_type(cg1.derive([ValueError()]), ExceptionGroup[ValueError]) +assert_type(cg1.derive([KeyboardInterrupt()]), BaseExceptionGroup[KeyboardInterrupt]) From d6090edb31a6e263e7ac65b7e02a6e93aa6ebe88 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 20 Nov 2022 14:09:38 +0000 Subject: [PATCH 02/11] [pre-commit.ci] auto fixes from pre-commit.com hooks --- test_cases/stdlib/builtins/check_exception_group.py | 1 - 1 file changed, 1 deletion(-) diff --git a/test_cases/stdlib/builtins/check_exception_group.py b/test_cases/stdlib/builtins/check_exception_group.py index c30e3aa1f7f5..477917d13889 100644 --- a/test_cases/stdlib/builtins/check_exception_group.py +++ b/test_cases/stdlib/builtins/check_exception_group.py @@ -3,7 +3,6 @@ from typing import TypeVar from typing_extensions import assert_type - # BaseExceptionGroup # ================== From 4e37a93c5f1e06e221d90879e10a3323797603e9 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Sun, 20 Nov 2022 06:29:39 -0800 Subject: [PATCH 03/11] only in 3.11 --- .../stdlib/builtins/check_exception_group.py | 486 +++++++++--------- 1 file changed, 244 insertions(+), 242 deletions(-) diff --git a/test_cases/stdlib/builtins/check_exception_group.py b/test_cases/stdlib/builtins/check_exception_group.py index 477917d13889..77e0fdd9e17f 100644 --- a/test_cases/stdlib/builtins/check_exception_group.py +++ b/test_cases/stdlib/builtins/check_exception_group.py @@ -1,368 +1,370 @@ from __future__ import annotations +import sys from typing import TypeVar from typing_extensions import assert_type -# BaseExceptionGroup -# ================== +if sys.version_info >= (3, 11): + # BaseExceptionGroup + # ================== -# `BaseExceptionGroup` can work with `BaseException`: -beg = BaseExceptionGroup("x", [SystemExit(), SystemExit()]) -assert_type(beg, BaseExceptionGroup[SystemExit]) -assert_type(beg.exceptions, tuple[SystemExit | BaseExceptionGroup[SystemExit], ...]) + # `BaseExceptionGroup` can work with `BaseException`: + beg = BaseExceptionGroup("x", [SystemExit(), SystemExit()]) + assert_type(beg, BaseExceptionGroup[SystemExit]) + assert_type(beg.exceptions, tuple[SystemExit | BaseExceptionGroup[SystemExit], ...]) -# Covariance works: -_beg1: BaseExceptionGroup[BaseException] = beg + # Covariance works: + _beg1: BaseExceptionGroup[BaseException] = beg -# `BaseExceptionGroup` can work with `Exception`: -beg2 = BaseExceptionGroup("x", [ValueError()]) -# FIXME: this is not right, runtime returns `ExceptionGroup` instance instead, -# but I am unable to represent this with types right now. -assert_type(beg2, BaseExceptionGroup[ValueError]) + # `BaseExceptionGroup` can work with `Exception`: + beg2 = BaseExceptionGroup("x", [ValueError()]) + # FIXME: this is not right, runtime returns `ExceptionGroup` instance instead, + # but I am unable to represent this with types right now. + assert_type(beg2, BaseExceptionGroup[ValueError]) -# .subgroup() -# ----------- + # .subgroup() + # ----------- -assert_type(beg.subgroup(KeyboardInterrupt), BaseExceptionGroup[KeyboardInterrupt] | None) -assert_type(beg.subgroup((KeyboardInterrupt, SystemExit)), BaseExceptionGroup[BaseException] | None) + assert_type(beg.subgroup(KeyboardInterrupt), BaseExceptionGroup[KeyboardInterrupt] | None) + assert_type(beg.subgroup((KeyboardInterrupt, SystemExit)), BaseExceptionGroup[BaseException] | None) -def is_base_exc(exc: BaseException) -> bool: - return isinstance(exc, BaseException) + def is_base_exc(exc: BaseException) -> bool: + return isinstance(exc, BaseException) -def is_specific(exc: SystemExit | BaseExceptionGroup[SystemExit]) -> bool: - return isinstance(exc, SystemExit) + def is_specific(exc: SystemExit | BaseExceptionGroup[SystemExit]) -> bool: + return isinstance(exc, SystemExit) -# This one does not have `BaseExceptionGroup` part, -# this is why we treat as an error. -def is_system_exit(exc: SystemExit) -> bool: - return isinstance(exc, SystemExit) + # This one does not have `BaseExceptionGroup` part, + # this is why we treat as an error. + def is_system_exit(exc: SystemExit) -> bool: + return isinstance(exc, SystemExit) -def unrelated_subgroup(exc: KeyboardInterrupt) -> bool: - return False + def unrelated_subgroup(exc: KeyboardInterrupt) -> bool: + return False -assert_type(beg.subgroup(is_base_exc), BaseExceptionGroup[SystemExit] | None) -assert_type(beg.subgroup(is_specific), BaseExceptionGroup[SystemExit] | None) -beg.subgroup(is_system_exit) # type: ignore -beg.subgroup(unrelated_subgroup) # type: ignore + assert_type(beg.subgroup(is_base_exc), BaseExceptionGroup[SystemExit] | None) + assert_type(beg.subgroup(is_specific), BaseExceptionGroup[SystemExit] | None) + beg.subgroup(is_system_exit) # type: ignore + beg.subgroup(unrelated_subgroup) # type: ignore -# This might be strange at first, `ValueError` is not listed in the generic params. -# But, this seems practical. Some exception types can be down-casted. -assert_type(beg.subgroup(ValueError), ExceptionGroup[ValueError] | None) -assert_type(beg.subgroup((ValueError, KeyError)), ExceptionGroup[Exception] | None) + # This might be strange at first, `ValueError` is not listed in the generic params. + # But, this seems practical. Some exception types can be down-casted. + assert_type(beg.subgroup(ValueError), ExceptionGroup[ValueError] | None) + assert_type(beg.subgroup((ValueError, KeyError)), ExceptionGroup[Exception] | None) -# Callable are harder, we don't support cast to `ExceptionGroup` here. -# Because callables might return `True` the first time. And `BaseExceptionGroup` -# will stick, no matter what arguments are. + # Callable are harder, we don't support cast to `ExceptionGroup` here. + # Because callables might return `True` the first time. And `BaseExceptionGroup` + # will stick, no matter what arguments are. -def is_exception(exc: Exception) -> bool: - return isinstance(exc, Exception) + def is_exception(exc: Exception) -> bool: + return isinstance(exc, Exception) -def is_exception_or_beg(exc: Exception | BaseExceptionGroup[SystemError]) -> bool: - return isinstance(exc, Exception) + def is_exception_or_beg(exc: Exception | BaseExceptionGroup[SystemError]) -> bool: + return isinstance(exc, Exception) -# This is an error because of the `Exception` argument type, -# while `SystemError` is needed. -beg.subgroup(is_exception_or_beg) # type: ignore + # This is an error because of the `Exception` argument type, + # while `SystemError` is needed. + beg.subgroup(is_exception_or_beg) # type: ignore -# This is an error, because `BaseExceptionGroup` is not an `Exception` -# subclass. It is required. -beg.subgroup(is_exception) # type: ignore + # This is an error, because `BaseExceptionGroup` is not an `Exception` + # subclass. It is required. + beg.subgroup(is_exception) # type: ignore -# .split() -# -------- + # .split() + # -------- -assert_type( - beg.split(KeyboardInterrupt), tuple[BaseExceptionGroup[KeyboardInterrupt] | None, BaseExceptionGroup[SystemExit] | None] -) -assert_type( - beg.split((KeyboardInterrupt, SystemExit)), - tuple[BaseExceptionGroup[BaseException] | None, BaseExceptionGroup[SystemExit] | None], -) -assert_type( - beg.split(ValueError), # there are no `ValueError` items in there, but anyway - tuple[ExceptionGroup[ValueError] | None, BaseExceptionGroup[SystemExit] | None], -) + assert_type( + beg.split(KeyboardInterrupt), tuple[BaseExceptionGroup[KeyboardInterrupt] | None, BaseExceptionGroup[SystemExit] | None] + ) + assert_type( + beg.split((KeyboardInterrupt, SystemExit)), + tuple[BaseExceptionGroup[BaseException] | None, BaseExceptionGroup[SystemExit] | None], + ) + assert_type( + beg.split(ValueError), # there are no `ValueError` items in there, but anyway + tuple[ExceptionGroup[ValueError] | None, BaseExceptionGroup[SystemExit] | None], + ) -excs_to_split: list[ValueError | KeyError | SystemExit] = [ValueError(), KeyError(), SystemExit()] -to_split = BaseExceptionGroup("x", excs_to_split) -assert_type(to_split, BaseExceptionGroup[ValueError | KeyError | SystemExit]) + excs_to_split: list[ValueError | KeyError | SystemExit] = [ValueError(), KeyError(), SystemExit()] + to_split = BaseExceptionGroup("x", excs_to_split) + assert_type(to_split, BaseExceptionGroup[ValueError | KeyError | SystemExit]) -# Ideally the first part should be `ExceptionGroup[ValueError]` (done) -# and the second part should be `BaseExceptionGroup[KeyError | SystemExit]`, -# but we cannot substract type from a union. -# We also cannot change `BaseExceptionGroup` to `ExceptionGroup` even if needed -# in the second part here because of that. -assert_type( - to_split.split(ValueError), - tuple[ExceptionGroup[ValueError] | None, BaseExceptionGroup[ValueError | KeyError | SystemExit] | None,], -) + # Ideally the first part should be `ExceptionGroup[ValueError]` (done) + # and the second part should be `BaseExceptionGroup[KeyError | SystemExit]`, + # but we cannot substract type from a union. + # We also cannot change `BaseExceptionGroup` to `ExceptionGroup` even if needed + # in the second part here because of that. + assert_type( + to_split.split(ValueError), + tuple[ExceptionGroup[ValueError] | None, BaseExceptionGroup[ValueError | KeyError | SystemExit] | None,], + ) -def split_callable1(exc: ValueError | KeyError | SystemExit | BaseExceptionGroup[ValueError | KeyError | SystemExit]) -> bool: - return True + def split_callable1(exc: ValueError | KeyError | SystemExit | BaseExceptionGroup[ValueError | KeyError | SystemExit]) -> bool: + return True -assert_type( - to_split.split(split_callable1), # Concrete type is ok - tuple[ - BaseExceptionGroup[ValueError | KeyError | SystemExit] | None, - BaseExceptionGroup[ValueError | KeyError | SystemExit] | None, - ], -) -assert_type( - to_split.split(is_base_exc), # Base class is ok - tuple[ - BaseExceptionGroup[ValueError | KeyError | SystemExit] | None, - BaseExceptionGroup[ValueError | KeyError | SystemExit] | None, - ], -) -# `Exception` cannot be used: `BaseExceptionGroup` is not a subtype of it. -to_split.split(is_exception) # type: ignore + assert_type( + to_split.split(split_callable1), # Concrete type is ok + tuple[ + BaseExceptionGroup[ValueError | KeyError | SystemExit] | None, + BaseExceptionGroup[ValueError | KeyError | SystemExit] | None, + ], + ) + assert_type( + to_split.split(is_base_exc), # Base class is ok + tuple[ + BaseExceptionGroup[ValueError | KeyError | SystemExit] | None, + BaseExceptionGroup[ValueError | KeyError | SystemExit] | None, + ], + ) + # `Exception` cannot be used: `BaseExceptionGroup` is not a subtype of it. + to_split.split(is_exception) # type: ignore -# .derive() -# --------- + # .derive() + # --------- -assert_type(beg.derive([ValueError()]), ExceptionGroup[ValueError]) -assert_type(beg.derive([KeyboardInterrupt()]), BaseExceptionGroup[KeyboardInterrupt]) + assert_type(beg.derive([ValueError()]), ExceptionGroup[ValueError]) + assert_type(beg.derive([KeyboardInterrupt()]), BaseExceptionGroup[KeyboardInterrupt]) -# ExceptionGroup -# ============== + # ExceptionGroup + # ============== -# `ExceptionGroup` can work with `Exception`: -excs: list[ValueError | KeyError] = [ValueError(), KeyError()] -eg = ExceptionGroup("x", excs) -assert_type(eg, ExceptionGroup[ValueError | KeyError]) -assert_type(eg.exceptions, tuple[ValueError | KeyError | ExceptionGroup[ValueError | KeyError], ...]) + # `ExceptionGroup` can work with `Exception`: + excs: list[ValueError | KeyError] = [ValueError(), KeyError()] + eg = ExceptionGroup("x", excs) + assert_type(eg, ExceptionGroup[ValueError | KeyError]) + assert_type(eg.exceptions, tuple[ValueError | KeyError | ExceptionGroup[ValueError | KeyError], ...]) -# Covariance works: -_eg1: ExceptionGroup[Exception] = eg + # Covariance works: + _eg1: ExceptionGroup[Exception] = eg -# `ExceptionGroup` cannot work with `BaseException`: -ExceptionGroup("x", [SystemExit()]) # type: ignore + # `ExceptionGroup` cannot work with `BaseException`: + ExceptionGroup("x", [SystemExit()]) # type: ignore -# .subgroup() -# ----------- + # .subgroup() + # ----------- -# Our decision is to ban cases like:: -# -# >>> eg = ExceptionGroup('x', [ValueError()]) -# >>> eg.subgroup(BaseException) -# ExceptionGroup('e', [ValueError()]) -# -# are possible in runtime. -# We do it because, it does not make sense for all other base exception types. -# Supporting just `BaseException` looks like an overkill. -eg.subgroup(BaseException) # type: ignore -eg.subgroup((KeyboardInterrupt, SystemExit)) # type: ignore + # Our decision is to ban cases like:: + # + # >>> eg = ExceptionGroup('x', [ValueError()]) + # >>> eg.subgroup(BaseException) + # ExceptionGroup('e', [ValueError()]) + # + # are possible in runtime. + # We do it because, it does not make sense for all other base exception types. + # Supporting just `BaseException` looks like an overkill. + eg.subgroup(BaseException) # type: ignore + eg.subgroup((KeyboardInterrupt, SystemExit)) # type: ignore -assert_type(eg.subgroup(Exception), ExceptionGroup[Exception] | None) -assert_type(eg.subgroup(ValueError), ExceptionGroup[ValueError] | None) -assert_type(eg.subgroup((ValueError, KeyError)), ExceptionGroup[Exception] | None) + assert_type(eg.subgroup(Exception), ExceptionGroup[Exception] | None) + assert_type(eg.subgroup(ValueError), ExceptionGroup[ValueError] | None) + assert_type(eg.subgroup((ValueError, KeyError)), ExceptionGroup[Exception] | None) -def subgroup_eg1(exc: ValueError | KeyError | ExceptionGroup[ValueError | KeyError]) -> bool: - return True + def subgroup_eg1(exc: ValueError | KeyError | ExceptionGroup[ValueError | KeyError]) -> bool: + return True -def subgroup_eg2(exc: ValueError | KeyError) -> bool: - return True + def subgroup_eg2(exc: ValueError | KeyError) -> bool: + return True -assert_type(eg.subgroup(subgroup_eg1), ExceptionGroup[ValueError | KeyError] | None) -assert_type(eg.subgroup(is_exception), ExceptionGroup[ValueError | KeyError] | None) -assert_type(eg.subgroup(is_base_exc), ExceptionGroup[ValueError | KeyError] | None) -assert_type(eg.subgroup(is_base_exc), ExceptionGroup[ValueError | KeyError] | None) + assert_type(eg.subgroup(subgroup_eg1), ExceptionGroup[ValueError | KeyError] | None) + assert_type(eg.subgroup(is_exception), ExceptionGroup[ValueError | KeyError] | None) + assert_type(eg.subgroup(is_base_exc), ExceptionGroup[ValueError | KeyError] | None) + assert_type(eg.subgroup(is_base_exc), ExceptionGroup[ValueError | KeyError] | None) -# Does not have `ExceptionGroup` part: -eg.subgroup(subgroup_eg2) # type: ignore + # Does not have `ExceptionGroup` part: + eg.subgroup(subgroup_eg2) # type: ignore -# .split() -# -------- + # .split() + # -------- -assert_type(eg.split(TypeError), tuple[ExceptionGroup[TypeError] | None, ExceptionGroup[ValueError | KeyError] | None]) -assert_type( - eg.split((TypeError, IndexError)), tuple[ExceptionGroup[Exception] | None, ExceptionGroup[ValueError | KeyError] | None] -) -assert_type( - eg.split(is_exception), tuple[ExceptionGroup[ValueError | KeyError] | None, ExceptionGroup[ValueError | KeyError] | None] -) -assert_type( - eg.split(is_base_exc), - # is not converted, because `ExceptionGroup` cannot have - # direct `BaseException` subclasses inside. - tuple[ExceptionGroup[ValueError | KeyError] | None, ExceptionGroup[ValueError | KeyError] | None], -) + assert_type(eg.split(TypeError), tuple[ExceptionGroup[TypeError] | None, ExceptionGroup[ValueError | KeyError] | None]) + assert_type( + eg.split((TypeError, IndexError)), tuple[ExceptionGroup[Exception] | None, ExceptionGroup[ValueError | KeyError] | None] + ) + assert_type( + eg.split(is_exception), tuple[ExceptionGroup[ValueError | KeyError] | None, ExceptionGroup[ValueError | KeyError] | None] + ) + assert_type( + eg.split(is_base_exc), + # is not converted, because `ExceptionGroup` cannot have + # direct `BaseException` subclasses inside. + tuple[ExceptionGroup[ValueError | KeyError] | None, ExceptionGroup[ValueError | KeyError] | None], + ) -# It does not include `ExceptionGroup` itself, so it will fail: -def value_or_key_error(exc: ValueError | KeyError) -> bool: - return isinstance(exc, (ValueError, KeyError)) + # It does not include `ExceptionGroup` itself, so it will fail: + def value_or_key_error(exc: ValueError | KeyError) -> bool: + return isinstance(exc, (ValueError, KeyError)) -eg.split(value_or_key_error) # type: ignore + eg.split(value_or_key_error) # type: ignore -# `ExceptionGroup` cannot have direct `BaseException` subclasses inside. -eg.split(BaseException) # type: ignore -eg.split((SystemExit, GeneratorExit)) # type: ignore + # `ExceptionGroup` cannot have direct `BaseException` subclasses inside. + eg.split(BaseException) # type: ignore + eg.split((SystemExit, GeneratorExit)) # type: ignore -# .derive() -# --------- + # .derive() + # --------- -assert_type(eg.derive([ValueError()]), ExceptionGroup[ValueError]) -assert_type(eg.derive([KeyboardInterrupt()]), BaseExceptionGroup[KeyboardInterrupt]) + assert_type(eg.derive([ValueError()]), ExceptionGroup[ValueError]) + assert_type(eg.derive([KeyboardInterrupt()]), BaseExceptionGroup[KeyboardInterrupt]) -# BaseExceptionGroup Custom Subclass -# ================================== -# In some cases `Self` type can be preserved in runtime, -# but it is impossible to express. That's why we always fallback to -# `BaseExceptionGroup` and `ExceptionGroup`. + # BaseExceptionGroup Custom Subclass + # ================================== + # In some cases `Self` type can be preserved in runtime, + # but it is impossible to express. That's why we always fallback to + # `BaseExceptionGroup` and `ExceptionGroup`. -_BE = TypeVar("_BE", bound=BaseException) + _BE = TypeVar("_BE", bound=BaseException) -class CustomBaseGroup(BaseExceptionGroup[_BE]): - ... + class CustomBaseGroup(BaseExceptionGroup[_BE]): + ... -cb1 = CustomBaseGroup("x", [SystemExit()]) -assert_type(cb1, CustomBaseGroup[SystemExit]) -cb2 = CustomBaseGroup("x", [ValueError()]) -assert_type(cb2, CustomBaseGroup[ValueError]) + cb1 = CustomBaseGroup("x", [SystemExit()]) + assert_type(cb1, CustomBaseGroup[SystemExit]) + cb2 = CustomBaseGroup("x", [ValueError()]) + assert_type(cb2, CustomBaseGroup[ValueError]) -# .subgroup() -# ----------- + # .subgroup() + # ----------- -assert_type(cb1.subgroup(KeyboardInterrupt), BaseExceptionGroup[KeyboardInterrupt] | None) -assert_type(cb2.subgroup((KeyboardInterrupt, SystemExit)), BaseExceptionGroup[BaseException] | None) + assert_type(cb1.subgroup(KeyboardInterrupt), BaseExceptionGroup[KeyboardInterrupt] | None) + assert_type(cb2.subgroup((KeyboardInterrupt, SystemExit)), BaseExceptionGroup[BaseException] | None) -assert_type(cb1.subgroup(ValueError), ExceptionGroup[ValueError] | None) -assert_type(cb2.subgroup((KeyError, TypeError)), ExceptionGroup[Exception] | None) + assert_type(cb1.subgroup(ValueError), ExceptionGroup[ValueError] | None) + assert_type(cb2.subgroup((KeyError, TypeError)), ExceptionGroup[Exception] | None) -def cb_subgroup1(exc: SystemExit | CustomBaseGroup[SystemExit]) -> bool: - return True + def cb_subgroup1(exc: SystemExit | CustomBaseGroup[SystemExit]) -> bool: + return True -def cb_subgroup2(exc: ValueError | CustomBaseGroup[ValueError]) -> bool: - return True + def cb_subgroup2(exc: ValueError | CustomBaseGroup[ValueError]) -> bool: + return True -assert_type(cb1.subgroup(cb_subgroup1), BaseExceptionGroup[SystemExit] | None) -assert_type(cb2.subgroup(cb_subgroup2), BaseExceptionGroup[ValueError] | None) -cb1.subgroup(cb_subgroup2) # type: ignore -cb2.subgroup(cb_subgroup1) # type: ignore + assert_type(cb1.subgroup(cb_subgroup1), BaseExceptionGroup[SystemExit] | None) + assert_type(cb2.subgroup(cb_subgroup2), BaseExceptionGroup[ValueError] | None) + cb1.subgroup(cb_subgroup2) # type: ignore + cb2.subgroup(cb_subgroup1) # type: ignore -# .split() -# -------- + # .split() + # -------- -assert_type( - cb1.split(KeyboardInterrupt), tuple[BaseExceptionGroup[KeyboardInterrupt] | None, BaseExceptionGroup[SystemExit] | None] -) -assert_type(cb1.split(TypeError), tuple[ExceptionGroup[TypeError] | None, BaseExceptionGroup[SystemExit] | None]) -assert_type(cb2.split((TypeError, IndexError)), tuple[ExceptionGroup[Exception] | None, BaseExceptionGroup[ValueError] | None]) + assert_type( + cb1.split(KeyboardInterrupt), tuple[BaseExceptionGroup[KeyboardInterrupt] | None, BaseExceptionGroup[SystemExit] | None] + ) + assert_type(cb1.split(TypeError), tuple[ExceptionGroup[TypeError] | None, BaseExceptionGroup[SystemExit] | None]) + assert_type(cb2.split((TypeError, IndexError)), tuple[ExceptionGroup[Exception] | None, BaseExceptionGroup[ValueError] | None]) -def cb_split1(exc: SystemExit | CustomBaseGroup[SystemExit]) -> bool: - return True + def cb_split1(exc: SystemExit | CustomBaseGroup[SystemExit]) -> bool: + return True -def cb_split2(exc: ValueError | CustomBaseGroup[ValueError]) -> bool: - return True + def cb_split2(exc: ValueError | CustomBaseGroup[ValueError]) -> bool: + return True -assert_type(cb1.split(cb_split1), tuple[BaseExceptionGroup[SystemExit] | None, BaseExceptionGroup[SystemExit] | None]) -assert_type(cb2.split(cb_split2), tuple[BaseExceptionGroup[ValueError] | None, BaseExceptionGroup[ValueError] | None]) -cb1.split(cb_split2) # type: ignore -cb2.split(cb_split1) # type: ignore + assert_type(cb1.split(cb_split1), tuple[BaseExceptionGroup[SystemExit] | None, BaseExceptionGroup[SystemExit] | None]) + assert_type(cb2.split(cb_split2), tuple[BaseExceptionGroup[ValueError] | None, BaseExceptionGroup[ValueError] | None]) + cb1.split(cb_split2) # type: ignore + cb2.split(cb_split1) # type: ignore -# .derive() -# --------- + # .derive() + # --------- -# Note, that `Self` type is not preserved in runtime. -assert_type(cb1.derive([ValueError()]), ExceptionGroup[ValueError]) -assert_type(cb1.derive([KeyboardInterrupt()]), BaseExceptionGroup[KeyboardInterrupt]) -assert_type(cb2.derive([ValueError()]), ExceptionGroup[ValueError]) -assert_type(cb2.derive([KeyboardInterrupt()]), BaseExceptionGroup[KeyboardInterrupt]) + # Note, that `Self` type is not preserved in runtime. + assert_type(cb1.derive([ValueError()]), ExceptionGroup[ValueError]) + assert_type(cb1.derive([KeyboardInterrupt()]), BaseExceptionGroup[KeyboardInterrupt]) + assert_type(cb2.derive([ValueError()]), ExceptionGroup[ValueError]) + assert_type(cb2.derive([KeyboardInterrupt()]), BaseExceptionGroup[KeyboardInterrupt]) -# ExceptionGroup Custom Subclass -# ============================== + # ExceptionGroup Custom Subclass + # ============================== -_E = TypeVar("_E", bound=Exception) + _E = TypeVar("_E", bound=Exception) -class CustomGroup(ExceptionGroup[_E]): - ... + class CustomGroup(ExceptionGroup[_E]): + ... -CustomGroup("x", [SystemExit()]) # type: ignore -cg1 = CustomGroup("x", [ValueError()]) -assert_type(cg1, CustomGroup[ValueError]) + CustomGroup("x", [SystemExit()]) # type: ignore + cg1 = CustomGroup("x", [ValueError()]) + assert_type(cg1, CustomGroup[ValueError]) -# .subgroup() -# ----------- + # .subgroup() + # ----------- -cg1.subgroup(BaseException) # type: ignore -cg1.subgroup((KeyboardInterrupt, SystemExit)) # type: ignore + cg1.subgroup(BaseException) # type: ignore + cg1.subgroup((KeyboardInterrupt, SystemExit)) # type: ignore -assert_type(cg1.subgroup(ValueError), ExceptionGroup[ValueError] | None) -assert_type(cg1.subgroup((KeyError, TypeError)), ExceptionGroup[Exception] | None) + assert_type(cg1.subgroup(ValueError), ExceptionGroup[ValueError] | None) + assert_type(cg1.subgroup((KeyError, TypeError)), ExceptionGroup[Exception] | None) -def cg_subgroup1(exc: ValueError | CustomGroup[ValueError]) -> bool: - return True + def cg_subgroup1(exc: ValueError | CustomGroup[ValueError]) -> bool: + return True -def cg_subgroup2(exc: ValueError) -> bool: - return True + def cg_subgroup2(exc: ValueError) -> bool: + return True -assert_type(cg1.subgroup(cg_subgroup1), ExceptionGroup[ValueError] | None) -cg1.subgroup(cb_subgroup2) # type: ignore + assert_type(cg1.subgroup(cg_subgroup1), ExceptionGroup[ValueError] | None) + cg1.subgroup(cb_subgroup2) # type: ignore -# .split() -# -------- + # .split() + # -------- -assert_type(cg1.split(TypeError), tuple[ExceptionGroup[TypeError] | None, ExceptionGroup[ValueError] | None]) -assert_type(cg1.split((TypeError, IndexError)), tuple[ExceptionGroup[Exception] | None, ExceptionGroup[ValueError] | None]) -cg1.split(BaseException) # type: ignore + assert_type(cg1.split(TypeError), tuple[ExceptionGroup[TypeError] | None, ExceptionGroup[ValueError] | None]) + assert_type(cg1.split((TypeError, IndexError)), tuple[ExceptionGroup[Exception] | None, ExceptionGroup[ValueError] | None]) + cg1.split(BaseException) # type: ignore -def cg_split1(exc: ValueError | CustomGroup[ValueError]) -> bool: - return True + def cg_split1(exc: ValueError | CustomGroup[ValueError]) -> bool: + return True -def cg_split2(exc: ValueError) -> bool: - return True + def cg_split2(exc: ValueError) -> bool: + return True -assert_type(cg1.split(cg_split1), tuple[ExceptionGroup[ValueError] | None, ExceptionGroup[ValueError] | None]) -cg1.split(cg_split2) # type: ignore + assert_type(cg1.split(cg_split1), tuple[ExceptionGroup[ValueError] | None, ExceptionGroup[ValueError] | None]) + cg1.split(cg_split2) # type: ignore -# .derive() -# --------- + # .derive() + # --------- -# Note, that `Self` type is not preserved in runtime. -assert_type(cg1.derive([ValueError()]), ExceptionGroup[ValueError]) -assert_type(cg1.derive([KeyboardInterrupt()]), BaseExceptionGroup[KeyboardInterrupt]) + # Note, that `Self` type is not preserved in runtime. + assert_type(cg1.derive([ValueError()]), ExceptionGroup[ValueError]) + assert_type(cg1.derive([KeyboardInterrupt()]), BaseExceptionGroup[KeyboardInterrupt]) From 5daa26c7d58ff8109825de8e9ab4abee92a31c74 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 20 Nov 2022 14:30:41 +0000 Subject: [PATCH 04/11] [pre-commit.ci] auto fixes from pre-commit.com hooks --- .../stdlib/builtins/check_exception_group.py | 49 ++----------------- 1 file changed, 3 insertions(+), 46 deletions(-) diff --git a/test_cases/stdlib/builtins/check_exception_group.py b/test_cases/stdlib/builtins/check_exception_group.py index 77e0fdd9e17f..23b355a2cb37 100644 --- a/test_cases/stdlib/builtins/check_exception_group.py +++ b/test_cases/stdlib/builtins/check_exception_group.py @@ -22,32 +22,26 @@ # but I am unable to represent this with types right now. assert_type(beg2, BaseExceptionGroup[ValueError]) - # .subgroup() # ----------- assert_type(beg.subgroup(KeyboardInterrupt), BaseExceptionGroup[KeyboardInterrupt] | None) assert_type(beg.subgroup((KeyboardInterrupt, SystemExit)), BaseExceptionGroup[BaseException] | None) - def is_base_exc(exc: BaseException) -> bool: return isinstance(exc, BaseException) - def is_specific(exc: SystemExit | BaseExceptionGroup[SystemExit]) -> bool: return isinstance(exc, SystemExit) - # This one does not have `BaseExceptionGroup` part, # this is why we treat as an error. def is_system_exit(exc: SystemExit) -> bool: return isinstance(exc, SystemExit) - def unrelated_subgroup(exc: KeyboardInterrupt) -> bool: return False - assert_type(beg.subgroup(is_base_exc), BaseExceptionGroup[SystemExit] | None) assert_type(beg.subgroup(is_specific), BaseExceptionGroup[SystemExit] | None) beg.subgroup(is_system_exit) # type: ignore @@ -62,15 +56,12 @@ def unrelated_subgroup(exc: KeyboardInterrupt) -> bool: # Because callables might return `True` the first time. And `BaseExceptionGroup` # will stick, no matter what arguments are. - def is_exception(exc: Exception) -> bool: return isinstance(exc, Exception) - def is_exception_or_beg(exc: Exception | BaseExceptionGroup[SystemError]) -> bool: return isinstance(exc, Exception) - # This is an error because of the `Exception` argument type, # while `SystemError` is needed. beg.subgroup(is_exception_or_beg) # type: ignore @@ -79,7 +70,6 @@ def is_exception_or_beg(exc: Exception | BaseExceptionGroup[SystemError]) -> boo # subclass. It is required. beg.subgroup(is_exception) # type: ignore - # .split() # -------- @@ -109,11 +99,9 @@ def is_exception_or_beg(exc: Exception | BaseExceptionGroup[SystemError]) -> boo tuple[ExceptionGroup[ValueError] | None, BaseExceptionGroup[ValueError | KeyError | SystemExit] | None,], ) - def split_callable1(exc: ValueError | KeyError | SystemExit | BaseExceptionGroup[ValueError | KeyError | SystemExit]) -> bool: return True - assert_type( to_split.split(split_callable1), # Concrete type is ok tuple[ @@ -131,14 +119,12 @@ def split_callable1(exc: ValueError | KeyError | SystemExit | BaseExceptionGroup # `Exception` cannot be used: `BaseExceptionGroup` is not a subtype of it. to_split.split(is_exception) # type: ignore - # .derive() # --------- assert_type(beg.derive([ValueError()]), ExceptionGroup[ValueError]) assert_type(beg.derive([KeyboardInterrupt()]), BaseExceptionGroup[KeyboardInterrupt]) - # ExceptionGroup # ============== @@ -154,7 +140,6 @@ def split_callable1(exc: ValueError | KeyError | SystemExit | BaseExceptionGroup # `ExceptionGroup` cannot work with `BaseException`: ExceptionGroup("x", [SystemExit()]) # type: ignore - # .subgroup() # ----------- @@ -174,15 +159,12 @@ def split_callable1(exc: ValueError | KeyError | SystemExit | BaseExceptionGroup assert_type(eg.subgroup(ValueError), ExceptionGroup[ValueError] | None) assert_type(eg.subgroup((ValueError, KeyError)), ExceptionGroup[Exception] | None) - def subgroup_eg1(exc: ValueError | KeyError | ExceptionGroup[ValueError | KeyError]) -> bool: return True - def subgroup_eg2(exc: ValueError | KeyError) -> bool: return True - assert_type(eg.subgroup(subgroup_eg1), ExceptionGroup[ValueError | KeyError] | None) assert_type(eg.subgroup(is_exception), ExceptionGroup[ValueError | KeyError] | None) assert_type(eg.subgroup(is_base_exc), ExceptionGroup[ValueError | KeyError] | None) @@ -191,7 +173,6 @@ def subgroup_eg2(exc: ValueError | KeyError) -> bool: # Does not have `ExceptionGroup` part: eg.subgroup(subgroup_eg2) # type: ignore - # .split() # -------- @@ -213,21 +194,18 @@ def subgroup_eg2(exc: ValueError | KeyError) -> bool: def value_or_key_error(exc: ValueError | KeyError) -> bool: return isinstance(exc, (ValueError, KeyError)) - eg.split(value_or_key_error) # type: ignore # `ExceptionGroup` cannot have direct `BaseException` subclasses inside. eg.split(BaseException) # type: ignore eg.split((SystemExit, GeneratorExit)) # type: ignore - # .derive() # --------- assert_type(eg.derive([ValueError()]), ExceptionGroup[ValueError]) assert_type(eg.derive([KeyboardInterrupt()]), BaseExceptionGroup[KeyboardInterrupt]) - # BaseExceptionGroup Custom Subclass # ================================== # In some cases `Self` type can be preserved in runtime, @@ -236,17 +214,14 @@ def value_or_key_error(exc: ValueError | KeyError) -> bool: _BE = TypeVar("_BE", bound=BaseException) - class CustomBaseGroup(BaseExceptionGroup[_BE]): ... - cb1 = CustomBaseGroup("x", [SystemExit()]) assert_type(cb1, CustomBaseGroup[SystemExit]) cb2 = CustomBaseGroup("x", [ValueError()]) assert_type(cb2, CustomBaseGroup[ValueError]) - # .subgroup() # ----------- @@ -256,21 +231,17 @@ class CustomBaseGroup(BaseExceptionGroup[_BE]): assert_type(cb1.subgroup(ValueError), ExceptionGroup[ValueError] | None) assert_type(cb2.subgroup((KeyError, TypeError)), ExceptionGroup[Exception] | None) - def cb_subgroup1(exc: SystemExit | CustomBaseGroup[SystemExit]) -> bool: return True - def cb_subgroup2(exc: ValueError | CustomBaseGroup[ValueError]) -> bool: return True - assert_type(cb1.subgroup(cb_subgroup1), BaseExceptionGroup[SystemExit] | None) assert_type(cb2.subgroup(cb_subgroup2), BaseExceptionGroup[ValueError] | None) cb1.subgroup(cb_subgroup2) # type: ignore cb2.subgroup(cb_subgroup1) # type: ignore - # .split() # -------- @@ -278,23 +249,21 @@ def cb_subgroup2(exc: ValueError | CustomBaseGroup[ValueError]) -> bool: cb1.split(KeyboardInterrupt), tuple[BaseExceptionGroup[KeyboardInterrupt] | None, BaseExceptionGroup[SystemExit] | None] ) assert_type(cb1.split(TypeError), tuple[ExceptionGroup[TypeError] | None, BaseExceptionGroup[SystemExit] | None]) - assert_type(cb2.split((TypeError, IndexError)), tuple[ExceptionGroup[Exception] | None, BaseExceptionGroup[ValueError] | None]) - + assert_type( + cb2.split((TypeError, IndexError)), tuple[ExceptionGroup[Exception] | None, BaseExceptionGroup[ValueError] | None] + ) def cb_split1(exc: SystemExit | CustomBaseGroup[SystemExit]) -> bool: return True - def cb_split2(exc: ValueError | CustomBaseGroup[ValueError]) -> bool: return True - assert_type(cb1.split(cb_split1), tuple[BaseExceptionGroup[SystemExit] | None, BaseExceptionGroup[SystemExit] | None]) assert_type(cb2.split(cb_split2), tuple[BaseExceptionGroup[ValueError] | None, BaseExceptionGroup[ValueError] | None]) cb1.split(cb_split2) # type: ignore cb2.split(cb_split1) # type: ignore - # .derive() # --------- @@ -304,22 +273,18 @@ def cb_split2(exc: ValueError | CustomBaseGroup[ValueError]) -> bool: assert_type(cb2.derive([ValueError()]), ExceptionGroup[ValueError]) assert_type(cb2.derive([KeyboardInterrupt()]), BaseExceptionGroup[KeyboardInterrupt]) - # ExceptionGroup Custom Subclass # ============================== _E = TypeVar("_E", bound=Exception) - class CustomGroup(ExceptionGroup[_E]): ... - CustomGroup("x", [SystemExit()]) # type: ignore cg1 = CustomGroup("x", [ValueError()]) assert_type(cg1, CustomGroup[ValueError]) - # .subgroup() # ----------- @@ -329,19 +294,15 @@ class CustomGroup(ExceptionGroup[_E]): assert_type(cg1.subgroup(ValueError), ExceptionGroup[ValueError] | None) assert_type(cg1.subgroup((KeyError, TypeError)), ExceptionGroup[Exception] | None) - def cg_subgroup1(exc: ValueError | CustomGroup[ValueError]) -> bool: return True - def cg_subgroup2(exc: ValueError) -> bool: return True - assert_type(cg1.subgroup(cg_subgroup1), ExceptionGroup[ValueError] | None) cg1.subgroup(cb_subgroup2) # type: ignore - # .split() # -------- @@ -349,19 +310,15 @@ def cg_subgroup2(exc: ValueError) -> bool: assert_type(cg1.split((TypeError, IndexError)), tuple[ExceptionGroup[Exception] | None, ExceptionGroup[ValueError] | None]) cg1.split(BaseException) # type: ignore - def cg_split1(exc: ValueError | CustomGroup[ValueError]) -> bool: return True - def cg_split2(exc: ValueError) -> bool: return True - assert_type(cg1.split(cg_split1), tuple[ExceptionGroup[ValueError] | None, ExceptionGroup[ValueError] | None]) cg1.split(cg_split2) # type: ignore - # .derive() # --------- From 9c06c0a558a3c9ec45e225fcef875f468d99005a Mon Sep 17 00:00:00 2001 From: sobolevn Date: Mon, 21 Nov 2022 16:32:54 +0300 Subject: [PATCH 05/11] Address review --- .../stdlib/builtins/check_exception_group.py | 23 ++++++++----------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/test_cases/stdlib/builtins/check_exception_group.py b/test_cases/stdlib/builtins/check_exception_group.py index 23b355a2cb37..260bb37771e0 100644 --- a/test_cases/stdlib/builtins/check_exception_group.py +++ b/test_cases/stdlib/builtins/check_exception_group.py @@ -26,7 +26,7 @@ # ----------- assert_type(beg.subgroup(KeyboardInterrupt), BaseExceptionGroup[KeyboardInterrupt] | None) - assert_type(beg.subgroup((KeyboardInterrupt, SystemExit)), BaseExceptionGroup[BaseException] | None) + assert_type(beg.subgroup((KeyboardInterrupt,)), BaseExceptionGroup[KeyboardInterrupt] | None) def is_base_exc(exc: BaseException) -> bool: return isinstance(exc, BaseException) @@ -47,10 +47,9 @@ def unrelated_subgroup(exc: KeyboardInterrupt) -> bool: beg.subgroup(is_system_exit) # type: ignore beg.subgroup(unrelated_subgroup) # type: ignore - # This might be strange at first, `ValueError` is not listed in the generic params. - # But, this seems practical. Some exception types can be down-casted. + # `Exception`` subgroup returns `ExceptionGroup`: assert_type(beg.subgroup(ValueError), ExceptionGroup[ValueError] | None) - assert_type(beg.subgroup((ValueError, KeyError)), ExceptionGroup[Exception] | None) + assert_type(beg.subgroup((ValueError,)), ExceptionGroup[ValueError] | None) # Callable are harder, we don't support cast to `ExceptionGroup` here. # Because callables might return `True` the first time. And `BaseExceptionGroup` @@ -59,11 +58,11 @@ def unrelated_subgroup(exc: KeyboardInterrupt) -> bool: def is_exception(exc: Exception) -> bool: return isinstance(exc, Exception) - def is_exception_or_beg(exc: Exception | BaseExceptionGroup[SystemError]) -> bool: + def is_exception_or_beg(exc: Exception | BaseExceptionGroup[SystemExit]) -> bool: return isinstance(exc, Exception) # This is an error because of the `Exception` argument type, - # while `SystemError` is needed. + # while `SystemExit` is needed instead. beg.subgroup(is_exception_or_beg) # type: ignore # This is an error, because `BaseExceptionGroup` is not an `Exception` @@ -77,8 +76,8 @@ def is_exception_or_beg(exc: Exception | BaseExceptionGroup[SystemError]) -> boo beg.split(KeyboardInterrupt), tuple[BaseExceptionGroup[KeyboardInterrupt] | None, BaseExceptionGroup[SystemExit] | None] ) assert_type( - beg.split((KeyboardInterrupt, SystemExit)), - tuple[BaseExceptionGroup[BaseException] | None, BaseExceptionGroup[SystemExit] | None], + beg.split((KeyboardInterrupt,)), + tuple[BaseExceptionGroup[KeyboardInterrupt] | None, BaseExceptionGroup[SystemExit] | None], ) assert_type( beg.split(ValueError), # there are no `ValueError` items in there, but anyway @@ -157,7 +156,7 @@ def split_callable1(exc: ValueError | KeyError | SystemExit | BaseExceptionGroup assert_type(eg.subgroup(Exception), ExceptionGroup[Exception] | None) assert_type(eg.subgroup(ValueError), ExceptionGroup[ValueError] | None) - assert_type(eg.subgroup((ValueError, KeyError)), ExceptionGroup[Exception] | None) + assert_type(eg.subgroup((ValueError,)), ExceptionGroup[ValueError] | None) def subgroup_eg1(exc: ValueError | KeyError | ExceptionGroup[ValueError | KeyError]) -> bool: return True @@ -177,9 +176,7 @@ def subgroup_eg2(exc: ValueError | KeyError) -> bool: # -------- assert_type(eg.split(TypeError), tuple[ExceptionGroup[TypeError] | None, ExceptionGroup[ValueError | KeyError] | None]) - assert_type( - eg.split((TypeError, IndexError)), tuple[ExceptionGroup[Exception] | None, ExceptionGroup[ValueError | KeyError] | None] - ) + assert_type(eg.split((TypeError,)), tuple[ExceptionGroup[TypeError] | None, ExceptionGroup[ValueError | KeyError] | None]) assert_type( eg.split(is_exception), tuple[ExceptionGroup[ValueError | KeyError] | None, ExceptionGroup[ValueError | KeyError] | None] ) @@ -226,7 +223,7 @@ class CustomBaseGroup(BaseExceptionGroup[_BE]): # ----------- assert_type(cb1.subgroup(KeyboardInterrupt), BaseExceptionGroup[KeyboardInterrupt] | None) - assert_type(cb2.subgroup((KeyboardInterrupt, SystemExit)), BaseExceptionGroup[BaseException] | None) + assert_type(cb2.subgroup((KeyboardInterrupt,)), BaseExceptionGroup[KeyboardInterrupt] | None) assert_type(cb1.subgroup(ValueError), ExceptionGroup[ValueError] | None) assert_type(cb2.subgroup((KeyError, TypeError)), ExceptionGroup[Exception] | None) From 0eaf7b894a102acf4713fb80304800182cd7f8ce Mon Sep 17 00:00:00 2001 From: sobolevn Date: Mon, 21 Nov 2022 16:35:32 +0300 Subject: [PATCH 06/11] Fix pyright --- test_cases/stdlib/builtins/check_exception_group.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test_cases/stdlib/builtins/check_exception_group.py b/test_cases/stdlib/builtins/check_exception_group.py index 260bb37771e0..45c150a9086f 100644 --- a/test_cases/stdlib/builtins/check_exception_group.py +++ b/test_cases/stdlib/builtins/check_exception_group.py @@ -226,7 +226,7 @@ class CustomBaseGroup(BaseExceptionGroup[_BE]): assert_type(cb2.subgroup((KeyboardInterrupt,)), BaseExceptionGroup[KeyboardInterrupt] | None) assert_type(cb1.subgroup(ValueError), ExceptionGroup[ValueError] | None) - assert_type(cb2.subgroup((KeyError, TypeError)), ExceptionGroup[Exception] | None) + assert_type(cb2.subgroup((KeyError,)), ExceptionGroup[KeyError] | None) def cb_subgroup1(exc: SystemExit | CustomBaseGroup[SystemExit]) -> bool: return True @@ -247,7 +247,7 @@ def cb_subgroup2(exc: ValueError | CustomBaseGroup[ValueError]) -> bool: ) assert_type(cb1.split(TypeError), tuple[ExceptionGroup[TypeError] | None, BaseExceptionGroup[SystemExit] | None]) assert_type( - cb2.split((TypeError, IndexError)), tuple[ExceptionGroup[Exception] | None, BaseExceptionGroup[ValueError] | None] + cb2.split((TypeError,)), tuple[ExceptionGroup[TypeError] | None, BaseExceptionGroup[ValueError] | None] ) def cb_split1(exc: SystemExit | CustomBaseGroup[SystemExit]) -> bool: @@ -289,7 +289,7 @@ class CustomGroup(ExceptionGroup[_E]): cg1.subgroup((KeyboardInterrupt, SystemExit)) # type: ignore assert_type(cg1.subgroup(ValueError), ExceptionGroup[ValueError] | None) - assert_type(cg1.subgroup((KeyError, TypeError)), ExceptionGroup[Exception] | None) + assert_type(cg1.subgroup((KeyError,)), ExceptionGroup[KeyError] | None) def cg_subgroup1(exc: ValueError | CustomGroup[ValueError]) -> bool: return True @@ -304,7 +304,7 @@ def cg_subgroup2(exc: ValueError) -> bool: # -------- assert_type(cg1.split(TypeError), tuple[ExceptionGroup[TypeError] | None, ExceptionGroup[ValueError] | None]) - assert_type(cg1.split((TypeError, IndexError)), tuple[ExceptionGroup[Exception] | None, ExceptionGroup[ValueError] | None]) + assert_type(cg1.split((TypeError,)), tuple[ExceptionGroup[TypeError] | None, ExceptionGroup[ValueError] | None]) cg1.split(BaseException) # type: ignore def cg_split1(exc: ValueError | CustomGroup[ValueError]) -> bool: From 7e57c9c3fd221be1704df017d8ba6ed7159d549e Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 21 Nov 2022 13:38:16 +0000 Subject: [PATCH 07/11] [pre-commit.ci] auto fixes from pre-commit.com hooks --- test_cases/stdlib/builtins/check_exception_group.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/test_cases/stdlib/builtins/check_exception_group.py b/test_cases/stdlib/builtins/check_exception_group.py index 45c150a9086f..da5b505fb99d 100644 --- a/test_cases/stdlib/builtins/check_exception_group.py +++ b/test_cases/stdlib/builtins/check_exception_group.py @@ -246,9 +246,7 @@ def cb_subgroup2(exc: ValueError | CustomBaseGroup[ValueError]) -> bool: cb1.split(KeyboardInterrupt), tuple[BaseExceptionGroup[KeyboardInterrupt] | None, BaseExceptionGroup[SystemExit] | None] ) assert_type(cb1.split(TypeError), tuple[ExceptionGroup[TypeError] | None, BaseExceptionGroup[SystemExit] | None]) - assert_type( - cb2.split((TypeError,)), tuple[ExceptionGroup[TypeError] | None, BaseExceptionGroup[ValueError] | None] - ) + assert_type(cb2.split((TypeError,)), tuple[ExceptionGroup[TypeError] | None, BaseExceptionGroup[ValueError] | None]) def cb_split1(exc: SystemExit | CustomBaseGroup[SystemExit]) -> bool: return True From aba41b985628130552996edf6e0d0c5fd2311e49 Mon Sep 17 00:00:00 2001 From: sobolevn Date: Mon, 21 Nov 2022 16:41:16 +0300 Subject: [PATCH 08/11] Fix flake8 --- .flake8 | 2 ++ test_cases/stdlib/builtins/check_exception_group.py | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.flake8 b/.flake8 index 87d3a985e0ad..0aa0d067df0a 100644 --- a/.flake8 +++ b/.flake8 @@ -38,6 +38,8 @@ per-file-ignores = # https://github.com/PyCQA/flake8/issues/1079 # F811 redefinition of unused '...' stdlib/typing.pyi: B, E301, E302, E305, E501, E701, E741, NQA102, F401, F403, F405, F811, F822, Y037 + # `ExceptionGroup` and `BaseExceptionGroup` are not recognised as builtins yet: + test_cases/stdlib/builtins/check_exception_group.py: F821, E203, E301, E302, E305, E501 # Generated protobuf files include docstrings *_pb2.pyi: B, E301, E302, E305, E501, E701, NQA102, Y021, Y026 diff --git a/test_cases/stdlib/builtins/check_exception_group.py b/test_cases/stdlib/builtins/check_exception_group.py index da5b505fb99d..83cb1ab4a998 100644 --- a/test_cases/stdlib/builtins/check_exception_group.py +++ b/test_cases/stdlib/builtins/check_exception_group.py @@ -95,7 +95,7 @@ def is_exception_or_beg(exc: Exception | BaseExceptionGroup[SystemExit]) -> bool # in the second part here because of that. assert_type( to_split.split(ValueError), - tuple[ExceptionGroup[ValueError] | None, BaseExceptionGroup[ValueError | KeyError | SystemExit] | None,], + tuple[ExceptionGroup[ValueError] | None, BaseExceptionGroup[ValueError | KeyError | SystemExit] | None], ) def split_callable1(exc: ValueError | KeyError | SystemExit | BaseExceptionGroup[ValueError | KeyError | SystemExit]) -> bool: From 7416e6ae0b3096557acaa7fc25accf3bccd675f6 Mon Sep 17 00:00:00 2001 From: sobolevn Date: Mon, 21 Nov 2022 17:07:41 +0300 Subject: [PATCH 09/11] Fix flake8 --- .flake8 | 2 -- test_cases/stdlib/builtins/check_exception_group.py | 4 ++++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.flake8 b/.flake8 index 0aa0d067df0a..87d3a985e0ad 100644 --- a/.flake8 +++ b/.flake8 @@ -38,8 +38,6 @@ per-file-ignores = # https://github.com/PyCQA/flake8/issues/1079 # F811 redefinition of unused '...' stdlib/typing.pyi: B, E301, E302, E305, E501, E701, E741, NQA102, F401, F403, F405, F811, F822, Y037 - # `ExceptionGroup` and `BaseExceptionGroup` are not recognised as builtins yet: - test_cases/stdlib/builtins/check_exception_group.py: F821, E203, E301, E302, E305, E501 # Generated protobuf files include docstrings *_pb2.pyi: B, E301, E302, E305, E501, E701, NQA102, Y021, Y026 diff --git a/test_cases/stdlib/builtins/check_exception_group.py b/test_cases/stdlib/builtins/check_exception_group.py index 83cb1ab4a998..d7e21ad36bfb 100644 --- a/test_cases/stdlib/builtins/check_exception_group.py +++ b/test_cases/stdlib/builtins/check_exception_group.py @@ -5,6 +5,10 @@ from typing_extensions import assert_type if sys.version_info >= (3, 11): + # This can be removed later, but right now `flake8` does not know + # about these two classes: + from builtins import BaseExceptionGroup, ExceptionGroup + # BaseExceptionGroup # ================== From caccf63ad5dfc7c0acd5db6ef8d2b409dbf5a9a9 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 21 Nov 2022 14:09:46 +0000 Subject: [PATCH 10/11] [pre-commit.ci] auto fixes from pre-commit.com hooks --- test_cases/stdlib/builtins/check_exception_group.py | 1 - 1 file changed, 1 deletion(-) diff --git a/test_cases/stdlib/builtins/check_exception_group.py b/test_cases/stdlib/builtins/check_exception_group.py index d7e21ad36bfb..c8a78de6c79a 100644 --- a/test_cases/stdlib/builtins/check_exception_group.py +++ b/test_cases/stdlib/builtins/check_exception_group.py @@ -11,7 +11,6 @@ # BaseExceptionGroup # ================== - # `BaseExceptionGroup` can work with `BaseException`: beg = BaseExceptionGroup("x", [SystemExit(), SystemExit()]) assert_type(beg, BaseExceptionGroup[SystemExit]) From 93a4638f9cdc15427db6c9265aa870530cd28188 Mon Sep 17 00:00:00 2001 From: AlexWaygood Date: Mon, 21 Nov 2022 16:59:17 +0000 Subject: [PATCH 11/11] Add the magic suffix to the test-case filename --- .../{check_exception_group.py => check_exception_group-py311.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename test_cases/stdlib/builtins/{check_exception_group.py => check_exception_group-py311.py} (100%) diff --git a/test_cases/stdlib/builtins/check_exception_group.py b/test_cases/stdlib/builtins/check_exception_group-py311.py similarity index 100% rename from test_cases/stdlib/builtins/check_exception_group.py rename to test_cases/stdlib/builtins/check_exception_group-py311.py