Skip to content

Commit 3f903f8

Browse files
committed
Turn --warn-no-return on by default
Fixes interaction with Generators. Fixes tests.
1 parent ed7d0c0 commit 3f903f8

14 files changed

+48
-16
lines changed

mypy/checker.py

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
Type, AnyType, CallableType, Void, FunctionLike, Overloaded, TupleType, TypedDictType,
3333
Instance, NoneTyp, ErrorType, strip_type, TypeType,
3434
UnionType, TypeVarId, TypeVarType, PartialType, DeletedType, UninhabitedType, TypeVarDef,
35-
true_only, false_only, function_type
35+
true_only, false_only, function_type, is_named_instance
3636
)
3737
from mypy.sametypes import is_same_type, is_same_types
3838
from mypy.messages import MessageBuilder
@@ -639,16 +639,22 @@ def is_implicit_any(t: Type) -> bool:
639639
self.accept(item.body)
640640
unreachable = self.binder.is_unreachable()
641641

642-
if (self.options.warn_no_return and not unreachable
643-
and not isinstance(self.return_types[-1], (Void, NoneTyp, AnyType))
644-
and (defn.is_coroutine or not defn.is_generator)):
645-
# Control flow fell off the end of a function that was
646-
# declared to return a non-None type.
647-
# Allow functions that are entirely pass/Ellipsis.
648-
if self.is_trivial_body(defn.body):
649-
pass
642+
if (self.options.warn_no_return and not unreachable):
643+
if (defn.is_generator or
644+
is_named_instance(self.return_types[-1], 'typing.AwaitableGenerator')):
645+
return_type = self.get_generator_return_type(self.return_types[-1],
646+
defn.is_coroutine)
650647
else:
651-
self.msg.note(messages.MISSING_RETURN_STATEMENT, defn)
648+
return_type = self.return_types[-1]
649+
650+
if not isinstance(return_type, (Void, NoneTyp, AnyType)):
651+
# Control flow fell off the end of a function that was
652+
# declared to return a non-None type.
653+
# Allow functions that are entirely pass/Ellipsis.
654+
if self.is_trivial_body(defn.body):
655+
pass
656+
else:
657+
self.msg.note(messages.MISSING_RETURN_STATEMENT, defn)
652658

653659
self.return_types.pop()
654660

