From 64157f1407c2d92efd245413a16519a2617214e8 Mon Sep 17 00:00:00 2001 From: hauntsaninja Date: Sat, 16 Sep 2023 16:38:29 -0700 Subject: [PATCH 1/4] Preserve implicitly exported types via attribute access Resolves #13965 --- mypy/checkmember.py | 14 +++++++++++++- test-data/unit/check-flags.test | 13 ++++++++++--- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/mypy/checkmember.py b/mypy/checkmember.py index 60430839ff62c..0df5ba024ade3 100644 --- a/mypy/checkmember.py +++ b/mypy/checkmember.py @@ -24,6 +24,7 @@ FuncDef, IndexExpr, MypyFile, + NameExpr, OverloadedFuncDef, SymbolNode, SymbolTable, @@ -608,7 +609,18 @@ def analyze_member_var_access( mx.msg.undefined_in_superclass(name, mx.context) return AnyType(TypeOfAny.from_error) else: - return report_missing_attribute(mx.original_type, itype, name, mx) + ret = report_missing_attribute(mx.original_type, itype, name, mx) + # Avoid paying double jeopardy if we can't find the member due to --no-implicit-reexport + if ( + mx.module_symbol_table is not None + and name in mx.module_symbol_table + and not mx.module_symbol_table[name].module_public + ): + v = mx.module_symbol_table[name].node + e = NameExpr(name) + e.node = v + return mx.chk.expr_checker.analyze_ref_expr(e, lvalue=mx.is_lvalue) + return ret def check_final_member(name: str, info: TypeInfo, msg: MessageBuilder, ctx: Context) -> None: diff --git a/test-data/unit/check-flags.test b/test-data/unit/check-flags.test index 96f78d81dd168..17aa921f07dc3 100644 --- a/test-data/unit/check-flags.test +++ b/test-data/unit/check-flags.test @@ -1611,14 +1611,21 @@ from other_module_2 import a # E: Module "other_module_2" does not explicitly e reveal_type(a) # N: Revealed type is "builtins.int" import other_module_2 -# TODO: this should also reveal builtins.int, see #13965 reveal_type(other_module_2.a) # E: "object" does not explicitly export attribute "a" [attr-defined] \ - # N: Revealed type is "Any" + # N: Revealed type is "builtins.int" + +from other_module_2 import b # E: Module "other_module_2" does not explicitly export attribute "b" [attr-defined] +reveal_type(b) # N: Revealed type is "def (a: builtins.int) -> builtins.str" + +import other_module_2 +reveal_type(other_module_2.b) # E: "object" does not explicitly export attribute "b" [attr-defined] \ + # N: Revealed type is "def (a: builtins.int) -> builtins.str" [file other_module_1.py] a = 5 +def b(a: int) -> str: ... [file other_module_2.py] -from other_module_1 import a +from other_module_1 import a, b [case testNoImplicitReexportRespectsAll] # flags: --no-implicit-reexport From 3cd1252b5f7be377607670a07313bd52ff8b1e62 Mon Sep 17 00:00:00 2001 From: hauntsaninja Date: Sat, 16 Sep 2023 17:15:00 -0700 Subject: [PATCH 2/4] . --- mypy/checkmember.py | 1 + test-data/unit/check-modules.test | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/mypy/checkmember.py b/mypy/checkmember.py index 0df5ba024ade3..798bcbede1bdc 100644 --- a/mypy/checkmember.py +++ b/mypy/checkmember.py @@ -618,6 +618,7 @@ def analyze_member_var_access( ): v = mx.module_symbol_table[name].node e = NameExpr(name) + e.set_line(mx.context) e.node = v return mx.chk.expr_checker.analyze_ref_expr(e, lvalue=mx.is_lvalue) return ret diff --git a/test-data/unit/check-modules.test b/test-data/unit/check-modules.test index 3da5996ed2742..f09649f40e9da 100644 --- a/test-data/unit/check-modules.test +++ b/test-data/unit/check-modules.test @@ -1862,7 +1862,8 @@ import stub reveal_type(stub.y) # N: Revealed type is "builtins.int" reveal_type(stub.z) # E: Module "stub" does not explicitly export attribute "z" \ - # N: Revealed type is "Any" + # N: Revealed type is "builtins.int" + [file stub.pyi] from substub import y as y From 6b9b50386badaf85f9cdb13d2c344be968d16b5a Mon Sep 17 00:00:00 2001 From: hauntsaninja Date: Sun, 17 Sep 2023 13:54:02 -0700 Subject: [PATCH 3/4] better fixture --- test-data/unit/check-flags.test | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test-data/unit/check-flags.test b/test-data/unit/check-flags.test index 17aa921f07dc3..c229fd7d45331 100644 --- a/test-data/unit/check-flags.test +++ b/test-data/unit/check-flags.test @@ -1611,14 +1611,14 @@ from other_module_2 import a # E: Module "other_module_2" does not explicitly e reveal_type(a) # N: Revealed type is "builtins.int" import other_module_2 -reveal_type(other_module_2.a) # E: "object" does not explicitly export attribute "a" [attr-defined] \ +reveal_type(other_module_2.a) # E: Module "other_module_2" does not explicitly export attribute "a" [attr-defined] \ # N: Revealed type is "builtins.int" from other_module_2 import b # E: Module "other_module_2" does not explicitly export attribute "b" [attr-defined] reveal_type(b) # N: Revealed type is "def (a: builtins.int) -> builtins.str" import other_module_2 -reveal_type(other_module_2.b) # E: "object" does not explicitly export attribute "b" [attr-defined] \ +reveal_type(other_module_2.b) # E: Module "other_module_2" does not explicitly export attribute "b" [attr-defined] \ # N: Revealed type is "def (a: builtins.int) -> builtins.str" [file other_module_1.py] @@ -1626,6 +1626,7 @@ a = 5 def b(a: int) -> str: ... [file other_module_2.py] from other_module_1 import a, b +[builtins fixtures/module.pyi] [case testNoImplicitReexportRespectsAll] # flags: --no-implicit-reexport From f8b1f0aae7aa6a74f1958d9de30dd327e6555df5 Mon Sep 17 00:00:00 2001 From: hauntsaninja Date: Sun, 17 Sep 2023 13:56:59 -0700 Subject: [PATCH 4/4] getattr test --- test-data/unit/check-flags.test | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/test-data/unit/check-flags.test b/test-data/unit/check-flags.test index c229fd7d45331..06b7cab8391ba 100644 --- a/test-data/unit/check-flags.test +++ b/test-data/unit/check-flags.test @@ -1657,11 +1657,15 @@ __all__ = ('b',) [case testNoImplicitReexportGetAttr] # flags: --no-implicit-reexport --python-version 3.7 from other_module_2 import a # E: Module "other_module_2" does not explicitly export attribute "a" +reveal_type(a) # N: Revealed type is "builtins.int" +from other_module_2 import b # E: Module "other_module_2" does not explicitly export attribute "b" +reveal_type(b) # N: Revealed type is "builtins.str" [file other_module_1.py] -from typing import Any -def __getattr__(name: str) -> Any: ... +b: str = "asdf" +def __getattr__(name: str) -> int: ... [file other_module_2.py] -from other_module_1 import a +from other_module_1 import a, b +def __getattr__(name: str) -> bytes: ... [builtins fixtures/tuple.pyi] [case textNoImplicitReexportSuggestions]