8000 Merge branch 'assign-none-to-module' · python/mypy@06fc68b · GitHub
[go: up one dir, main page]

Skip to content

Commit 06fc68b

Browse files
committed
Merge branch 'assign-none-to-module'
Partially addresses #649.
2 parents 747d8e9 + d7ff731 commit 06fc68b

File tree

3 files changed

+48
-3
lines changed

3 files changed

+48
-3
lines changed

mypy/checker.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1240,6 +1240,7 @@ def check_lvalue(self, lvalue: Node) -> Tuple[Type, IndexExpr, Var]:
12401240
if self.is_definition(lvalue):
12411241
if isinstance(lvalue, NameExpr):
12421242
inferred = cast(Var, lvalue.node)
1243+
assert isinstance(inferred, Var)
12431244
else:
12441245
m = cast(MemberExpr, lvalue)
12451246
self.accept(m.expr)

mypy/semanal.py

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2055,8 +2055,11 @@ def add_symbol(self, name: str, node: SymbolTableNode,
20552055
existing.node != node.node) and existing.kind != UNBOUND_IMPORTED:
20562056
# Modules can be imported multiple times to support import
20572057
# of multiple submodules of a package (e.g. a.x and a.y).
2058-
if not (existing.type and node.type and is_same_type(existing.type, node.type)):
2059-
# Only report an error if the symbol collision provides a different type.
2058+
ok = False
2059+
# Only report an error if the symbol collision provides a different type.
2060+
if existing.type and node.type and is_same_type(existing.type, node.type):
2061+
ok = True
2062+
if not ok:
20602063
self.name_already_defined(name, context)
20612064
self.globals[name] = node
20622065

@@ -2222,11 +2225,24 @@ def process_nested_classes(self, outer_def: ClassDef) -> None:
22222225
self.process_nested_classes(node)
22232226

22242227
def visit_import_from(self, node: ImportFrom) -> None:
2228+
# We can't bind module names during the first pass, as the target module might be
2229+
# unprocessed. However, we add dummy unbound imported names to the symbol table so
2230+
# that we at least know that the name refers to a module.
22252231
for name, as_name in node.names:
22262232
imported_name = as_name or name
22272233
if imported_name not in self.sem.globals:
22282234
self.sem.add_symbol(imported_name, SymbolTableNode(UNBOUND_IMPORTED, None), node)
22292235

2236+
def visit_import(self, node: Import) -> None:
2237+
# This is similar to visit_import_from -- see the comment there.
2238+
for id, as_id in node.ids:
2239+
imported_id = as_id or id
2240+
if imported_id not in self.sem.globals:
2241+
self.sem.add_symbol(imported_id, SymbolTableNode(UNBOUND_IMPORTED, None), node)
2242+
else:
2243+
# If the previous symbol is a variable, this should take precedence.
2244+
self.sem.globals[imported_id] = SymbolTableNode(UNBOUND_IMPORTED, None)
2245+
22302246
def visit_for_stmt(self, s: ForStmt) -> None:
22312247
self.analyze_lvalue(s.index)
22322248

mypy/test/data/check-modules.test

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -322,7 +322,6 @@ def xab(): pass
322322
[out]
323323
main:1: error: Cannot find module named 'xab'
324324
main:1: note: (Perhaps setting MYPYPATH would help)
325-
main:1: error: Name 'xab' already defined
326325

327326
[case testAccessingUnknownModuleFromOtherModule]
328327
import x
@@ -605,6 +604,35 @@ m.f = 1 # E: Incompatible types in assignment (expression has type "int", variab
605604
def f(): pass
606605
[out]
607606

607+
[case testConditionalImportAndAssignNoneToModule]
608+
if object():
609+
import m
610+
else:
611+
m = None
612+
m.f(1) # E: Argument 1 to "f" has incompatible type "int"; expected "str"
613+
[file m.py]
614+
def f(x: str) -> None: pass
615+
[builtins fixtures/module.py]
616+
[out]
617+
618+
[case testConditionalImportAndAssignInvalidToModule]
619+
if object():
620+
import m
621+
else:
622+
m = 1 # E: Incompatible types in assignment (expression has type "int", variable has type "module")
623+
[file m.py]
624+
[builtins fixtures/module.py]
625+
[out]
626+
627+
[case testImportAndAssignToModule]
628+
import m
629+
m = None
630+
m.f(1) # E: Argument 1 to "f" has incompatible type "int"; expected "str"
631+
[file m.py]
632+
def f(x: str) -> None: pass
633+
[builtins fixtures/module.py]
634+
[out]
635+
608636

609637
-- Test cases that simulate 'mypy -m modname'
610638
--

0 commit comments

Comments
 (0)
0