Skip to content

Commit 4c27f8d

Browse files
authored
fix: retain imports with aliases during cleanup process (#2569)
1 parent 189fb45 commit 4c27f8d

7 files changed

Lines changed: 95 additions & 2 deletions

File tree

src/datamodel_code_generator/parser/base.py

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1341,6 +1341,39 @@ def __alias_shadowed_imports( # noqa: PLR6301
13411341
reference_path=model_field.data_type.import_.reference_path,
13421342
)
13431343

1344+
@classmethod
1345+
def _collect_used_names_from_models(cls, models: list[DataModel]) -> set[str]:
1346+
"""Collect identifiers referenced by models before rendering."""
1347+
names: set[str] = set()
1348+
1349+
def add(name: str | None) -> None:
1350+
if not name:
1351+
return
1352+
# first segment is sufficient to match import target or alias
1353+
names.add(name.split(".")[0])
1354+
1355+
def walk_data_type(data_type: DataType) -> None:
1356+
add(data_type.alias or data_type.type)
1357+
if data_type.reference:
1358+
add(data_type.reference.short_name)
1359+
for child in data_type.data_types:
1360+
walk_data_type(child)
1361+
if data_type.dict_key:
1362+
walk_data_type(data_type.dict_key)
1363+
1364+
for model in models:
1365+
add(model.class_name)
1366+
add(model.duplicate_class_name)
1367+
for base in model.base_classes:
1368+
add(base.type_hint)
1369+
for import_ in model.imports:
1370+
add(import_.alias or import_.import_.split(".")[-1])
1371+
for field in model.fields:
1372+
add(field.name)
1373+
add(field.alias)
1374+
walk_data_type(field.data_type)
1375+
return names
1376+
13441377
def parse( # noqa: PLR0912, PLR0914, PLR0915
13451378
self,
13461379
with_import: bool | None = True, # noqa: FBT001, FBT002
@@ -1466,12 +1499,14 @@ class Processed(NamedTuple):
14661499

14671500
for processed_model in processed_models:
14681501
# postprocess imports to remove unused imports.
1469-
model_code = str("\n".join([str(m) for m in processed_model.models]))
1502+
used_names = self._collect_used_names_from_models(processed_model.models)
14701503
unused_imports = [
14711504
(from_, import_)
14721505
for from_, imports_ in processed_model.imports.items()
14731506
for import_ in imports_
1474-
if import_ not in model_code
1507+
if not {processed_model.imports.alias.get(from_, {}).get(import_, import_), import_}.intersection(
1508+
used_names
1509+
)
14751510
]
14761511
for from_, import_ in unused_imports:
14771512
processed_model.imports.remove(Import(from_=from_, import_=import_))
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# generated by datamodel-codegen:
2+
# filename: alias_import_alias
3+
# timestamp: 2019-07-26T00:00:00+00:00
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# generated by datamodel-codegen:
2+
# filename: a.schema.json
3+
# timestamp: 2019-07-26T00:00:00+00:00
4+
5+
from __future__ import annotations
6+
7+
from pydantic import BaseModel
8+
9+
10+
class TypeA(BaseModel):
11+
value: str
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# generated by datamodel-codegen:
2+
# filename: b.schema.json
3+
# timestamp: 2019-07-26T00:00:00+00:00
4+
5+
from __future__ import annotations
6+
7+
from pydantic import BaseModel
8+
9+
from . import a_schema as a_schema_1
10+
11+
12+
class Container(BaseModel):
13+
a_schema: a_schema_1.TypeA
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"$schema": "http://json-schema.org/draft-07/schema#",
3+
"title": "TypeA",
4+
"type": "object",
5+
"properties": {
6+
"value": {
7+
"type": "string"
8+
}
9+
},
10+
"required": ["value"]
11+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"$schema": "http://json-schema.org/draft-07/schema#",
3+
"title": "Container",
4+
"type": "object",
5+
"properties": {
6+
"a_schema": {
7+
"$ref": "a.schema.json"
8+
}
9+
},
10+
"required": ["a_schema"]
11+
}

tests/main/jsonschema/test_main_jsonschema.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2405,6 +2405,15 @@ def test_main_invalid_import_name(output_dir: Path) -> None:
24052405
)
24062406

24072407

2408+
def test_main_alias_import_alias(output_dir: Path) -> None:
2409+
"""Ensure imports with aliases are retained after cleanup."""
2410+
run_main_and_assert(
2411+
input_path=JSON_SCHEMA_DATA_PATH / "alias_import_alias",
2412+
output_path=output_dir,
2413+
expected_directory=EXPECTED_JSON_SCHEMA_PATH / "alias_import_alias",
2414+
)
2415+
2416+
24082417
@pytest.mark.parametrize(
24092418
("output_model", "expected_output"),
24102419
[

0 commit comments

Comments
 (0)