Skip to content

Commit 26b51e5

Browse files
drtyrsagvanrossum
authored andcommitted
Fix --warn-return-any for NotImplemented (#4545)
fixes #4534
1 parent 7ba2df4 commit 26b51e5

File tree

4 files changed

+84
-3
lines changed

4 files changed

+84
-3
lines changed

mypy/checker.py

+10-2
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@
5959
from mypy.meet import is_overlapping_types
6060
from mypy.options import Options
6161
from mypy.plugin import Plugin, CheckerPluginInterface
62+
from mypy.sharedparse import BINARY_MAGIC_METHODS
6263

6364
from mypy import experiments
6465

@@ -2179,8 +2180,11 @@ def check_return_stmt(self, s: ReturnStmt) -> None:
21792180
if isinstance(typ, AnyType):
21802181
# (Unless you asked to be warned in that case, and the
21812182
# function is not declared to return Any)
2182-
if (self.options.warn_return_any and not self.current_node_deferred and
2183-
not is_proper_subtype(AnyType(TypeOfAny.special_form), return_type)):
2183+
if (self.options.warn_return_any
2184+
and not self.current_node_deferred
2185+
and not is_proper_subtype(AnyType(TypeOfAny.special_form), return_type)
2186+
and not (defn.name() in BINARY_MAGIC_METHODS and
2187+
is_literal_not_implemented(s.expr))):
21842188
self.msg.incorrectly_returning_any(return_type, s)
21852189
return
21862190

@@ -3232,6 +3236,10 @@ def remove_optional(typ: Type) -> Type:
32323236
return typ
32333237

32343238

3239+
def is_literal_not_implemented(n: Expression) -> bool:
3240+
return isinstance(n, NameExpr) and n.fullname == 'builtins.NotImplemented'
3241+
3242+
32353243
def builtin_item_type(tp: Type) -> Optional[Type]:
32363244
"""Get the item type of a builtin container.
32373245

mypy/sharedparse.py

+46-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
"__delitem__",
1717
"__divmod__",
1818
"__div__",
19-
"__divmod__",
2019
"__enter__",
2120
"__exit__",
2221
"__eq__",
@@ -92,6 +91,52 @@
9291

9392
MAGIC_METHODS_POS_ARGS_ONLY = MAGIC_METHODS - MAGIC_METHODS_ALLOWING_KWARGS
9493

94+
BINARY_MAGIC_METHODS = {
95+
"__add__",
96+
"__and__",
97+
"__cmp__",
98+
"__divmod__",
99+
"__div__",
100+
"__eq__",
101+
"__floordiv__",
102+
"__ge__",
103+
"__gt__",
104+
"__iadd__",
105+
"__iand__",
106+
"__idiv__",
107+
"__ifloordiv__",
108+
"__ilshift__",
109+
"__imod__",
110+
"__imul__",
111+
"__ior__",
112+
"__ipow__",
113+
"__irshift__",
114+
"__isub__",
115+
"__ixor__",
116+
"__le__",
117+
"__lshift__",
118+
"__lt__",
119+
"__mod__",
120+
"__mul__",
121+
"__or__",
122+
"__pow__",
123+
"__radd__",
124+
"__rand__",
125+
"__rdiv__",
126+
"__rfloordiv__",
127+
"__rlshift__",
128+
"__rmod__",
129+
"__rmul__",
130+
"__ror__",
131+
"__rpow__",
132+
"__rrshift__",
133+
"__rshift__",
134+
"__rsub__",
135+
"__rxor__",
136+
"__sub__",
137+
"__xor__",
138+
}
139+
95140

96141
def special_function_elide_names(name: str) -> bool:
97142
return name in MAGIC_METHODS_POS_ARGS_ONLY

test-data/unit/check-warnings.test

+15
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,21 @@ def f() -> int: return g()
143143
[out]
144144
main:4: warning: Returning Any from function declared to return "int"
145145

146+
[case testReturnAnyForNotImplementedInBinaryMagicMethods]
147+
# flags: --warn-return-any
148+
class A:
149+
def __eq__(self, other: object) -> bool: return NotImplemented
150+
[builtins fixtures/notimplemented.pyi]
151+
[out]
152+
153+
[case testReturnAnyForNotImplementedInNormalMethods]
154+
# flags: --warn-return-any
155+
class A:
156+
def some(self) -> bool: return NotImplemented
157+
[builtins fixtures/notimplemented.pyi]
158+
[out]
159+
main:3: warning: Returning Any from function declared to return "bool"
160+
146161
[case testReturnAnyFromTypedFunctionWithSpecificFormatting]
147162
# flags: --warn-return-any
148163
from typing import Any, Tuple
+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# builtins stub used in NotImplemented related cases.
2+
from typing import Any, cast
3+
4+
5+
class object:
6+
def __init__(self) -> None: pass
7+
8+
class type: pass
9+
class function: pass
10+
class bool: pass
11+
class int: pass
12+
class str: pass
13+
NotImplemented = cast(Any, None)

0 commit comments

Comments
 (0)