mypy/main.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -219,8 +219,8 @@ def add_invertible_flag(flag: str,
219219
" --check-untyped-defs enabled")
220220
add_invertible_flag('--warn-redundant-casts', default=False, strict_flag=True,
221221
help="warn about casting an expression to its inferred type")
222-
add_invertible_flag('--warn-no-return', default=False,
223-
help="warn about functions that end without returning")
222+
add_invertible_flag('--no-warn-no-return', dest='warn_no_return', default=True,
223+
help="do not warn about functions that end without returning")
224224
add_invertible_flag('--warn-unused-ignores', default=False, strict_flag=True,
225225
help="warn about unneeded '# type: ignore' comments")
226226
add_invertible_flag('--show-error-context', default=True,

mypy/options.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ def __init__(self) -> None:
6363
self.warn_redundant_casts = False
6464

6565
# Warn about falling off the end of a function returning non-None
66-
self.warn_no_return = False
66+
self.warn_no_return = True
6767

6868
# Warn about unused '# type: ignore' comments
6969
self.warn_unused_ignores = False

test-data/samples/crawl.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -319,7 +319,7 @@ def close(self, recycle: bool = False) -> None:
319319
self.conn = None
320320

321321
@asyncio.coroutine
322-
def putline(self, line: str) -> Generator[Any, None, None]:
322+
def putline(self, line: str) -> None:
323323
"""Write a line to the connection.
324324
325325
Used for the request line and headers.

test-data/stdlib-samples/3.2/subprocess.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -784,6 +784,7 @@ def __exit__(self, type: type, value: BaseException,
784784
self.stdin.close()
785785
# Wait for the process to terminate, to avoid zombies.
786786
self.wait()
787+
return False
787788

788789
def __del__(self, _maxsize: int = sys.maxsize,
789790
_active: List['Popen'] = _active) -> None:

test-data/stdlib-samples/3.2/tempfile.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ def __stat(fn: str) -> object:
101101
except IOError:
102102
raise _os.error()
103103
f.close()
104+
return None
104105
_stat = __stat
105106

106107
def _exists(fn: str) -> bool:
@@ -421,6 +422,7 @@ def __exit__(self, exc: _Type[BaseException], value: BaseException,
421422
def __exit__(self, exc: _Type[BaseException], value: BaseException,
422423
tb: _Optional[_TracebackType]) -> bool:
423424
self.file.__exit__(exc, value, tb)
425+
return False
424426

425427

426428
def NamedTemporaryFile(mode: str = 'w+b', buffering: int = -1,
@@ -554,6 +556,7 @@ def __enter__(self) -> 'SpooledTemporaryFile':
554556
def __exit__(self, exc: type, value: BaseException,
555557
tb: _TracebackType) -> bool:
556558
self._file.close()
559+
return False
557560

558561
# file protocol
559562
def __iter__(self) -> _Iterable[_Any]:
@@ -690,6 +693,7 @@ def cleanup(self, _warn: bool = False) -> None:
690693
def __exit__(self, exc: type, value: BaseException,
691694
tb: _TracebackType) -> bool:
692695
self.cleanup()
696+
return False
693697

694698
def __del__(self) -> None:
695699
# Issue a ResourceWarning if implicit cleanup needed

test-data/unit/check-async-await.test

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ T = TypeVar('T')
6969
async def f(x: T) -> T:
7070
y = await f(x) # type: int
7171
reveal_type(y)
72+
return x
7273
[out]
7374
main:5: error: Argument 1 to "f" has incompatible type "T"; expected "int"
7475
main:6: error: Revealed type is 'builtins.int'
@@ -113,6 +114,7 @@ async def g() -> int:
113114
return 0
114115
async def f() -> str:
115116
x = await g() # type: str
117+
return x
116118
[builtins fixtures/async_await.pyi]
117119
[out]
118120
main:5: error: Incompatible types in assignment (expression has type "int", variable has type "str")

test-data/unit/check-classes.test

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -838,6 +838,7 @@ class A:
838838
def f(self) -> str:
839839
self.x = 1
840840
self.x = '' # E: Incompatible types in assignment (expression has type "str", variable has type "int")
841+
return ''
841842
[builtins fixtures/property.pyi]
842843
[out]
843844

test-data/unit/check-generics.test

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,7 @@ class A(Generic[T]):
250250
a = object() # Fail
251251
b = self.f() # type: object
252252
b = self.f()
253+
return None
253254
[out]
254255
main:5: error: Incompatible types in assignment (expression has type "object", variable has type "T")
255256
main:6: error: Incompatible types in assignment (expression has type "object", variable has type "T")

test-data/unit/check-incremental.test

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1553,6 +1553,7 @@ from funcs import callee
15531553
from classes import Outer
15541554
def caller(a: Outer.Inner) -> int:
15551555
callee(a)
1556+
return 0
15561557

15571558
[case testIncrementalLoadsParentAfterChild]
15581559
# cmd: mypy -m r.s

test-data/unit/check-statements.test

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,12 @@ def f() -> Generator[int, None, str]:
6161
return # E: Return value expected
6262
[out]
6363

64+
[case testNoReturnInGenerator]
65+
from typing import Generator
66+
def f() -> Generator[int, None, str]: # N: Missing return statement
67+
yield 1
68+
[out]
69+
6470
[case testEmptyReturnInNoneTypedGenerator]
6571
from typing import Generator
6672
def f() -> Generator[int, None, None]:
@@ -722,6 +728,7 @@ def f(*a: BaseException) -> int:
722728
except BaseException as err: pass
723729
try: pass
724730
except BaseException as err: f(err)
731+
return 0
725732
x = f()
726733
[builtins fixtures/exception.pyi]
727734

@@ -732,6 +739,7 @@ def f(*a: BaseException) -> int:
732739
x
733740
try: pass
734741
except BaseException as err: f(err)
742+
return 0
735743
x = f()
736744
[builtins fixtures/exception.pyi]
737745

@@ -742,6 +750,7 @@ def f(*a: BaseException) -> int:
742750
try: pass
743751
except BaseException as err: f(err)
744752
x
753+
return 0
745754
x = f()
746755
[builtins fixtures/exception.pyi]
747756

@@ -762,6 +771,7 @@ def f(*arg: BaseException) -> int:
762771
f(err)
763772
b = err.b
764773
reveal_type(b)
774+
return 0
765775
x = f()
766776
[builtins fixtures/exception.pyi]
767777
[out]
@@ -785,6 +795,7 @@ def f(*arg: BaseException) -> int:
785795
f(err)
786796
b = err.b
787797
reveal_type(b)
798+
return 0
788799
x = f()
789800
[builtins fixtures/exception.pyi]
790801
[out]
@@ -808,6 +819,7 @@ def f(*arg: BaseException) -> int:
808819
b = err.b
809820
reveal_type(b)
810821
x
822+
return 0
811823
x = f()
812824
[builtins fixtures/exception.pyi]
813825
[out]

test-data/unit/check-super.test

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ class A(B):
1515
a = super().f() # E: Incompatible types in assignment (expression has type "B", variable has type "A")
1616
a = super().g() # E: "g" undefined in superclass
1717
b = super().f()
18+
return a
1819
[out]
1920

2021
[case testAccessingSuperTypeMethodWithArgs]
@@ -85,7 +86,7 @@ class A:
8586
class B(A):
8687
def __new__(cls, x: int, y: str = '') -> 'A':
8788
super().__new__(cls, 1)
88-
super().__new__(cls, 1, '') # E: Too many arguments for "__new__" of "A"
89+
return super().__new__(cls, 1, '') # E: Too many arguments for "__new__" of "A"
8990
B('') # E: Argument 1 to "B" has incompatible type "str"; expected "int"
9091
B(1)
9192
B(1, 'x')

test-data/unit/check-typevar-values.test

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ def f(x: T) -> T:
9999
b = x
100100
a = '' # E: Incompatible types in assignment (expression has type "str", variable has type "int")
101101
b = 1 # E: Incompatible types in assignment (expression has type "int", variable has type "str")
102+
return x
102103
[out]
103104

104105
[case testIsinstanceAndTypeVarValues]
@@ -107,9 +108,11 @@ T = TypeVar('T', int, str)
107108
def f(x: T) -> T:
108109
if isinstance(x, int):
109110
return 2
111+
return x
110112
def g(x: T) -> T:
111113
if isinstance(x, str):
112114
return ''
115+
return x
113116
def h(x: T) -> T:
114117
if isinstance(x, int):
115118
return '' # E: Incompatible return value type (got "str", expected "int")

test-data/unit/typexport-basic.test

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -314,7 +314,7 @@ from typing import TypeVar, Generic
314314
T = TypeVar('T')
315315
class A(Generic[T]):
316316
def f(self) -> T:
317-
self.f()
317+
return self.f()
318318
[out]
319319
CallExpr(5) : T`1
320320
MemberExpr(5) : def () -> T`1

0 commit comments

Comments
 (0)