Skip to content

Commit 1dcff0d

Browse files
authored
Preserve implicitly exported types via attribute access (#16129)
Resolves #13965. Follow up to #13967. Unblocks #14086
1 parent 9b91524 commit 1dcff0d

File tree

3 files changed

+35
-9
lines changed

3 files changed

+35
-9
lines changed

mypy/checkmember.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
FuncDef,
2525
IndexExpr,
2626
MypyFile,
27+
NameExpr,
2728
OverloadedFuncDef,
2829
SymbolNode,
2930
SymbolTable,
@@ -608,7 +609,19 @@ def analyze_member_var_access(
608609
mx.msg.undefined_in_superclass(name, mx.context)
609610
return AnyType(TypeOfAny.from_error)
610611
else:
611-
return report_missing_attribute(mx.original_type, itype, name, mx)
612+
ret = report_missing_attribute(mx.original_type, itype, name, mx)
613+
# Avoid paying double jeopardy if we can't find the member due to --no-implicit-reexport
614+
if (
615+
mx.module_symbol_table is not None
616+
and name in mx.module_symbol_table
617+
and not mx.module_symbol_table[name].module_public
618+
):
619+
v = mx.module_symbol_table[name].node
620+
e = NameExpr(name)
621+
e.set_line(mx.context)
622+
e.node = v
623+
return mx.chk.expr_checker.analyze_ref_expr(e, lvalue=mx.is_lvalue)
624+
return ret
612625

613626

614627
def check_final_member(name: str, info: TypeInfo, msg: MessageBuilder, ctx: Context) -> None:

test-data/unit/check-flags.test

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1611,14 +1611,22 @@ from other_module_2 import a # E: Module "other_module_2" does not explicitly e
16111611
reveal_type(a) # N: Revealed type is "builtins.int"
16121612

16131613
import other_module_2
1614-
# TODO: this should also reveal builtins.int, see #13965
1615-
reveal_type(other_module_2.a) # E: "object" does not explicitly export attribute "a" [attr-defined] \
1616-
# N: Revealed type is "Any"
1614+
reveal_type(other_module_2.a) # E: Module "other_module_2" does not explicitly export attribute "a" [attr-defined] \
1615+
# N: Revealed type is "builtins.int"
1616+
1617+
from other_module_2 import b # E: Module "other_module_2" does not explicitly export attribute "b" [attr-defined]
1618+
reveal_type(b) # N: Revealed type is "def (a: builtins.int) -> builtins.str"
1619+
1620+
import other_module_2
1621+
reveal_type(other_module_2.b) # E: Module "other_module_2" does not explicitly export attribute "b" [attr-defined] \
1622+
# N: Revealed type is "def (a: builtins.int) -> builtins.str"
16171623

16181624
[file other_module_1.py]
16191625
a = 5
1626+
def b(a: int) -> str: ...
16201627
[file other_module_2.py]
1621-
from other_module_1 import a
1628+
from other_module_1 import a, b
1629+
[builtins fixtures/module.pyi]
16221630

16231631
[case testNoImplicitReexportRespectsAll]
16241632
# flags: --no-implicit-reexport
@@ -1649,11 +1657,15 @@ __all__ = ('b',)
16491657
[case testNoImplicitReexportGetAttr]
16501658
# flags: --no-implicit-reexport --python-version 3.7
16511659
from other_module_2 import a # E: Module "other_module_2" does not explicitly export attribute "a"
1660+
reveal_type(a) # N: Revealed type is "builtins.int"
1661+
from other_module_2 import b # E: Module "other_module_2" does not explicitly export attribute "b"
1662+
reveal_type(b) # N: Revealed type is "builtins.str"
16521663
[file other_module_1.py]
1653-
from typing import Any
1654-
def __getattr__(name: str) -> Any: ...
1664+
b: str = "asdf"
1665+
def __getattr__(name: str) -> int: ...
16551666
[file other_module_2.py]
1656-
from other_module_1 import a
1667+
from other_module_1 import a, b
1668+
def __getattr__(name: str) -> bytes: ...
16571669
[builtins fixtures/tuple.pyi]
16581670

16591671
[case textNoImplicitReexportSuggestions]

test-data/unit/check-modules.test

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1862,7 +1862,8 @@ import stub
18621862

18631863
reveal_type(stub.y) # N: Revealed type is "builtins.int"
18641864
reveal_type(stub.z) # E: Module "stub" does not explicitly export attribute "z" \
1865-
# N: Revealed type is "Any"
1865+
# N: Revealed type is "builtins.int"
1866+
18661867

18671868
[file stub.pyi]
18681869
from substub import y as y

0 commit comments

Comments
 (0)