Skip to content

Commit 5de9bf7

Browse files
authored
Fix allOf merging logic to handle single $ref inheritance with property overrides (#2647)
1 parent 737281a commit 5de9bf7

4 files changed

Lines changed: 65 additions & 1 deletion

File tree

src/datamodel_code_generator/parser/jsonschema.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1365,7 +1365,15 @@ def _schema_signature(self, prop_schema: JsonSchemaObject | bool) -> str | bool:
13651365
return json.dumps(prop_schema.dict(exclude_unset=True, by_alias=True), sort_keys=True, default=repr)
13661366

13671367
def _merge_all_of_object(self, obj: JsonSchemaObject) -> JsonSchemaObject | None:
1368-
"""Merge allOf items when they share object properties to avoid duplicate models."""
1368+
"""Merge allOf items when they share object properties to avoid duplicate models.
1369+
1370+
Skip merging when there is exactly one $ref (inheritance with property overrides).
1371+
Continue merging when multiple $refs share properties to avoid duplicate fields.
1372+
"""
1373+
ref_count = sum(1 for item in obj.allOf if item.ref)
1374+
if ref_count == 1:
1375+
return None
1376+
13691377
resolved_items: list[JsonSchemaObject] = []
13701378
property_signatures: dict[str, set[str | bool]] = {}
13711379
for item in obj.allOf:
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# generated by datamodel-codegen:
2+
# filename: all_of_ref_with_property_override.json
3+
# timestamp: 2019-07-26T00:00:00+00:00
4+
5+
from __future__ import annotations
6+
7+
from typing import Any, Optional
8+
9+
from pydantic import BaseModel, constr
10+
11+
12+
class Thing(BaseModel):
13+
type: str
14+
name: constr(min_length=1)
15+
16+
17+
class Person(Thing):
18+
type: Optional[Any] = 'playground:Person'
19+
name: Optional[Any] = None
20+
age: Optional[int] = None
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
{
2+
"$schema": "https://json-schema.org/draft/2020-12/schema",
3+
"$id": "https://example.com/person.schema.json",
4+
"title": "Person",
5+
"$defs": {
6+
"Thing": {
7+
"type": "object",
8+
"properties": {
9+
"type": { "type": "string" },
10+
"name": { "type": "string", "minLength": 1 }
11+
},
12+
"required": ["type", "name"]
13+
}
14+
},
15+
"type": "object",
16+
"allOf": [
17+
{ "$ref": "#/$defs/Thing" }
18+
],
19+
"properties": {
20+
"type": { "default": "playground:Person" },
21+
"name": { "minLength": 2 },
22+
"age": { "type": "integer" }
23+
}
24+
}

tests/main/jsonschema/test_main_jsonschema.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -936,6 +936,18 @@ def test_main_all_of_merge_boolean_property(output_file: Path) -> None:
936936
)
937937

938938

939+
def test_main_all_of_ref_with_property_override(output_file: Path) -> None:
940+
"""Test allOf with $ref preserves inheritance when properties are overridden."""
941+
with chdir(JSON_SCHEMA_DATA_PATH):
942+
run_main_and_assert(
943+
input_path=Path("all_of_ref_with_property_override.json"),
944+
output_path=output_file,
945+
input_file_type="jsonschema",
946+
assert_func=assert_file_content,
947+
expected_file="all_of_ref_with_property_override.py",
948+
)
949+
950+
939951
@pytest.mark.skipif(
940952
black.__version__.split(".")[0] >= "24",
941953
reason="Installed black doesn't support the old style",

0 commit comments

Comments
 (0)