Skip to content

Commit 5afc4a2

Browse files
committed
Add support for tuple values on except clauses
Issue #1590
1 parent 529d098 commit 5afc4a2

File tree

2 files changed

+61
-9
lines changed

2 files changed

+61
-9
lines changed

mypy/checker.py

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1839,18 +1839,38 @@ def exception_type(self, n: Node) -> Type:
18391839
self.fail('Unsupported exception', n)
18401840
return AnyType()
18411841

1842+
def check_for_function_like_exception_type(self, type: Type, context: Context) -> Type:
1843+
if not isinstance(type, FunctionLike):
1844+
return None
1845+
1846+
item = type.items()[0]
1847+
ret = item.ret_type
1848+
if (is_subtype(ret, self.named_type('builtins.BaseException'))
1849+
and item.is_type_obj()):
1850+
return ret
1851+
else:
1852+
self.fail(messages.INVALID_EXCEPTION_TYPE, context)
1853+
return AnyType()
1854+
18421855
def check_exception_type(self, type: Type, context: Context) -> Type:
1843-
if isinstance(type, FunctionLike):
1844-
item = type.items()[0]
1845-
ret = item.ret_type
1846-
if (is_subtype(ret, self.named_type('builtins.BaseException'))
1847-
and item.is_type_obj()):
1848-
return ret
1849-
else:
1850-
self.fail(messages.INVALID_EXCEPTION_TYPE, context)
1851-
return AnyType()
1856+
ret = self.check_for_function_like_exception_type(type, context)
1857+
if ret is not None:
1858+
return ret
18521859
elif isinstance(type, AnyType):
18531860
return AnyType()
1861+
elif isinstance(type, TupleType):
1862+
t = None # type: Type
1863+
for item in type.items:
1864+
tt = self.check_for_function_like_exception_type(item, context)
1865+
1866+
if tt is None:
1867+
tt = AnyType()
1868+
1869+
if t:
1870+
t = join_types(t, tt)
1871+
else:
1872+
t = tt
1873+
return t
18541874
else:
18551875
self.fail(messages.INVALID_EXCEPTION_TYPE, context)
18561876
return AnyType()

mypy/test/data/check-statements.test

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -573,6 +573,8 @@ except (E1, E2) as e1:
573573
except (E2, E1) as e2:
574574
a = e2 # type: E1
575575
b = e2 # type: E2 # E: Incompatible types in assignment (expression has type "E1", variable has type "E2")
576+
except (E1, E2, int) as e3: # E: Exception type must be derived from BaseException
577+
pass
576578
[builtins fixtures/exception.py]
577579

578580
[case testReuseTryExceptionVariable]
@@ -618,6 +620,36 @@ except exc as e: pass # E: Exception type must be derived from BaseE
618620
except BaseException() as b: pass # E: Exception type must be derived from BaseException
619621
[builtins fixtures/exception.py]
620622

623+
[case testTupleValueAsExceptionType]
624+
import typing
625+
def exc() -> BaseException: pass
626+
class E1(BaseException): pass
627+
class E2(E1): pass
628+
class E3(E1): pass
629+
630+
exs1 = (E1, E2)
631+
try: pass
632+
except exs1 as e1:
633+
reveal_type(e1) # E: Revealed type is '__main__.E1'
634+
635+
exs3 = (E2, E3)
636+
try: pass
637+
except exs3 as e3:
638+
reveal_type(e3) # E: Revealed type is '__main__.E1'
639+
[builtins fixtures/exception.py]
640+
641+
[case testInvalidTupleValueAsExceptionType]
642+
import typing
643+
def exc() -> BaseException: pass
644+
class E1(BaseException): pass
645+
class E2(E1): pass
646+
class E3(E1): pass
647+
648+
exs1 = (E1, E2, int)
649+
try: pass
650+
except exs1 as e: pass # E: Exception type must be derived from BaseException
651+
[builtins fixtures/exception.py]
652+
621653
[case testOverloadedExceptionType]
622654
from typing import overload
623655
class E(BaseException):

0 commit comments

Comments
 (0)