Skip to content

Commit

Permalink
fix: unpack unions inside tuples in except handlers
Browse files Browse the repository at this point in the history
  • Loading branch information
subnix committed Sep 12, 2024
1 parent 0c10367 commit eb5c51b
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 2 deletions.
13 changes: 11 additions & 2 deletions mypy/checker.py
Original file line number Diff line number Diff line change
Expand Up @@ -4858,16 +4858,25 @@ def get_types_from_except_handler(self, typ: Type, n: Expression) -> list[Type]:
"""Helper for check_except_handler_test to retrieve handler types."""
typ = get_proper_type(typ)
if isinstance(typ, TupleType):
return typ.items
# avoid recursion here, since we can accidentally unpack tuples inside
merged_type = make_simplified_union(typ.items)
if isinstance(merged_type, UnionType):
return merged_type.relevant_items()
return [merged_type]
elif isinstance(typ, UnionType):
# recursion is fine here for top-level Union
return [
union_typ
for item in typ.relevant_items()
for union_typ in self.get_types_from_except_handler(item, n)
]
elif is_named_instance(typ, "builtins.tuple"):
# variadic tuple
return [typ.args[0]]
# avoid recursion here too
merged_type = make_simplified_union((typ.args[0],))
if isinstance(merged_type, UnionType):
return merged_type.relevant_items()
return [merged_type]
else:
return [typ]

Expand Down
51 changes: 51 additions & 0 deletions test-data/unit/check-statements.test
Original file line number Diff line number Diff line change
Expand Up @@ -794,6 +794,57 @@ def error_in_variadic(exc: Tuple[int, ...]) -> None:

[builtins fixtures/tuple.pyi]

[case testExceptWithMultipleTypes5]
from typing import Tuple, Type, Union

class E1(BaseException): pass
class E2(BaseException): pass
class E3(BaseException): pass

def union_in_variadic(exc: Tuple[Union[Type[E1], Type[E2]], ...]) -> None:
try:
pass
except exc as e:
reveal_type(e) # N: Revealed type is "Union[__main__.E1, __main__.E2]"

def nested_union_in_variadic(exc: Tuple[Union[Type[E1], Union[Type[E2], Type[E3]]], ...]) -> None:
try:
pass
except exc as e:
reveal_type(e) # N: Revealed type is "Union[__main__.E1, __main__.E2, __main__.E3]"

def union_in_tuple(exc: Tuple[Union[Type[E1], Type[E2]], Type[E3]]) -> None:
try:
pass
except exc as e:
reveal_type(e) # N: Revealed type is "Union[__main__.E1, __main__.E2, __main__.E3]"

def error_in_variadic_union(exc: Tuple[Union[Type[E1], int], ...]) -> None:
try:
pass
except exc as e: # E: Exception type must be derived from BaseException (or be a tuple of exception classes)
pass

def error_in_variadic_nested_union(exc: Tuple[Union[Type[E1], Union[Type[E2], int]], ...]) -> None:
try:
pass
except exc as e: # E: Exception type must be derived from BaseException (or be a tuple of exception classes)
pass

def error_in_tuple_inside_variadic_nested_union(exc: Tuple[Union[Type[E1], Union[Type[E2], Tuple[Type[E3]]]], ...]) -> None:
try:
pass
except exc as e: # E: Exception type must be derived from BaseException (or be a tuple of exception classes)
pass

def error_in_tuple_union(exc: Tuple[Union[Type[E1], Type[E2]], Union[Type[E3], int]]) -> None:
try:
pass
except exc as e: # E: Exception type must be derived from BaseException (or be a tuple of exception classes)
pass

[builtins fixtures/tuple.pyi]

[case testExceptWithAnyTypes]
from typing import Any

Expand Down

0 comments on commit eb5c51b

Please sign in to comment.