diff --git a/mypy/semanal.py b/mypy/semanal.py index adbd32ad51b1..ca24c33ef4ac 100644 --- a/mypy/semanal.py +++ b/mypy/semanal.py @@ -6091,10 +6091,14 @@ def visit_member_expr(self, expr: MemberExpr) -> None: elif isinstance(base.node, Var) and self.type and self.function_stack: # check for self.bar or cls.bar in method/classmethod func_def = self.function_stack[-1] - if not func_def.is_static and isinstance(func_def.type, CallableType): - formal_arg = func_def.type.argument_by_name(base.node.name) - if formal_arg and formal_arg.pos == 0: - type_info = self.type + if ( + func_def.has_self_or_cls_argument + and func_def.info is self.type + and isinstance(func_def.type, CallableType) + and func_def.arguments + and base.node is func_def.arguments[0].variable + ): + type_info = self.type elif isinstance(base.node, TypeAlias) and base.node.no_args: assert isinstance(base.node.target, ProperType) if isinstance(base.node.target, Instance): diff --git a/test-data/unit/check-classes.test b/test-data/unit/check-classes.test index 7e00017a088f..d9baaef55794 100644 --- a/test-data/unit/check-classes.test +++ b/test-data/unit/check-classes.test @@ -8328,6 +8328,37 @@ reveal_type(Foo.baz) # E: "type[Foo]" has no attribute "baz" \ foo: int def bar(x: int) -> int: ... +[case testClassScopeImportAccessibleInMethods] +class A: + import mod + from mod import var + + def __new__(cls) -> "A": + reveal_type(cls.mod) # N: Revealed type is "types.ModuleType" + reveal_type(cls.var) # N: Revealed type is "builtins.int" + reveal_type(cls.mod.var) # N: Revealed type is "builtins.int" + return cls() + + def pos_or_named_self(self) -> None: + reveal_type(self.mod) # N: Revealed type is "types.ModuleType" + reveal_type(self.var) # N: Revealed type is "builtins.int" + reveal_type(self.mod.var) # N: Revealed type is "builtins.int" + + def pos_only_self(self, /) -> None: + reveal_type(self.mod) # N: Revealed type is "types.ModuleType" + reveal_type(self.var) # N: Revealed type is "builtins.int" + reveal_type(self.mod.var) # N: Revealed type is "builtins.int" + + @classmethod + def clsmethod(cls) -> None: + reveal_type(cls.mod) # N: Revealed type is "types.ModuleType" + reveal_type(cls.var) # N: Revealed type is "builtins.int" + reveal_type(cls.mod.var) # N: Revealed type is "builtins.int" + +[file mod.py] +var = 1 +[builtins fixtures/module.pyi] + [case testClassScopeImportFunctionNested] class Foo: class Bar: diff --git a/test-data/unit/check-functions.test b/test-data/unit/check-functions.test index 55b87a27da34..b54dffe836b8 100644 --- a/test-data/unit/check-functions.test +++ b/test-data/unit/check-functions.test @@ -782,6 +782,19 @@ class A: # type: () -> None pass +[case testNestedFunctionInMethodCannotAccessEnclosingClassAttributes] +class A: + var: int + import mod + class B: ... + + def method(self) -> None: + def f1(arg: object) -> None: + arg.var # E: "object" has no attribute "var" + arg.mod # E: "object" has no attribute "mod" + arg.B # E: "object" has no attribute "B" +[file mod.py] + [case testDeepNestedFunctionWithTooFewArgumentsInTypeComment] class A: def f(self):