Skip to content

Commit 704dd18

Browse files
committed
Allow assignments to function definitions
This also fixes certain bogus errors about conditional imports/definitions of functions.
1 parent 5a0f7ec commit 704dd18

File tree

4 files changed

+78
-42
lines changed

4 files changed

+78
-42
lines changed

mypy/semanal.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1112,7 +1112,7 @@ def is_self_member_ref(self, memberexpr: MemberExpr) -> bool:
11121112
return isinstance(node, Var) and (cast(Var, node)).is_self
11131113

11141114
def check_lvalue_validity(self, node: Node, ctx: Context) -> None:
1115-
if isinstance(node, (FuncDef, TypeInfo, TypeVarExpr)):
1115+
if isinstance(node, (TypeInfo, TypeVarExpr)):
11161116
self.fail('Invalid assignment target', ctx)
11171117

11181118
def store_declared_types(self, lvalue: Node, typ: Type) -> None:

mypy/test/data/check-functions.test

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1174,3 +1174,15 @@ class A(Generic[t]):
11741174
def foo(self, x: t) -> None:
11751175
return None
11761176
[builtins fixtures/bool.py]
1177+
1178+
1179+
-- Redefining functions
1180+
-- --------------------
1181+
1182+
1183+
[case testRedefineFunction]
1184+
def f(x): pass
1185+
def g(x, y): pass
1186+
def h(y): pass
1187+
f = h
1188+
f = g # E: Incompatible types in assignment (expression has type Callable[[Any, Any], Any], variable has type Callable[[Any], Any])

mypy/test/data/check-modules.test

Lines changed: 65 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,6 @@ _m.f("hola")
144144
def f(c:str) -> None: pass
145145
[out]
146146

147-
148147
[case testImportWithStubIncompatibleType]
149148
import _m
150149
_m.f("hola")
@@ -472,8 +471,9 @@ x = 1
472471
[out]
473472

474473

475-
-- Conditional definitions
476-
-- -----------------------
474+
-- Conditional definitions and function redefinitions via module object
475+
-- --------------------------------------------------------------------
476+
477477

478478
[case testConditionalImportAndAssign]
479479
try:
@@ -543,6 +543,68 @@ except:
543543
def f(x): pass
544544
def g(x, y): pass
545545

546+
[case testImportVariableAndAssignNone]
547+
try:
548+
from m import x
549+
except:
550+
x = None
551+
[file m.py]
552+
x = 1
553+
554+
[case testImportFunctionAndAssignNone]
555+
try:
556+
from m import f
557+
except:
558+
f = None
559+
[file m.py]
560+
def f(): pass
561+
562+
[case testImportFunctionAndAssignFunction]
563+
def g(x): pass
564+
try:
565+
from m import f
566+
except:
567+
f = g
568+
[file m.py]
569+
def f(y): pass
570+
571+
[case testImportFunctionAndAssignIncompatible]
572+
try:
573+
from m import f
574+
except:
575+
f = 1 # E: Incompatible types in assignment (expression has type "int", variable has type Callable[[], Any])
576+
[file m.py]
577+
def f(): pass
578+
579+
[case testAssignToFuncDefViaGlobalDecl2]
580+
import typing
581+
from m import f
582+
def g() -> None:
583+
global f
584+
f = None
585+
f = 1 # E: Incompatible types in assignment (expression has type "int", variable has type Callable[[], Any])
586+
[file m.py]
587+
def f(): pass
588+
[out]
589+
main: note: In function "g":
590+
591+
[case testAssignToFuncDefViaNestedModules]
592+
import m.n
593+
m.n.f = None
594+
m.n.f = 1 # E: Incompatible types in assignment (expression has type "int", variable has type Callable[[], Any])
595+
[file m/__init__.py]
596+
[file m/n.py]
597+
def f(): pass
598+
[out]
599+
600+
[case testAssignToFuncDefViaModule]
601+
import m
602+
m.f = None
603+
m.f = 1 # E: Incompatible types in assignment (expression has type "int", variable has type Callable[[], Any])
604+
[file m.py]
605+
def f(): pass
606+
[out]
607+
546608

547609
-- Test cases that simulate 'mypy -m modname'
548610
--

mypy/test/data/semanal-errors.test

Lines changed: 0 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -786,44 +786,6 @@ class D(str): pass # ok
786786
class A(A): pass # E: Cycle in inheritance hierarchy
787787
[out]
788788

789-
[case testAssignToFuncDef]
790-
def f(): pass
791-
f = None # E: Invalid assignment target
792-
[out]
793-
794-
[case testAssignToFuncDefViaModule]
795-
import m
796-
m.f = None # E: Invalid assignment target
797-
[file m.py]
798-
def f(): pass
799-
[out]
800-
801-
[case testAssignToFuncDefViaNestedModules]
802-
import m.n
803-
m.n.f = None # E: Invalid assignment target
804-
[file m/__init__.py]
805-
[file m/n.py]
806-
def f(): pass
807-
[out]
808-
809-
[case testAssignToFuncDefViaImport]
810-
from m import f
811-
f = None # E: Invalid assignment target
812-
[file m.py]
813-
def f(): pass
814-
[out]
815-
816-
[case testAssignToFuncDefViaGlobalDecl2]
817-
import typing
818-
from m import f
819-
def g() -> None:
820-
global f
821-
f = None # E: Invalid assignment target
822-
[file m.py]
823-
def f(): pass
824-
[out]
825-
main: note: In function "g":
826-
827789
[case testAssignToTypeDef]
828790
import typing
829791
class A: pass

0 commit comments

Comments
 (0)