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
3 changes: 2 additions & 1 deletion docs/cli-reference/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ This documentation is auto-generated from test cases.
| Category | Options | Description |
|----------|---------|-------------|
| 📁 [Base Options](base-options.md) | 7 | Input/output configuration |
| 🔧 [Typing Customization](typing-customization.md) | 26 | Type annotation and import behavior |
| 🔧 [Typing Customization](typing-customization.md) | 27 | Type annotation and import behavior |
| 🏷️ [Field Customization](field-customization.md) | 22 | Field naming and docstring behavior |
| 🏗️ [Model Customization](model-customization.md) | 36 | Model generation behavior |
| 🎨 [Template Customization](template-customization.md) | 18 | Output formatting and custom rendering |
Expand All @@ -28,6 +28,7 @@ This documentation is auto-generated from test cases.
- [`--aliases`](field-customization.md#aliases)
- [`--all-exports-collision-strategy`](general-options.md#all-exports-collision-strategy)
- [`--all-exports-scope`](general-options.md#all-exports-scope)
- [`--allof-class-hierarchy`](typing-customization.md#allof-class-hierarchy)
- [`--allof-merge-mode`](typing-customization.md#allof-merge-mode)
- [`--allow-extra-fields`](model-customization.md#allow-extra-fields)
- [`--allow-population-by-field-name`](model-customization.md#allow-population-by-field-name)
Expand Down
2 changes: 2 additions & 0 deletions docs/cli-reference/quick-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ datamodel-codegen [OPTIONS]

| Option | Description |
|--------|-------------|
| [`--allof-class-hierarchy`](typing-customization.md#allof-class-hierarchy) | Controls how allOf schemas are represented in the generated class hierarchy. |
| [`--allof-merge-mode`](typing-customization.md#allof-merge-mode) | Merge constraints from root model references in allOf schemas. |
| [`--disable-future-imports`](typing-customization.md#disable-future-imports) | Prevent automatic addition of __future__ imports in generated code. |
| [`--enum-field-as-literal`](typing-customization.md#enum-field-as-literal) | Convert all enum fields to Literal types instead of Enum classes. |
Expand Down Expand Up @@ -198,6 +199,7 @@ All options sorted alphabetically:
- [`--aliases`](field-customization.md#aliases) - Apply custom field and class name aliases from JSON file.
- [`--all-exports-collision-strategy`](general-options.md#all-exports-collision-strategy) - Handle name collisions when exporting recursive module hiera...
- [`--all-exports-scope`](general-options.md#all-exports-scope) - Generate __all__ exports for child modules in __init__.py fi...
- [`--allof-class-hierarchy`](typing-customization.md#allof-class-hierarchy) - Controls how allOf schemas are represented in the generated ...
- [`--allof-merge-mode`](typing-customization.md#allof-merge-mode) - Merge constraints from root model references in allOf schema...
- [`--allow-extra-fields`](model-customization.md#allow-extra-fields) - Allow extra fields in generated Pydantic models (extra='allo...
- [`--allow-population-by-field-name`](model-customization.md#allow-population-by-field-name) - Allow Pydantic model population by field name (not just alia...
Expand Down
328 changes: 328 additions & 0 deletions docs/cli-reference/typing-customization.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

| Option | Description |
|--------|-------------|
| [`--allof-class-hierarchy`](#allof-class-hierarchy) | Controls how allOf schemas are represented in the generated ... |
| [`--allof-merge-mode`](#allof-merge-mode) | Merge constraints from root model references in allOf schema... |
| [`--disable-future-imports`](#disable-future-imports) | Prevent automatic addition of __future__ imports in generate... |
| [`--enum-field-as-literal`](#enum-field-as-literal) | Convert all enum fields to Literal types instead of Enum cla... |
Expand Down Expand Up @@ -33,6 +34,333 @@

---

## `--allof-class-hierarchy` {#allof-class-hierarchy}

Controls how allOf schemas are represented in the generated class hierarchy.
`--allof-class-hierarchy if-no-conflict` (default) creates parent classes for allOf schemas
only when there are no property conflicts between parent schemas. Otherwise, properties are merged into the child class
which is then decoupled from the parent classes and no longer inherits from them.
`--allof-class-hierarchy always` keeps class hierarchy for allOf schemas,
even in multiple inheritance scenarios where two parent schemas define the same property.

!!! tip "Usage"

```bash
datamodel-codegen --input schema.json --allof-class-hierarchy always # (1)!
```

1. :material-arrow-left: `--allof-class-hierarchy` - the option documented here

??? example "Examples"

**Input Schema:**

```json
{
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"StringDatatype": {
"description": "A base string type.",
"type": "string",
"pattern": "^\\S(.*\\S)?$"
},
"ConstrainedStringDatatype": {
"description": "A constrained string.",
"allOf": [
{ "$ref": "#/definitions/StringDatatype" },
{ "type": "string", "minLength": 1, "pattern": "^[A-Z].*" }
]
},
"IntegerDatatype": {
"description": "A whole number.",
"type": "integer"
},
"NonNegativeIntegerDatatype": {
"description": "Non-negative integer.",
"allOf": [
{ "$ref": "#/definitions/IntegerDatatype" },
{ "minimum": 0 }
]
},
"BoundedIntegerDatatype": {
"description": "Integer between 0 and 100.",
"allOf": [
{ "$ref": "#/definitions/IntegerDatatype" },
{ "minimum": 0, "maximum": 100 }
]
},
"EmailDatatype": {
"description": "Email with format.",
"allOf": [
{ "$ref": "#/definitions/StringDatatype" },
{ "format": "email" }
]
},
"FormattedStringDatatype": {
"description": "A string with email format.",
"type": "string",
"format": "email"
},
"ObjectBase": {
"type": "object",
"properties": {
"id": { "type": "integer" }
}
},
"ObjectWithAllOf": {
"description": "Object inheritance - not a root model.",
"allOf": [
{ "$ref": "#/definitions/ObjectBase" },
{ "type": "object", "properties": { "name": { "type": "string" } } }
]
},
"MultiRefAllOf": {
"description": "Multiple refs - not handled by new code.",
"allOf": [
{ "$ref": "#/definitions/StringDatatype" },
{ "$ref": "#/definitions/IntegerDatatype" }
]
},
"NoConstraintAllOf": {
"description": "No constraints added.",
"allOf": [
{ "$ref": "#/definitions/StringDatatype" }
]
},
"IncompatibleTypeAllOf": {
"description": "Incompatible types.",
"allOf": [
{ "$ref": "#/definitions/StringDatatype" },
{ "type": "boolean" }
]
},
"ConstraintWithProperties": {
"description": "Constraint item has properties.",
"allOf": [
{ "$ref": "#/definitions/StringDatatype" },
{ "properties": { "extra": { "type": "string" } } }
]
},
"ConstraintWithItems": {
"description": "Constraint item has items.",
"allOf": [
{ "$ref": "#/definitions/StringDatatype" },
{ "items": { "type": "string" } }
]
},
"NumberIntegerCompatible": {
"description": "Number and integer are compatible.",
"allOf": [
{ "$ref": "#/definitions/IntegerDatatype" },
{ "type": "number", "minimum": 0 }
]
},
"RefWithSchemaKeywords": {
"description": "Ref with additional schema keywords.",
"allOf": [
{ "$ref": "#/definitions/StringDatatype", "minLength": 5 },
{ "maxLength": 100 }
]
},
"ArrayDatatype": {
"type": "array",
"items": { "type": "string" }
},
"RefToArrayAllOf": {
"description": "Ref to array - not a root model.",
"allOf": [
{ "$ref": "#/definitions/ArrayDatatype" },
{ "minItems": 1 }
]
},
"ObjectNoPropsDatatype": {
"type": "object"
},
"RefToObjectNoPropsAllOf": {
"description": "Ref to object without properties - not a root model.",
"allOf": [
{ "$ref": "#/definitions/ObjectNoPropsDatatype" },
{ "minProperties": 1 }
]
},
"PatternPropsDatatype": {
"patternProperties": {
"^S_": { "type": "string" }
}
},
"RefToPatternPropsAllOf": {
"description": "Ref to patternProperties - not a root model.",
"allOf": [
{ "$ref": "#/definitions/PatternPropsDatatype" },
{ "minProperties": 1 }
]
},
"NestedAllOfDatatype": {
"allOf": [
{ "type": "string" },
{ "minLength": 1 }
]
},
"RefToNestedAllOfAllOf": {
"description": "Ref to nested allOf - not a root model.",
"allOf": [
{ "$ref": "#/definitions/NestedAllOfDatatype" },
{ "maxLength": 100 }
]
},
"ConstraintsOnlyDatatype": {
"description": "Constraints only, no type.",
"minLength": 1,
"pattern": "^[A-Z]"
},
"RefToConstraintsOnlyAllOf": {
"description": "Ref to constraints-only schema.",
"allOf": [
{ "$ref": "#/definitions/ConstraintsOnlyDatatype" },
{ "maxLength": 100 }
]
},
"NoDescriptionAllOf": {
"allOf": [
{ "$ref": "#/definitions/StringDatatype" },
{ "minLength": 5 }
]
},
"EmptyConstraintItemAllOf": {
"description": "AllOf with empty constraint item.",
"allOf": [
{ "$ref": "#/definitions/StringDatatype" },
{},
{ "maxLength": 50 }
]
},
"ConflictingFormatAllOf": {
"description": "Conflicting formats - falls back to existing behavior.",
"allOf": [
{ "$ref": "#/definitions/FormattedStringDatatype" },
{ "format": "date-time" }
]
}
},
"type": "object",
"properties": {
"name": { "$ref": "#/definitions/ConstrainedStringDatatype" },
"count": { "$ref": "#/definitions/NonNegativeIntegerDatatype" },
"percentage": { "$ref": "#/definitions/BoundedIntegerDatatype" },
"email": { "$ref": "#/definitions/EmailDatatype" },
"obj": { "$ref": "#/definitions/ObjectWithAllOf" },
"multi": { "$ref": "#/definitions/MultiRefAllOf" },
"noconstraint": { "$ref": "#/definitions/NoConstraintAllOf" },
"incompatible": { "$ref": "#/definitions/IncompatibleTypeAllOf" },
"withprops": { "$ref": "#/definitions/ConstraintWithProperties" },
"withitems": { "$ref": "#/definitions/ConstraintWithItems" },
"numint": { "$ref": "#/definitions/NumberIntegerCompatible" },
"refwithkw": { "$ref": "#/definitions/RefWithSchemaKeywords" },
"refarr": { "$ref": "#/definitions/RefToArrayAllOf" },
"refobjnoprops": { "$ref": "#/definitions/RefToObjectNoPropsAllOf" },
"refpatternprops": { "$ref": "#/definitions/RefToPatternPropsAllOf" },
"refnestedallof": { "$ref": "#/definitions/RefToNestedAllOfAllOf" },
"refconstraintsonly": { "$ref": "#/definitions/RefToConstraintsOnlyAllOf" },
"nodescription": { "$ref": "#/definitions/NoDescriptionAllOf" },
"emptyconstraint": { "$ref": "#/definitions/EmptyConstraintItemAllOf" },
"conflictingformat": { "$ref": "#/definitions/ConflictingFormatAllOf" }
}
}
```

**Output:**

=== "With Option"

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

from __future__ import annotations

from pydantic import BaseModel, Field, constr


class Entity(BaseModel):
type: str
type_list: list[str] | None = ['playground:Entity']


class Entity2(BaseModel):
type: str
type_list: list[str]


class Thing(Entity):
type: str
type_list: list[str]
name: constr(min_length=1) = Field(..., description='The things name')


class Location(Entity2):
type: str
type_list: list[str]
address: constr(min_length=5) = Field(
..., description='The address of the location'
)


class Person(Thing, Location):
name: constr(min_length=1) | None = Field(None, description="The person's name")
type: str
type_list: list[str]
```

=== "Without Option"

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

from __future__ import annotations

from typing import Any

from pydantic import BaseModel, Field, constr


class Person(BaseModel):
name: constr(min_length=1) = Field(..., description='The things name')
type: Any
type_list: list[Any]
address: constr(min_length=5) = Field(
..., description='The address of the location'
)


class Entity(BaseModel):
type: str
type_list: list[str] | None = ['playground:Entity']


class Entity2(BaseModel):
type: str
type_list: list[str]


class Thing(Entity):
type: str
type_list: list[str]
name: constr(min_length=1) = Field(..., description='The things name')


class Location(Entity2):
type: str
type_list: list[str]
address: constr(min_length=5) = Field(
..., description='The address of the location'
)
```

---

## `--allof-merge-mode` {#allof-merge-mode}

Merge constraints from root model references in allOf schemas.
Expand Down
Loading
Loading