diff --git a/mypy/semanal.py b/mypy/semanal.py index 86183704f680..8a29f66f05b5 100644 --- a/mypy/semanal.py +++ b/mypy/semanal.py @@ -1869,6 +1869,15 @@ def visit_import_from(self, imp: ImportFrom) -> None: continue if node and not node.module_hidden: + # expand into importing class, too... unless there's something already there. + # (deciding what expands is based on line order which cannot be checked here.) + if self.is_class_scope(): + assert self.type is not None + defn = node.node + if imported_id not in self.type.names.keys() and isinstance(defn, FuncDef): + if not defn.is_decorated and not defn.is_overload: + defn.info = self.type + self.add_symbol(defn.name, defn, imp) self.process_imported_symbol( node, module_id, id, imported_id, fullname, module_public, context=imp ) diff --git a/test-data/unit/check-classes.test b/test-data/unit/check-classes.test index b15f9f77f3c7..4a85c2ca0c36 100644 --- a/test-data/unit/check-classes.test +++ b/test-data/unit/check-classes.test @@ -6968,3 +6968,68 @@ class B(A): # E: Final class __main__.B has abstract attributes "foo" [case testUndefinedBaseclassInNestedClass] class C: class C1(XX): pass # E: Name "XX" is not defined + +[case testExpandImportedMethodInClass] +# https://github.com/python/mypy/issues/7045 +class Foo: + from a import meth + +reveal_type(Foo().meth) # N: Revealed type is "def (x: builtins.int) -> builtins.int" +[file a.py] +def meth(self, x: int) -> int: + ... + +[case testExpandImportedFunctionInClass] +class Foo: + from a import func + +reveal_type(Foo.func) # N: Revealed type is "def () -> builtins.str" +[file a.py] +def func() -> str: + ... + +[case testExpandImportedMethodInNestedClass] +class Foo: + class Bar: + from a import meth + +reveal_type(Foo.Bar().meth) # N: Revealed type is "def (x: builtins.int) -> builtins.int" +[file a.py] +def meth(self, x: int) -> int: + ... + +[case testExpandUndefinedImports] +class Foo: + from not_a_module import func + +reveal_type(Foo.func) +reveal_type(Foo().func) +[out] +main:2: error: Cannot find implementation or library stub for module named "not_a_module" +main:2: note: See https://mypy.readthedocs.io/en/stable/running_mypy.html#missing-imports +main:4: note: Revealed type is "Any" +main:5: note: Revealed type is "Any" + +[case testExpandImportedMethodWithFollowImports] +# flags: --follow-imports=skip +class Foo: + from a import meth + +reveal_type(Foo().meth) # N: Revealed type is "Any" +[file a.py] +def meth(self, x: int) -> int: + ... + +[case testExpandWithNonSelfFirstArgument] +class Foo: + from a import func + +reveal_type(Foo().func) +reveal_type(Foo.func) +[file a.py] +def func(self: str, x: int) -> int: + ... +[out] +main:4: error: Invalid self argument "Foo" to attribute function "func" with type "Callable[[str, int], int]" +main:4: note: Revealed type is "def (x: builtins.int) -> builtins.int" +main:5: note: Revealed type is "def (self: builtins.str, x: builtins.int) -> builtins.int"