Skip to content

Commit eb5c51b

Browse files
committed
fix: unpack unions inside tuples in except handlers
1 parent 0c10367 commit eb5c51b

File tree

2 files changed

+62
-2
lines changed

2 files changed

+62
-2
lines changed

mypy/checker.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4858,16 +4858,25 @@ def get_types_from_except_handler(self, typ: Type, n: Expression) -> list[Type]:
48584858
"""Helper for check_except_handler_test to retrieve handler types."""
48594859
typ = get_proper_type(typ)
48604860
if isinstance(typ, TupleType):
4861-
return typ.items
4861+
# avoid recursion here, since we can accidentally unpack tuples inside
4862+
merged_type = make_simplified_union(typ.items)
4863+
if isinstance(merged_type, UnionType):
4864+
return merged_type.relevant_items()
4865+
return [merged_type]
48624866
elif isinstance(typ, UnionType):
4867+
# recursion is fine here for top-level Union
48634868
return [
48644869
union_typ
48654870
for item in typ.relevant_items()
48664871
for union_typ in self.get_types_from_except_handler(item, n)
48674872
]
48684873
elif is_named_instance(typ, "builtins.tuple"):
48694874
# variadic tuple
4870-
return [typ.args[0]]
4875+
# avoid recursion here too
4876+
merged_type = make_simplified_union((typ.args[0],))
4877+
if isinstance(merged_type, UnionType):
4878+
return merged_type.relevant_items()
4879+
return [merged_type]
48714880
else:
48724881
return [typ]
48734882

test-data/unit/check-statements.test

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -794,6 +794,57 @@ def error_in_variadic(exc: Tuple[int, ...]) -> None:
794794

795795
[builtins fixtures/tuple.pyi]
796796

797+
[case testExceptWithMultipleTypes5]
798+
from typing import Tuple, Type, Union
799+
800+
class E1(BaseException): pass
801+
class E2(BaseException): pass
802+
class E3(BaseException): pass
803+
804+
def union_in_variadic(exc: Tuple[Union[Type[E1], Type[E2]], ...]) -> None:
805+
try:
806+
pass
807+
except exc as e:
808+
reveal_type(e) # N: Revealed type is "Union[__main__.E1, __main__.E2]"
809+
810+
def nested_union_in_variadic(exc: Tuple[Union[Type[E1], Union[Type[E2], Type[E3]]], ...]) -> None:
811+
try:
812+
pass
813+
except exc as e:
814+
reveal_type(e) # N: Revealed type is "Union[__main__.E1, __main__.E2, __main__.E3]"
815+
816+
def union_in_tuple(exc: Tuple[Union[Type[E1], Type[E2]], Type[E3]]) -> None:
817+
try:
818+
pass
819+
except exc as e:
820+
reveal_type(e) # N: Revealed type is "Union[__main__.E1, __main__.E2, __main__.E3]"
821+
822+
def error_in_variadic_union(exc: Tuple[Union[Type[E1], int], ...]) -> None:
823+
try:
824+
pass
825+
except exc as e: # E: Exception type must be derived from BaseException (or be a tuple of exception classes)
826+
pass
827+
828+
def error_in_variadic_nested_union(exc: Tuple[Union[Type[E1], Union[Type[E2], int]], ...]) -> None:
829+
try:
830+
pass
831+
except exc as e: # E: Exception type must be derived from BaseException (or be a tuple of exception classes)
832+
pass
833+
834+
def error_in_tuple_inside_variadic_nested_union(exc: Tuple[Union[Type[E1], Union[Type[E2], Tuple[Type[E3]]]], ...]) -> None:
835+
try:
836+
pass
837+
except exc as e: # E: Exception type must be derived from BaseException (or be a tuple of exception classes)
838+
pass
839+
840+
def error_in_tuple_union(exc: Tuple[Union[Type[E1], Type[E2]], Union[Type[E3], int]]) -> None:
841+
try:
842+
pass
843+
except exc as e: # E: Exception type must be derived from BaseException (or be a tuple of exception classes)
844+
pass
845+
846+
[builtins fixtures/tuple.pyi]
847+
797848
[case testExceptWithAnyTypes]
798849
from typing import Any
799850

0 commit comments

Comments
 (0)