diff --git a/mypy/semanal_pass1.py b/mypy/semanal_pass1.py index 07c0f7cab204..92018c9a223f 100644 --- a/mypy/semanal_pass1.py +++ b/mypy/semanal_pass1.py @@ -147,14 +147,20 @@ def visit_assignment_stmt(self, s: AssignmentStmt) -> None: for lval in s.lvalues: self.analyze_lvalue(lval, explicit_type=s.type is not None) - def visit_func_def(self, func: FuncDef) -> None: + def visit_func_def(self, func: FuncDef, decorated: bool = False) -> None: + """Process a func def. + + decorated is true if we are processing a func def in a + Decorator that needs a _fullname and to have its body analyzed but + does not need to be added to the symbol table. + """ sem = self.sem if sem.type is not None: # Don't process methods during pass 1. return func.is_conditional = sem.block_depth[-1] > 0 func._fullname = sem.qualified_name(func.name()) - at_module = sem.is_module_scope() + at_module = sem.is_module_scope() and not decorated if (at_module and func.name() == '__getattr__' and self.sem.cur_mod_node.is_package_init_file() and self.sem.cur_mod_node.is_stub): if isinstance(func.type, CallableType): @@ -311,6 +317,7 @@ def visit_decorator(self, d: Decorator) -> None: return d.var._fullname = self.sem.qualified_name(d.var.name()) self.add_symbol(d.var.name(), SymbolTableNode(self.kind_by_scope(), d), d) + self.visit_func_def(d.func, decorated=True) def visit_if_stmt(self, s: IfStmt) -> None: infer_reachability_of_if_statement(s, self.sem.options) diff --git a/test-data/unit/check-modules.test b/test-data/unit/check-modules.test index 9699fd084b55..36cd21b25189 100644 --- a/test-data/unit/check-modules.test +++ b/test-data/unit/check-modules.test @@ -733,6 +733,27 @@ import m.a [file m/a.py] [out] +[case testCheckDecoratedFuncAsAnnotWithImportCycle] +import a +[file a.py] +from typing import TypeVar +import b + +T = TypeVar('T') +def idf(x: T) -> T: return x + +@idf +def Session() -> None: pass + +[file b.py] +MYPY = False +if MYPY: + from a import Session + +def f(self, session: Session) -> None: # E: Invalid type "a.Session" + pass +[builtins fixtures/bool.pyi] + -- Checks dealing with submodules and different kinds of imports -- ------------------------------------------------------------- diff --git a/test-data/unit/check-unreachable-code.test b/test-data/unit/check-unreachable-code.test index 988038264d54..43de8a8b1eb4 100644 --- a/test-data/unit/check-unreachable-code.test +++ b/test-data/unit/check-unreachable-code.test @@ -416,6 +416,25 @@ x = 1 [builtins fixtures/ops.pyi] [out] +[case testSysPlatformInFunctionImport3] +from typing import Callable +import sys + +def idf(x: Callable[[], None]) -> Callable[[], None]: return x + +@idf +def foo() -> None: + if sys.platform == 'fictional': + import b as a + else: + import a + a.x +[file a.py] +x = 1 +[builtins fixtures/ops.pyi] +[out] + + [case testSysPlatformInMethodImport2] import sys class A: