Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 0 additions & 66 deletions docs/cli-reference/field-customization.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
| [`--field-extra-keys`](#field-extra-keys) | Include specific extra keys in Field() definitions. |
| [`--field-extra-keys-without-x-prefix`](#field-extra-keys-without-x-prefix) | Include specified schema extension keys in Field() without r... |
| [`--field-include-all-keys`](#field-include-all-keys) | Include all schema keys in Field() json_schema_extra. |
| [`--field-type-collision-strategy`](#field-type-collision-strategy) | Configure how to resolve naming conflicts between field name... |
| [`--no-alias`](#no-alias) | Disable Field alias generation for non-Python-safe property ... |
| [`--original-field-name-delimiter`](#original-field-name-delimiter) | Specify delimiter for original field names when using snake-... |
| [`--remove-special-field-name-prefix`](#remove-special-field-name-prefix) | Remove the special prefix from field names. |
Expand Down Expand Up @@ -1814,71 +1813,6 @@ The `--field-include-all-keys` flag configures the code generation behavior.

---

## `--field-type-collision-strategy` {#field-type-collision-strategy}

Configure how to resolve naming conflicts between field names and generated type names.

When a schema property name matches a generated type name (e.g., a property "Fruit" with
an enum type that would also be named "Fruit"), a collision occurs. This option controls
the resolution strategy:

- `rename-field` (default): Rename the field with a suffix (e.g., `Fruit_1`) and preserve
the original name via `Field(alias='Fruit')`
- `rename-type`: Rename the type class with a suffix (e.g., `Fruit_`) and keep the original
field name

!!! tip "Usage"

```bash
datamodel-codegen --input schema.json --output-model-type pydantic_v2.BaseModel --field-type-collision-strategy rename-type # (1)!
```

1. :material-arrow-left: `--field-type-collision-strategy` - the option documented here

??? example "Examples"

**Input Schema:**

```json
{
"title": "Test",
"type": "object",
"properties": {
"Fruit": {
"enum": [
"apple",
"banana"
]
}
}
}
```

**Output:**

```python
# generated by datamodel-codegen:
# filename: field_type_collision_rename_type.json
# timestamp: 2019-07-26T00:00:00+00:00

from __future__ import annotations

from enum import Enum

from pydantic import BaseModel


class Fruit_1(Enum):
apple = 'apple'
banana = 'banana'


class Test(BaseModel):
Fruit: Fruit_1 | None = None
```

---

## `--no-alias` {#no-alias}

Disable Field alias generation for non-Python-safe property names.
Expand Down
3 changes: 1 addition & 2 deletions docs/cli-reference/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ This documentation is auto-generated from test cases.
|----------|---------|-------------|
| 📁 [Base Options](base-options.md) | 5 | Input/output configuration |
| 🔧 [Typing Customization](typing-customization.md) | 17 | Type annotation and import behavior |
| 🏷️ [Field Customization](field-customization.md) | 21 | Field naming and docstring behavior |
| 🏷️ [Field Customization](field-customization.md) | 20 | Field naming and docstring behavior |
| 🏗️ [Model Customization](model-customization.md) | 29 | Model generation behavior |
| 🎨 [Template Customization](template-customization.md) | 16 | Output formatting and custom rendering |
| 📘 [OpenAPI-only Options](openapi-only-options.md) | 6 | OpenAPI-specific features |
Expand Down Expand Up @@ -75,7 +75,6 @@ This documentation is auto-generated from test cases.
- [`--field-extra-keys`](field-customization.md#field-extra-keys)
- [`--field-extra-keys-without-x-prefix`](field-customization.md#field-extra-keys-without-x-prefix)
- [`--field-include-all-keys`](field-customization.md#field-include-all-keys)
- [`--field-type-collision-strategy`](field-customization.md#field-type-collision-strategy)
- [`--force-optional`](model-customization.md#force-optional)
- [`--formatters`](template-customization.md#formatters)
- [`--frozen-dataclasses`](model-customization.md#frozen-dataclasses)
Expand Down
2 changes: 0 additions & 2 deletions docs/cli-reference/quick-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@ datamodel-codegen [OPTIONS]
| [`--field-extra-keys`](field-customization.md#field-extra-keys) | Include specific extra keys in Field() definitions. |
| [`--field-extra-keys-without-x-prefix`](field-customization.md#field-extra-keys-without-x-prefix) | Include specified schema extension keys in Field() without requiring 'x-' prefix... |
| [`--field-include-all-keys`](field-customization.md#field-include-all-keys) | Include all schema keys in Field() json_schema_extra. |
| [`--field-type-collision-strategy`](field-customization.md#field-type-collision-strategy) | Configure how to resolve naming conflicts between field names and generated type... |
| [`--no-alias`](field-customization.md#no-alias) | Disable Field alias generation for non-Python-safe property names. |
| [`--original-field-name-delimiter`](field-customization.md#original-field-name-delimiter) | Specify delimiter for original field names when using snake-case conversion. |
| [`--remove-special-field-name-prefix`](field-customization.md#remove-special-field-name-prefix) | Remove the special prefix from field names. |
Expand Down Expand Up @@ -207,7 +206,6 @@ All options sorted alphabetically:
- [`--field-extra-keys`](field-customization.md#field-extra-keys) - Include specific extra keys in Field() definitions.
- [`--field-extra-keys-without-x-prefix`](field-customization.md#field-extra-keys-without-x-prefix) - Include specified schema extension keys in Field() without r...
- [`--field-include-all-keys`](field-customization.md#field-include-all-keys) - Include all schema keys in Field() json_schema_extra.
- [`--field-type-collision-strategy`](field-customization.md#field-type-collision-strategy) - Configure how to resolve naming conflicts between field name...
- [`--force-optional`](model-customization.md#force-optional) - Force all fields to be Optional regardless of required statu...
- [`--formatters`](template-customization.md#formatters) - Specify code formatters to apply to generated output.
- [`--frozen-dataclasses`](model-customization.md#frozen-dataclasses) - Generate frozen dataclasses with optional keyword-only field...
Expand Down
14 changes: 0 additions & 14 deletions src/datamodel_code_generator/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -309,17 +309,6 @@ class ModuleSplitMode(Enum):
Single = "single"


class FieldTypeCollisionStrategy(Enum):
"""Strategy for handling field name and type name collisions in Pydantic v2.

RenameField: Rename the field with a suffix (e.g., Fruit_1) and add alias (default).
RenameType: Rename the type class with a suffix (e.g., Fruit_) to preserve field name.
"""

RenameField = "rename-field"
RenameType = "rename-type"


class Error(Exception):
"""Base exception for datamodel-code-generator errors."""

Expand Down Expand Up @@ -496,7 +485,6 @@ def generate( # noqa: PLR0912, PLR0913, PLR0914, PLR0915
all_exports_scope: AllExportsScope | None = None,
all_exports_collision_strategy: AllExportsCollisionStrategy | None = None,
module_split_mode: ModuleSplitMode | None = None,
field_type_collision_strategy: FieldTypeCollisionStrategy | None = None,
) -> None:
"""Generate Python data models from schema definitions or structured data.

Expand Down Expand Up @@ -742,7 +730,6 @@ def get_header_and_first_line(csv_file: IO[str]) -> dict[str, Any]:
dataclass_arguments=dataclass_arguments,
type_mappings=type_mappings,
read_only_write_only_model_type=read_only_write_only_model_type,
field_type_collision_strategy=field_type_collision_strategy,
**kwargs,
)

Expand Down Expand Up @@ -889,7 +876,6 @@ def infer_input_type(text: str) -> InputFileType:
"DatetimeClassType",
"DefaultPutDict",
"Error",
"FieldTypeCollisionStrategy",
"InputFileType",
"InvalidClassNameError",
"LiteralType",
Expand Down
3 changes: 0 additions & 3 deletions src/datamodel_code_generator/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@
DataclassArguments,
DataModelType,
Error,
FieldTypeCollisionStrategy,
InputFileType,
InvalidClassNameError,
ModuleSplitMode,
Expand Down Expand Up @@ -472,7 +471,6 @@ def validate_all_exports_collision_strategy(cls, values: dict[str, Any]) -> dict
all_exports_scope: Optional[AllExportsScope] = None # noqa: UP045
all_exports_collision_strategy: Optional[AllExportsCollisionStrategy] = None # noqa: UP045
module_split_mode: Optional[ModuleSplitMode] = None # noqa: UP045
field_type_collision_strategy: Optional[FieldTypeCollisionStrategy] = None # noqa: UP045
watch: bool = False
watch_delay: float = 0.5

Expand Down Expand Up @@ -780,7 +778,6 @@ def run_generate_from_config( # noqa: PLR0913, PLR0917
all_exports_scope=config.all_exports_scope,
all_exports_collision_strategy=config.all_exports_collision_strategy,
module_split_mode=config.module_split_mode,
field_type_collision_strategy=config.field_type_collision_strategy,
)


Expand Down
9 changes: 0 additions & 9 deletions src/datamodel_code_generator/arguments.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
AllOfMergeMode,
DataclassArguments,
DataModelType,
FieldTypeCollisionStrategy,
InputFileType,
ModuleSplitMode,
OpenAPIScope,
Expand Down Expand Up @@ -602,14 +601,6 @@ def start_section(self, heading: str | None) -> None:
choices=[u.value for u in UnionMode],
default=None,
)
field_options.add_argument(
"--field-type-collision-strategy",
help="Strategy for handling field name and type name collisions (Pydantic v2 only). "
"'rename-field': rename field with suffix and add alias (default). "
"'rename-type': rename type class with suffix to preserve field name.",
choices=[s.value for s in FieldTypeCollisionStrategy],
default=None,
)
field_options.add_argument(
"--no-alias",
help="""Do not add a field alias. E.g., if --snake-case-field is used along with a base class, which has an
Expand Down
3 changes: 0 additions & 3 deletions src/datamodel_code_generator/cli_options.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,9 +135,6 @@ class CLIOptionMeta:
"--use-enum-values-in-discriminator": CLIOptionMeta(
name="--use-enum-values-in-discriminator", category=OptionCategory.FIELD
),
"--field-type-collision-strategy": CLIOptionMeta(
name="--field-type-collision-strategy", category=OptionCategory.FIELD
),
# ==========================================================================
# Typing Customization
# ==========================================================================
Expand Down
35 changes: 10 additions & 25 deletions src/datamodel_code_generator/parser/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@
AllExportsScope,
AllOfMergeMode,
Error,
FieldTypeCollisionStrategy,
ModuleSplitMode,
ReadOnlyWriteOnlyModelType,
ReuseScope,
Expand Down Expand Up @@ -771,7 +770,6 @@ def __init__( # noqa: PLR0912, PLR0913, PLR0915
dataclass_arguments: DataclassArguments | None = None,
type_mappings: list[str] | None = None,
read_only_write_only_model_type: ReadOnlyWriteOnlyModelType | None = None,
field_type_collision_strategy: FieldTypeCollisionStrategy | None = None,
) -> None:
"""Initialize the Parser with configuration options."""
self.keyword_only = keyword_only
Expand Down Expand Up @@ -928,7 +926,6 @@ def __init__( # noqa: PLR0912, PLR0913, PLR0915
self.read_only_write_only_model_type: ReadOnlyWriteOnlyModelType | None = read_only_write_only_model_type
self.use_frozen_field: bool = use_frozen_field
self.use_default_factory_for_optional_nested_models: bool = use_default_factory_for_optional_nested_models
self.field_type_collision_strategy: FieldTypeCollisionStrategy | None = field_type_collision_strategy

@property
def field_name_model_type(self) -> ModelType:
Expand Down Expand Up @@ -1847,34 +1844,22 @@ def __change_field_name(
) -> None:
if not self.data_model_type.SUPPORTS_FIELD_RENAMING:
return

rename_type = self.field_type_collision_strategy == FieldTypeCollisionStrategy.RenameType

for model in models:
if "Enum" in model.base_class or not model.BASE_CLASS:
if "Enum" in model.base_class:
continue
if not model.BASE_CLASS:
continue

for field in model.fields:
filed_name = field.name
resolver = ModelResolver(snake_case_field=self.snake_case_field, remove_suffix_number=True)
colliding_reference: Reference | None = None
filed_name_resolver = ModelResolver(snake_case_field=self.snake_case_field, remove_suffix_number=True)
for data_type in field.data_type.all_data_types:
if not data_type.reference:
continue
resolver.exclude_names.add(data_type.reference.short_name)
if rename_type and colliding_reference is None and data_type.reference.short_name == filed_name:
colliding_reference = data_type.reference

if colliding_reference is not None:
source = cast("DataModel", colliding_reference.source)
resolver.exclude_names.add(cast("str", filed_name))
new_class_name = resolver.add(["type"], cast("str", source.class_name)).name
source.class_name = new_class_name
else:
new_filed_name = resolver.add(["field"], cast("str", filed_name)).name
if filed_name != new_filed_name:
field.alias = filed_name
field.name = new_filed_name
if data_type.reference:
filed_name_resolver.exclude_names.add(data_type.reference.short_name)
new_filed_name = filed_name_resolver.add(["field"], cast("str", filed_name)).name
if filed_name != new_filed_name:
field.alias = filed_name
field.name = new_filed_name

def __set_one_literal_on_default(self, models: list[DataModel]) -> None:
if not self.use_one_literal_as_default:
Expand Down
3 changes: 0 additions & 3 deletions src/datamodel_code_generator/parser/graphql.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
AllOfMergeMode,
DataclassArguments,
DefaultPutDict,
FieldTypeCollisionStrategy,
LiteralType,
PythonVersion,
PythonVersionMin,
Expand Down Expand Up @@ -194,7 +193,6 @@ def __init__( # noqa: PLR0913
use_serialize_as_any: bool = False,
use_frozen_field: bool = False,
use_default_factory_for_optional_nested_models: bool = False,
field_type_collision_strategy: FieldTypeCollisionStrategy | None = None,
) -> None:
"""Initialize the GraphQL parser with configuration options."""
super().__init__(
Expand Down Expand Up @@ -292,7 +290,6 @@ def __init__( # noqa: PLR0913
use_serialize_as_any=use_serialize_as_any,
use_frozen_field=use_frozen_field,
use_default_factory_for_optional_nested_models=use_default_factory_for_optional_nested_models,
field_type_collision_strategy=field_type_collision_strategy,
)

self.data_model_scalar_type = data_model_scalar_type
Expand Down
3 changes: 0 additions & 3 deletions src/datamodel_code_generator/parser/jsonschema.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
DEFAULT_SHARED_MODULE_NAME,
AllOfMergeMode,
DataclassArguments,
FieldTypeCollisionStrategy,
InvalidClassNameError,
ReadOnlyWriteOnlyModelType,
ReuseScope,
Expand Down Expand Up @@ -606,7 +605,6 @@ def __init__( # noqa: PLR0913
dataclass_arguments: DataclassArguments | None = None,
type_mappings: list[str] | None = None,
read_only_write_only_model_type: ReadOnlyWriteOnlyModelType | None = None,
field_type_collision_strategy: FieldTypeCollisionStrategy | None = None,
) -> None:
"""Initialize the JSON Schema parser with configuration options."""
target_datetime_class = target_datetime_class or DatetimeClassType.Awaredatetime
Expand Down Expand Up @@ -705,7 +703,6 @@ def __init__( # noqa: PLR0913
dataclass_arguments=dataclass_arguments,
type_mappings=type_mappings,
read_only_write_only_model_type=read_only_write_only_model_type,
field_type_collision_strategy=field_type_collision_strategy,
)

self.remote_object_cache: DefaultPutDict[str, dict[str, YamlValue]] = DefaultPutDict()
Expand Down
3 changes: 0 additions & 3 deletions src/datamodel_code_generator/parser/openapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
AllOfMergeMode,
DataclassArguments,
Error,
FieldTypeCollisionStrategy,
LiteralType,
OpenAPIScope,
PythonVersion,
Expand Down Expand Up @@ -278,7 +277,6 @@ def __init__( # noqa: PLR0913
use_frozen_field: bool = False,
use_default_factory_for_optional_nested_models: bool = False,
use_status_code_in_response_name: bool = False,
field_type_collision_strategy: FieldTypeCollisionStrategy | None = None,
) -> None:
"""Initialize the OpenAPI parser with extensive configuration options."""
target_datetime_class = target_datetime_class or DatetimeClassType.Awaredatetime
Expand Down Expand Up @@ -377,7 +375,6 @@ def __init__( # noqa: PLR0913
read_only_write_only_model_type=read_only_write_only_model_type,
use_frozen_field=use_frozen_field,
use_default_factory_for_optional_nested_models=use_default_factory_for_optional_nested_models,
field_type_collision_strategy=field_type_collision_strategy,
)
self.open_api_scopes: list[OpenAPIScope] = openapi_scopes or [OpenAPIScope.Schemas]
self.include_path_parameters: bool = include_path_parameters
Expand Down

This file was deleted.

This file was deleted.

Loading
Loading