Skip to content

Commit 4423a49

Browse files
raymondbutcherilovelinuxpre-commit-ci[bot]gaborbernat
authored
Nullable required fields should not have default value (#2520)
Co-authored-by: Antonio Spadaro <ilovelinux@users.noreply.github.com> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Bernát Gábor <gaborjbernat@gmail.com> Co-authored-by: Bernát Gábor <bgabor8@bloomberg.net>
1 parent 590e568 commit 4423a49

7 files changed

Lines changed: 56 additions & 4 deletions

File tree

docs/cli-reference/model-customization.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3151,7 +3151,7 @@ for the generated code. Supported values include `pydantic.BaseModel`,
31513151
31523152
31533153
class MyObjItem(BaseModel):
3154-
items: list[Any] | None = None
3154+
items: list[Any] | None
31553155
31563156
31573157
class Model(BaseModel):

src/datamodel_code_generator/model/template/pydantic_v2/BaseModel.jinja2

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ class {{ class_name }}({{ base_class }}):{% if comment is defined %} # {{ comme
3232
{%- else %}
3333
{{ field.name }}: {{ field.type_hint }}
3434
{%- endif %}
35-
{%- if not field.has_default_factory_in_field and (not (field.required or (field.represented_default == 'None' and field.strip_default_none)) or field.data_type.is_optional)
35+
{%- if not field.has_default_factory_in_field and not field.required and (field.represented_default != 'None' or not field.strip_default_none or field.data_type.is_optional)
3636
%} = {{ field.represented_default }}
3737
{%- endif -%}
3838
{%- endif %}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111

1212
class MyObjItem(BaseModel):
13-
items: list[Any] | None = None
13+
items: list[Any] | None
1414

1515

1616
class Model(BaseModel):
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# generated by datamodel-codegen:
2+
# filename: nullable_required_annotated.yaml
3+
# timestamp: 2019-07-26T00:00:00+00:00
4+
5+
from __future__ import annotations
6+
7+
from typing import Annotated
8+
9+
from pydantic import BaseModel, Field
10+
11+
12+
class Person(BaseModel):
13+
first_name: Annotated[str | None, Field(alias='firstName')]
14+
last_name: Annotated[str | None, Field(alias='lastName')]

tests/data/expected/main/openapi/unquoted_null.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99

1010
class Thing(BaseModel):
11-
value: str | None = None
11+
value: str | None
1212

1313

1414
class NullThing(RootModel[None]):
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
openapi: 3.0.3
2+
info:
3+
version: 1.0.0
4+
title: Nullable Required Test
5+
description: Test case for nullable + required fields with Annotated
6+
paths: {}
7+
components:
8+
schemas:
9+
Person:
10+
type: object
11+
properties:
12+
firstName:
13+
type: string
14+
nullable: true
15+
lastName:
16+
type: string
17+
nullable: true
18+
required:
19+
- firstName
20+
- lastName

tests/main/openapi/test_main_openapi.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2691,6 +2691,24 @@ def test_main_openapi_nullable_31(output_file: Path) -> None:
26912691
)
26922692

26932693

2694+
def test_main_openapi_nullable_required_annotated(output_file: Path) -> None:
2695+
"""Test OpenAPI generation with nullable required fields using annotations."""
2696+
run_main_and_assert(
2697+
input_path=OPEN_API_DATA_PATH / "nullable_required_annotated.yaml",
2698+
output_path=output_file,
2699+
input_file_type="openapi",
2700+
assert_func=assert_file_content,
2701+
expected_file="nullable_required_annotated.py",
2702+
extra_args=[
2703+
"--output-model-type",
2704+
"pydantic_v2.BaseModel",
2705+
"--strict-nullable",
2706+
"--use-annotated",
2707+
"--snake-case-field",
2708+
],
2709+
)
2710+
2711+
26942712
@pytest.mark.cli_doc(
26952713
options=["--custom-file-header-path"],
26962714
input_schema="openapi/api.yaml",

0 commit comments

Comments
 (0)