Skip to content

Commit

Permalink
Preserve implicitly exported types via attribute access (#16129)
Browse files Browse the repository at this point in the history
Resolves #13965. Follow up to #13967. Unblocks #14086
  • Loading branch information
hauntsaninja authored Sep 19, 2023
1 parent 9b91524 commit 1dcff0d
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 9 deletions.
15 changes: 14 additions & 1 deletion mypy/checkmember.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
FuncDef,
IndexExpr,
MypyFile,
NameExpr,
OverloadedFuncDef,
SymbolNode,
SymbolTable,
Expand Down Expand Up @@ -608,7 +609,19 @@ 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.set_line(mx.context)
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:
Expand Down
26 changes: 19 additions & 7 deletions test-data/unit/check-flags.test
Original file line number Diff line number Diff line change
Expand Up @@ -1611,14 +1611,22 @@ 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"
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: 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]
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
[builtins fixtures/module.pyi]

[case testNoImplicitReexportRespectsAll]
# flags: --no-implicit-reexport
Expand Down Expand Up @@ -1649,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]
Expand Down
3 changes: 2 additions & 1 deletion test-data/unit/check-modules.test
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 1dcff0d

Please sign in to comment.