Skip to content

Commit 7086f52

Browse files
authored
Fix: Resolve invalid imports in single file output by improving reference checks (#2604)
1 parent 0b7a21c commit 7086f52

4 files changed

Lines changed: 145 additions & 1 deletion

File tree

src/datamodel_code_generator/parser/base.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -792,6 +792,8 @@ def __change_from_import(
792792
scoped_model_resolver: ModelResolver,
793793
init: bool, # noqa: FBT001
794794
) -> None:
795+
model_paths = {model.path for model in models}
796+
795797
for model in models:
796798
scoped_model_resolver.add([model.path], model.class_name)
797799
for model in models:
@@ -800,7 +802,7 @@ def __change_from_import(
800802
for data_type in model.all_data_types:
801803
# To change from/import
802804

803-
if not data_type.reference or data_type.reference.source in models:
805+
if not data_type.reference or data_type.reference.path in model_paths:
804806
# No need to import non-reference model.
805807
# Or, Referenced model is in the same file. we don't need to import the model
806808
continue
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
# generated by datamodel-codegen:
2+
# filename: all_of_any_of_base_class_ref.json
3+
# timestamp: 2019-07-26T00:00:00+00:00
4+
5+
from __future__ import annotations
6+
7+
from typing import Optional, Union
8+
9+
from pydantic import BaseModel, Field, confloat
10+
11+
12+
class MapState1(BaseModel):
13+
map_view_mode: str = Field("MODE_2D", alias="mapViewMode", const=True)
14+
15+
16+
class MapState2(BaseModel):
17+
latitude: Latitude
18+
longitude: Longitude
19+
zoom: Optional[Zoom] = 0
20+
bearing: Optional[Bearing] = None
21+
pitch: Pitch
22+
drag_rotate: Optional[DragRotate] = Field(None, alias="dragRotate")
23+
map_split_mode: str = Field("SWIPE_COMPARE", alias="mapSplitMode", const=True)
24+
is_split: bool = Field(True, alias="isSplit", const=True)
25+
26+
27+
class MapState3(BaseModel):
28+
pass
29+
30+
31+
class MapState4(MapState1, MapState3):
32+
pass
33+
34+
35+
class MapState5(MapState2, MapState3):
36+
pass
37+
38+
39+
class MapState6(MapState4):
40+
pass
41+
42+
43+
class MapState7(MapState5):
44+
pass
45+
46+
47+
class MapState(BaseModel):
48+
__root__: Union[MapState4, MapState5, MapState6, MapState7] = Field(
49+
..., title="MapState"
50+
)
51+
52+
53+
class Bearing(BaseModel):
54+
__root__: float
55+
56+
57+
class DragRotate(BaseModel):
58+
__root__: bool
59+
60+
61+
class Latitude(BaseModel):
62+
__root__: confloat(ge=-90.0, le=90.0)
63+
64+
65+
class Longitude(BaseModel):
66+
__root__: confloat(ge=-180.0, le=180.0)
67+
68+
69+
class Pitch(BaseModel):
70+
__root__: confloat(ge=0.0, lt=90.0)
71+
72+
73+
class Zoom(BaseModel):
74+
__root__: confloat(ge=0.0, le=25.0)
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
{
2+
"$id": "https://example.com/schemas/MapState.json",
3+
"$schema": "http://json-schema.org/draft-07/schema#",
4+
"title": "MapState",
5+
"allOf": [
6+
{
7+
"anyOf": [
8+
{
9+
"type": "object",
10+
"properties": {
11+
"latitude": {"type": "number", "minimum": -90, "maximum": 90},
12+
"longitude": {"type": "number", "minimum": -180, "maximum": 180},
13+
"zoom": {"type": "number", "minimum": 0, "maximum": 25, "default": 0},
14+
"bearing": {"type": "number"},
15+
"pitch": {"type": "number", "minimum": 0, "exclusiveMaximum": 90},
16+
"dragRotate": {"type": "boolean"},
17+
"mapSplitMode": {"type": "string", "const": "SINGLE_MAP"},
18+
"isSplit": {"type": "boolean", "const": false, "default": false}
19+
},
20+
"required": ["latitude", "longitude", "pitch", "mapSplitMode"]
21+
},
22+
{
23+
"type": "object",
24+
"properties": {
25+
"latitude": {"$ref": "#/allOf/0/anyOf/0/properties/latitude"},
26+
"longitude": {"$ref": "#/allOf/0/anyOf/0/properties/longitude"},
27+
"zoom": {"$ref": "#/allOf/0/anyOf/0/properties/zoom"},
28+
"bearing": {"$ref": "#/allOf/0/anyOf/0/properties/bearing"},
29+
"pitch": {"$ref": "#/allOf/0/anyOf/0/properties/pitch"},
30+
"dragRotate": {"$ref": "#/allOf/0/anyOf/0/properties/dragRotate"},
31+
"mapSplitMode": {"type": "string", "const": "SWIPE_COMPARE"},
32+
"isSplit": {"type": "boolean", "const": true, "default": true}
33+
},
34+
"required": ["latitude", "longitude", "pitch", "mapSplitMode"]
35+
}
36+
]
37+
},
38+
{
39+
"anyOf": [
40+
{
41+
"type": "object",
42+
"properties": {
43+
"mapViewMode": {"type": "string", "const": "MODE_2D"}
44+
},
45+
"required": ["mapViewMode"]
46+
},
47+
{
48+
"type": "object",
49+
"properties": {
50+
"mapViewMode": {"type": "string", "const": "MODE_3D"}
51+
},
52+
"required": ["mapViewMode"]
53+
}
54+
]
55+
}
56+
]
57+
}

tests/main/jsonschema/test_main_jsonschema.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2024,6 +2024,17 @@ def test_main_all_of_any_of(output_dir: Path) -> None:
20242024
)
20252025

20262026

2027+
def test_main_all_of_any_of_base_class_ref(output_file: Path) -> None:
2028+
"""Test allOf/anyOf with base class references to avoid invalid imports."""
2029+
run_main_and_assert(
2030+
input_path=JSON_SCHEMA_DATA_PATH / "all_of_any_of_base_class_ref.json",
2031+
output_path=output_file,
2032+
input_file_type="jsonschema",
2033+
assert_func=assert_file_content,
2034+
extra_args=["--snake-case-field", "--use-double-quotes", "--reuse-model"],
2035+
)
2036+
2037+
20272038
def test_main_all_of_one_of(output_dir: Path) -> None:
20282039
"""Test combination of allOf and oneOf."""
20292040
run_main_and_assert(

0 commit comments

Comments
 (0)