Skip to content

Commit 29766b2

Browse files
authored
[mypyc] Fix unsupported imports for type annotations (#20390)
This is a follow up to #18874 which broke certain imports of type annotations. Fixes mypyc/mypyc#1099 Fixes mypyc/mypyc#1167 Fixes #20365 Closes mypyc/mypyc#1100
1 parent 0a6f9ab commit 29766b2

File tree

2 files changed

+35
-27
lines changed

2 files changed

+35
-27
lines changed

mypyc/irbuild/function.py

Lines changed: 5 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -858,11 +858,6 @@ def get_func_target(builder: IRBuilder, fdef: FuncDef) -> AssignmentTarget:
858858
return builder.add_local_reg(fdef, object_rprimitive)
859859

860860

861-
# This function still does not support the following imports.
862-
# import json as _json
863-
# from json import decoder
864-
# Using either _json.JSONDecoder or decoder.JSONDecoder as a type hint for a dataclass field will fail.
865-
# See issue mypyc/mypyc#1099.
866861
def load_type(builder: IRBuilder, typ: TypeInfo, unbounded_type: Type | None, line: int) -> Value:
867862
# typ.fullname contains the module where the class object was defined. However, it is possible
868863
# that the class object's module was not imported in the file currently being compiled. So, we
@@ -876,34 +871,17 @@ def load_type(builder: IRBuilder, typ: TypeInfo, unbounded_type: Type | None, li
876871
# `mod2.mod3.OuterClass.InnerClass` and `unbounded_type.name` is `mod1.OuterClass.InnerClass`.
877872
# So, we must use unbounded_type.name to load the class object.
878873
# See issue mypyc/mypyc#1087.
879-
load_attr_path = (
880-
unbounded_type.name if isinstance(unbounded_type, UnboundType) else typ.fullname
881-
).removesuffix(f".{typ.name}")
882874
if typ in builder.mapper.type_to_ir:
883875
class_ir = builder.mapper.type_to_ir[typ]
884876
class_obj = builder.builder.get_native_type(class_ir)
885877
elif typ.fullname in builtin_names:
886878
builtin_addr_type, src = builtin_names[typ.fullname]
887879
class_obj = builder.add(LoadAddress(builtin_addr_type, src, line))
888-
# This elif-condition finds the longest import that matches the load_attr_path.
889-
elif module_name := max(
890-
(i for i in builder.imports if load_attr_path == i or load_attr_path.startswith(f"{i}.")),
891-
default="",
892-
key=len,
893-
):
894-
# Load the imported module.
895-
loaded_module = builder.load_module(module_name)
896-
# Recursively load attributes of the imported module. These may be submodules, classes or
897-
# any other object.
898-
for attr in (
899-
load_attr_path.removeprefix(f"{module_name}.").split(".")
900-
if load_attr_path != module_name
901-
else []
902-
):
903-
loaded_module = builder.py_get_attr(loaded_module, attr, line)
904-
class_obj = builder.builder.get_attr(
905-
loaded_module, typ.name, object_rprimitive, line, borrow=False
906-
)
880+
elif isinstance(unbounded_type, UnboundType):
881+
path_parts = unbounded_type.name.split(".")
882+
class_obj = builder.load_global_str(path_parts[0], line)
883+
for attr in path_parts[1:]:
884+
class_obj = builder.py_get_attr(class_obj, attr, line)
907885
else:
908886
class_obj = builder.load_global_str(typ.name, line)
909887

mypyc/test-data/run-classes.test

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,36 @@ print(C.__annotations__["spam"] is JSONDecoder)
9595
True
9696
True
9797

98+
[case testTypedDictWithFieldsAs]
99+
import json as _json
100+
from typing import TypedDict
101+
102+
class C(TypedDict):
103+
spam: _json.JSONDecoder
104+
[file driver.py]
105+
from native import C
106+
from json import JSONDecoder
107+
108+
print(C.__annotations__["spam"] is JSONDecoder)
109+
[typing fixtures/typing-full.pyi]
110+
[out]
111+
True
112+
113+
[case testTypedDictWithFieldsFrom]
114+
from json import decoder
115+
from typing import TypedDict
116+
117+
class C(TypedDict):
118+
spam: decoder.JSONDecoder
119+
[file driver.py]
120+
from native import C
121+
from json import JSONDecoder
122+
123+
print(C.__annotations__["spam"] is JSONDecoder)
124+
[typing fixtures/typing-full.pyi]
125+
[out]
126+
True
127+
98128
[case testClassWithDeletableAttributes]
99129
from typing import Any, cast
100130
from testutil import assertRaises

0 commit comments

Comments
 (0)