diff --git a/docs/cli-reference/field-customization.md b/docs/cli-reference/field-customization.md index 81012eb79..25148a0e1 100644 --- a/docs/cli-reference/field-customization.md +++ b/docs/cli-reference/field-customization.md @@ -3585,14 +3585,14 @@ format as the default. # generated by datamodel-codegen: # filename: person.json # timestamp: 2019-07-26T00:00:00+00:00 - + from __future__ import annotations - + from typing import Any - + from pydantic import BaseModel, conint - - + + class Person(BaseModel): firstName: str | None = None """The person's first name.""" diff --git a/src/datamodel_code_generator/parser/base.py b/src/datamodel_code_generator/parser/base.py index dbdd933fb..8bc665072 100644 --- a/src/datamodel_code_generator/parser/base.py +++ b/src/datamodel_code_generator/parser/base.py @@ -2125,7 +2125,11 @@ def __collapse_root_models( # noqa: PLR0912, PLR0914, PLR0915 if isinstance(discriminator, dict) else discriminator ) - copied_data_type.discriminator = prop_name + field_name, _ = self.model_resolver.get_valid_field_name_and_alias( + field_name=prop_name, + model_type=self.field_name_model_type, + ) + copied_data_type.discriminator = field_name assert isinstance(data_type.parent, DataType) data_type.parent.data_types.remove(data_type) data_type.parent.data_types.append(copied_data_type) diff --git a/tests/data/expected/main/openapi/discriminator/in_array_snake_case_pydantic_v2.py b/tests/data/expected/main/openapi/discriminator/in_array_snake_case_pydantic_v2.py new file mode 100644 index 000000000..2cc69fce9 --- /dev/null +++ b/tests/data/expected/main/openapi/discriminator/in_array_snake_case_pydantic_v2.py @@ -0,0 +1,32 @@ +# generated by datamodel-codegen: +# filename: discriminator_in_array_snake_case.yaml +# timestamp: 2023-07-27T00:00:00+00:00 + +from __future__ import annotations + +from enum import StrEnum +from typing import Annotated, Literal + +from pydantic import BaseModel, Field + + +class ObjectType(StrEnum): + foo = 'FOO' + + +class FooType(BaseModel): + object_type: Annotated[Literal['FOO'], Field(alias='objectType')] + + +class ObjectType1(StrEnum): + bar = 'BAR' + + +class BarType(BaseModel): + object_type: Annotated[Literal['BAR'], Field(alias='objectType')] + + +class Container(BaseModel): + items: ( + list[Annotated[FooType | BarType, Field(discriminator='object_type')]] | None + ) = None diff --git a/tests/data/openapi/discriminator_in_array_snake_case.yaml b/tests/data/openapi/discriminator_in_array_snake_case.yaml new file mode 100644 index 000000000..70de0af48 --- /dev/null +++ b/tests/data/openapi/discriminator_in_array_snake_case.yaml @@ -0,0 +1,36 @@ +openapi: "3.0.0" +info: + title: Repro + version: "1.0" +paths: {} +components: + schemas: + FooType: + type: object + required: + - objectType + properties: + objectType: + type: string + enum: + - FOO + BarType: + type: object + required: + - objectType + properties: + objectType: + type: string + enum: + - BAR + Container: + type: object + properties: + items: + type: array + items: + discriminator: + propertyName: objectType + oneOf: + - $ref: "#/components/schemas/FooType" + - $ref: "#/components/schemas/BarType" diff --git a/tests/main/openapi/test_main_openapi.py b/tests/main/openapi/test_main_openapi.py index 5f14d238e..d47cebb2c 100644 --- a/tests/main/openapi/test_main_openapi.py +++ b/tests/main/openapi/test_main_openapi.py @@ -2576,6 +2576,29 @@ def test_main_openapi_discriminator_in_array_underscore(output_file: Path) -> No ) +@LEGACY_BLACK_SKIP +@freeze_time("2023-07-27") +def test_main_openapi_discriminator_in_array_snake_case(output_file: Path) -> None: + """Test collapsed list item discriminator uses snake_case field name.""" + run_main_and_assert( + input_path=OPEN_API_DATA_PATH / "discriminator_in_array_snake_case.yaml", + output_path=output_file, + input_file_type="openapi", + assert_func=assert_file_content, + expected_file="discriminator/in_array_snake_case_pydantic_v2.py", + extra_args=[ + "--target-python-version", + "3.12", + "--output-model-type", + "pydantic_v2.BaseModel", + "--use-annotated", + "--snake-case-field", + "--collapse-root-models", + ], + force_exec_validation=True, + ) + + @pytest.mark.parametrize( ("output_model", "expected_output"), [