Skip to content

Commit fd9728f

Browse files
authored
Fix allOf partial property overrides to inherit parent types instead of Any (#2654)
* Fix inheritance of parent field types for allOf partial overrides * Fix inherited field type resolution for allOf with partial overrides
1 parent 3eae20d commit fd9728f

5 files changed

Lines changed: 76 additions & 3 deletions

File tree

src/datamodel_code_generator/parser/jsonschema.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1519,6 +1519,24 @@ def _parse_object_common_part( # noqa: PLR0912, PLR0913
15191519
class_name=name,
15201520
)
15211521
)
1522+
if base_classes:
1523+
for field in fields:
1524+
current_type = field.data_type
1525+
field_name = field.original_name or field.name
1526+
if current_type and current_type.type == ANY and field_name:
1527+
inherited_type = self._get_inherited_field_type(field_name, base_classes)
1528+
if inherited_type is not None:
1529+
if PYDANTIC_V2:
1530+
new_type = inherited_type.model_copy(deep=True)
1531+
else:
1532+
new_type = inherited_type.copy(deep=True)
1533+
new_type.is_optional = new_type.is_optional or current_type.is_optional
1534+
new_type.is_dict = new_type.is_dict or current_type.is_dict
1535+
new_type.is_list = new_type.is_list or current_type.is_list
1536+
new_type.is_set = new_type.is_set or current_type.is_set
1537+
if new_type.kwargs is None and current_type.kwargs is not None: # pragma: no cover
1538+
new_type.kwargs = current_type.kwargs
1539+
field.data_type = new_type
15221540
# ignore an undetected object
15231541
if ignore_duplicate_model and not fields and len(base_classes) == 1:
15241542
with self.model_resolver.current_base_path_context(self.model_resolver._base_path): # noqa: SLF001

tests/data/expected/main/jsonschema/all_of_ref_with_property_override.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
from __future__ import annotations
66

7-
from typing import Any, Optional
7+
from typing import Optional
88

99
from pydantic import BaseModel, constr
1010

@@ -15,6 +15,6 @@ class Thing(BaseModel):
1515

1616

1717
class Person(Thing):
18-
type: Optional[Any] = 'playground:Person'
19-
name: Optional[Any] = None
18+
type: Optional[str] = 'playground:Person'
19+
name: Optional[constr(min_length=1)] = None
2020
age: Optional[int] = None
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: allof_partial_override_inherited_types.yaml
3+
# timestamp: 2019-07-26T00:00:00+00:00
4+
5+
from __future__ import annotations
6+
7+
from typing import Optional
8+
9+
from pydantic import BaseModel, Field
10+
11+
12+
class Thing(BaseModel):
13+
type: Optional[str] = None
14+
name: Optional[str] = Field(None, description='First and Last name')
15+
16+
17+
class Person(Thing):
18+
type: Optional[str] = 'playground:Person'
19+
name: str = Field(..., description='First and Last name')
20+
age: Optional[int] = None
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
openapi: "3.0.0"
2+
components:
3+
schemas:
4+
Thing:
5+
type: object
6+
properties:
7+
type:
8+
type: string
9+
name:
10+
type: string
11+
description: First and Last name
12+
Person:
13+
allOf:
14+
- $ref: "#/components/schemas/Thing"
15+
- type: object
16+
properties:
17+
type:
18+
default: playground:Person
19+
name:
20+
description: First and Last name
21+
age:
22+
type: integer
23+
required:
24+
- name

tests/main/openapi/test_main_openapi.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1719,6 +1719,17 @@ def test_main_openapi_allof_with_required_inherited_comprehensive(output_file: P
17191719
)
17201720

17211721

1722+
def test_main_openapi_allof_partial_override_inherited_types(output_file: Path) -> None:
1723+
"""Test OpenAPI allOf partial overrides inherit parent field types."""
1724+
run_main_and_assert(
1725+
input_path=OPEN_API_DATA_PATH / "allof_partial_override_inherited_types.yaml",
1726+
output_path=output_file,
1727+
input_file_type="openapi",
1728+
assert_func=assert_file_content,
1729+
expected_file="allof_partial_override_inherited_types.py",
1730+
)
1731+
1732+
17221733
def test_main_openapi_allof_with_required_inherited_edge_cases(output_file: Path) -> None:
17231734
"""Test OpenAPI generation with allOf edge cases for branch coverage."""
17241735
run_main_and_assert(

0 commit comments

Comments
 (0)