Skip to content

Commit c987f59

Browse files
Add flag --use-default-keep-required-non-nullable
The aim is to provide a way to keep the field non nullable/optional when --use-default is used ```yaml Pet: required: - id - name properties: id: type: integer format: int64 default: 1 name: type: string tag: type: string ``` wil become: ```python class Pet(BaseModel): id: int = 1 name: str tag: str | None = None ``` instead of (current implementation): ```python class Pet(BaseModel): id: int | None = 1 name: str tag: str | None = None ```
1 parent f0960e9 commit c987f59

25 files changed

+692
-71
lines changed

docs/cli-reference/index.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ This documentation is auto-generated from test cases.
1111
| 📁 [Base Options](base-options.md) | 10 | Input/output configuration |
1212
| 🔧 [Typing Customization](typing-customization.md) | 29 | Type annotation and import behavior |
1313
| 🏷️ [Field Customization](field-customization.md) | 24 | Field naming and docstring behavior |
14-
| 🏗️ [Model Customization](model-customization.md) | 39 | Model generation behavior |
14+
| 🏗️ [Model Customization](model-customization.md) | 40 | Model generation behavior |
1515
| 🎨 [Template Customization](template-customization.md) | 21 | Output formatting and custom rendering |
1616
| 📘 [OpenAPI-only Options](openapi-only-options.md) | 7 | OpenAPI-specific features |
1717
| 📋 [GraphQL-only Options](graphql-only-options.md) | 1 | |
@@ -194,6 +194,7 @@ This documentation is auto-generated from test cases.
194194
- [`--use-decimal-for-multiple-of`](typing-customization.md#use-decimal-for-multiple-of)
195195
- [`--use-default`](model-customization.md#use-default)
196196
- [`--use-default-factory-for-optional-nested-models`](model-customization.md#use-default-factory-for-optional-nested-models)
197+
- [`--use-default-keep-required-non-nullable`](model-customization.md#use-default-keep-required-non-nullable)
197198
- [`--use-default-kwarg`](model-customization.md#use-default-kwarg)
198199
- [`--use-double-quotes`](template-customization.md#use-double-quotes)
199200
- [`--use-enum-values-in-discriminator`](field-customization.md#use-enum-values-in-discriminator)

docs/cli-reference/model-customization.md

Lines changed: 200 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
| [`--union-mode`](#union-mode) | Union mode for combining anyOf/oneOf schemas (smart or left_... |
3838
| [`--use-default`](#use-default) | Use default values from schema in generated models. |
3939
| [`--use-default-factory-for-optional-nested-models`](#use-default-factory-for-optional-nested-models) | Generate default_factory for optional nested model fields. |
40+
| [`--use-default-keep-required-non-nullable`](#use-default-keep-required-non-nullable) | When using default, keep required field non nullable/optiona... |
4041
| [`--use-default-kwarg`](#use-default-kwarg) | Use default= keyword argument instead of positional argument... |
4142
| [`--use-frozen-field`](#use-frozen-field) | Generate frozen (immutable) field definitions for readOnly p... |
4243
| [`--use-generic-base-class`](#use-generic-base-class) | Generate a shared base class with model configuration to avo... |
@@ -5292,38 +5293,115 @@ with their defaults, making them optional to provide when instantiating the mode
52925293

52935294
??? example "Examples"
52945295

5295-
**Input Schema:**
5296+
=== "OpenAPI"
52965297

5297-
```json
5298-
{
5299-
"$schema": "http://json-schema.org/draft-07/schema#",
5300-
"type": "object",
5301-
"title": "Use default with const",
5302-
"properties": {
5303-
"foo": {
5304-
"const": "foo"
5298+
**Input Schema:**
5299+
5300+
> **Error:** File not found: openapi/default_factory_keep_required_non_nullable.json
5301+
5302+
**Output:**
5303+
5304+
=== "Pydantic v2"
5305+
5306+
```python
5307+
# generated by datamodel-codegen:
5308+
# filename: default_factory_keep_required_non_nullable.yaml
5309+
# timestamp: 2019-07-26T00:00:00+00:00
5310+
5311+
from __future__ import annotations
5312+
5313+
from pydantic import BaseModel, Field, conint
5314+
5315+
5316+
class Data(BaseModel):
5317+
number: conint(ge=0) = Field(1, description='Number')
5318+
5319+
5320+
class Block(BaseModel):
5321+
data: Data
5322+
dataOptional: Data | None = None
5323+
```
5324+
5325+
=== "dataclass"
5326+
5327+
```python
5328+
# generated by datamodel-codegen:
5329+
# filename: default_factory_keep_required_non_nullable.yaml
5330+
# timestamp: 2019-07-26T00:00:00+00:00
5331+
5332+
from __future__ import annotations
5333+
5334+
from dataclasses import dataclass
5335+
5336+
5337+
@dataclass
5338+
class Data:
5339+
number: int = 1
5340+
5341+
5342+
@dataclass
5343+
class Block:
5344+
data: Data
5345+
dataOptional: Data | None = None
5346+
```
5347+
5348+
=== "msgspec"
5349+
5350+
```python
5351+
# generated by datamodel-codegen:
5352+
# filename: default_factory_keep_required_non_nullable.yaml
5353+
# timestamp: 2019-07-26T00:00:00+00:00
5354+
5355+
from __future__ import annotations
5356+
5357+
from typing import Annotated
5358+
5359+
from msgspec import UNSET, Meta, Struct, UnsetType
5360+
5361+
5362+
class Data(Struct):
5363+
number: Annotated[int, Meta(description='Number', ge=0)] = 1
5364+
5365+
5366+
class Block(Struct):
5367+
data: Data
5368+
dataOptional: Data | UnsetType = UNSET
5369+
```
5370+
5371+
=== "JSON Schema"
5372+
5373+
**Input Schema:**
5374+
5375+
```json
5376+
{
5377+
"$schema": "http://json-schema.org/draft-07/schema#",
5378+
"type": "object",
5379+
"title": "Use default with const",
5380+
"properties": {
5381+
"foo": {
5382+
"const": "foo"
5383+
}
53055384
}
53065385
}
5307-
}
5308-
```
5386+
```
53095387

5310-
**Output:**
5388+
**Output:**
53115389

5312-
```python
5313-
# generated by datamodel-codegen:
5314-
# filename: use_default_with_const.json
5315-
# timestamp: 2019-07-26T00:00:00+00:00
5316-
5317-
from __future__ import annotations
5318-
5319-
from typing import Literal
5320-
5321-
from pydantic import BaseModel
5322-
5323-
5324-
class UseDefaultWithConst(BaseModel):
5325-
foo: Literal['foo'] = 'foo'
5326-
```
5390+
```python
5391+
# generated by datamodel-codegen:
5392+
# filename: use_default_with_const.json
5393+
# timestamp: 2019-07-26T00:00:00+00:00
5394+
5395+
from __future__ import annotations
5396+
5397+
from typing import Literal
5398+
5399+
from pydantic import BaseModel
5400+
5401+
5402+
class UseDefaultWithConst(BaseModel):
5403+
foo: Literal['foo'] = 'foo'
5404+
```
53275405

53285406
---
53295407

@@ -5469,6 +5547,101 @@ for optional nested model fields instead of None default:
54695547

54705548
---
54715549

5550+
## `--use-default-keep-required-non-nullable` {#use-default-keep-required-non-nullable}
5551+
5552+
When using default, keep required field non nullable/optional.
5553+
5554+
The `--use-default-keep-required-non-nullable` flag keeps a required field
5555+
as non-nullale/optional:
5556+
- Dataclasses: `field: Model = field(Model)`
5557+
- Pydantic: `field: Model = Field(Model)`
5558+
- msgspec: `field: Model = field(Model)`
5559+
5560+
!!! tip "Usage"
5561+
5562+
```bash
5563+
datamodel-codegen --input schema.json --use-default --use-default-keep-required-non-nullable # (1)!
5564+
```
5565+
5566+
1. :material-arrow-left: `--use-default-keep-required-non-nullable` - the option documented here
5567+
5568+
??? example "Examples"
5569+
5570+
**Input Schema:**
5571+
5572+
> **Error:** File not found: openapi/default_factory_keep_required_non_nullable.json
5573+
5574+
**Output:**
5575+
5576+
=== "Pydantic v2"
5577+
5578+
```python
5579+
# generated by datamodel-codegen:
5580+
# filename: default_factory_keep_required_non_nullable.yaml
5581+
# timestamp: 2019-07-26T00:00:00+00:00
5582+
5583+
from __future__ import annotations
5584+
5585+
from pydantic import BaseModel, Field, conint
5586+
5587+
5588+
class Data(BaseModel):
5589+
number: conint(ge=0) = Field(1, description='Number')
5590+
5591+
5592+
class Block(BaseModel):
5593+
data: Data
5594+
dataOptional: Data | None = None
5595+
```
5596+
5597+
=== "dataclass"
5598+
5599+
```python
5600+
# generated by datamodel-codegen:
5601+
# filename: default_factory_keep_required_non_nullable.yaml
5602+
# timestamp: 2019-07-26T00:00:00+00:00
5603+
5604+
from __future__ import annotations
5605+
5606+
from dataclasses import dataclass
5607+
5608+
5609+
@dataclass
5610+
class Data:
5611+
number: int = 1
5612+
5613+
5614+
@dataclass
5615+
class Block:
5616+
data: Data
5617+
dataOptional: Data | None = None
5618+
```
5619+
5620+
=== "msgspec"
5621+
5622+
```python
5623+
# generated by datamodel-codegen:
5624+
# filename: default_factory_keep_required_non_nullable.yaml
5625+
# timestamp: 2019-07-26T00:00:00+00:00
5626+
5627+
from __future__ import annotations
5628+
5629+
from typing import Annotated
5630+
5631+
from msgspec import UNSET, Meta, Struct, UnsetType
5632+
5633+
5634+
class Data(Struct):
5635+
number: Annotated[int, Meta(description='Number', ge=0)] = 1
5636+
5637+
5638+
class Block(Struct):
5639+
data: Data
5640+
dataOptional: Data | UnsetType = UNSET
5641+
```
5642+
5643+
---
5644+
54725645
## `--use-default-kwarg` {#use-default-kwarg}
54735646

54745647
Use default= keyword argument instead of positional argument for fields with defaults.

docs/cli-reference/quick-reference.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ datamodel-codegen [OPTIONS]
127127
| [`--union-mode`](model-customization.md#union-mode) | Union mode for combining anyOf/oneOf schemas (smart or left_to_right). |
128128
| [`--use-default`](model-customization.md#use-default) | Use default values from schema in generated models. |
129129
| [`--use-default-factory-for-optional-nested-models`](model-customization.md#use-default-factory-for-optional-nested-models) | Generate default_factory for optional nested model fields. |
130+
| [`--use-default-keep-required-non-nullable`](model-customization.md#use-default-keep-required-non-nullable) | When using default, keep required field non nullable/optional. |
130131
| [`--use-default-kwarg`](model-customization.md#use-default-kwarg) | Use default= keyword argument instead of positional argument for fields with def... |
131132
| [`--use-frozen-field`](model-customization.md#use-frozen-field) | Generate frozen (immutable) field definitions for readOnly properties. |
132133
| [`--use-generic-base-class`](model-customization.md#use-generic-base-class) | Generate a shared base class with model configuration to avoid repetition (DRY). |
@@ -334,6 +335,7 @@ All options sorted alphabetically:
334335
- [`--use-decimal-for-multiple-of`](typing-customization.md#use-decimal-for-multiple-of) - Generate Decimal types for fields with multipleOf constraint...
335336
- [`--use-default`](model-customization.md#use-default) - Use default values from schema in generated models.
336337
- [`--use-default-factory-for-optional-nested-models`](model-customization.md#use-default-factory-for-optional-nested-models) - Generate default_factory for optional nested model fields.
338+
- [`--use-default-keep-required-non-nullable`](model-customization.md#use-default-keep-required-non-nullable) - When using default, keep required field non nullable/optiona...
337339
- [`--use-default-kwarg`](model-customization.md#use-default-kwarg) - Use default= keyword argument instead of positional argument...
338340
- [`--use-double-quotes`](template-customization.md#use-double-quotes) - Use double quotes for string literals in generated code.
339341
- [`--use-enum-values-in-discriminator`](field-customization.md#use-enum-values-in-discriminator) - Use enum values in discriminator mappings for union types.

0 commit comments

Comments
 (0)