Skip to content

Commit

Permalink
Merge pull request python#463 from yczhu/raise-from
Browse files Browse the repository at this point in the history
Implement raise from type checking
  • Loading branch information
JukkaL committed Oct 8, 2014
2 parents c15ba23 + 134ae8c commit afa127c
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 13 deletions.
31 changes: 18 additions & 13 deletions mypy/checker.py
Original file line number Diff line number Diff line change
Expand Up @@ -1328,19 +1328,24 @@ def visit_raise_stmt(self, s: RaiseStmt) -> Type:
"""Type check a raise statement."""
self.breaking_out = True
if s.expr:
typ = self.accept(s.expr)
if isinstance(typ, FunctionLike):
if typ.is_type_obj():
# Cases like "raise ExceptionClass".
typeinfo = typ.type_object()
base = self.lookup_typeinfo('builtins.BaseException')
if base in typeinfo.mro:
# Good!
return None
# Else fall back to the check below (which will fail).
self.check_subtype(typ,
self.named_type('builtins.BaseException'), s,
messages.INVALID_EXCEPTION)
self.type_check_raise(s.expr, s)
if s.from_expr:
self.type_check_raise(s.from_expr, s)

def type_check_raise(self, e: Node, s: RaiseStmt) -> None:
typ = self.accept(e)
if isinstance(typ, FunctionLike):
if typ.is_type_obj():
# Cases like "raise/from ExceptionClass".
typeinfo = typ.type_object()
base = self.lookup_typeinfo('builtins.BaseException')
if base in typeinfo.mro:
# Good!
return None
# Else fall back to the check below (which will fail).
self.check_subtype(typ,
self.named_type('builtins.BaseException'), s,
messages.INVALID_EXCEPTION)

def visit_try_stmt(self, s: TryStmt) -> Type:
"""Type check a try statement."""
Expand Down
2 changes: 2 additions & 0 deletions mypy/semanal.py
Original file line number Diff line number Diff line change
Expand Up @@ -993,6 +993,8 @@ def visit_return_stmt(self, s: ReturnStmt) -> None:
def visit_raise_stmt(self, s: RaiseStmt) -> None:
if s.expr:
s.expr.accept(self)
if s.from_expr:
s.from_expr.accept(self)

def visit_yield_stmt(self, s: YieldStmt) -> None:
if not self.is_func_scope():
Expand Down
24 changes: 24 additions & 0 deletions mypy/test/data/check-statements.test
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,30 @@ raise object # E: Exception must be derived from BaseException
raise f # E: Exception must be derived from BaseException
[builtins fixtures/exception.py]

[case testRaiseFromStatement]
from typing import Undefined
e = Undefined # type: BaseException
f = Undefined # type: MyError
a = Undefined # type: A
raise e from a # E: Exception must be derived from BaseException
raise e from e
raise e from f
class A: pass
class MyError(BaseException): pass
[builtins fixtures/exception.py]

[case testRaiseFromClassobject]
import typing
class A: pass
class MyError(BaseException): pass
def f(): pass
raise BaseException from BaseException
raise BaseException from MyError
raise BaseException from A # E: Exception must be derived from BaseException
raise BaseException from object # E: Exception must be derived from BaseException
raise BaseException from f # E: Exception must be derived from BaseException
[builtins fixtures/exception.py]

[case testTryFinallyStatement]
import typing
try:
Expand Down

0 comments on commit afa127c

Please sign in to comment.