Skip to content

Commit 8431860

Browse files
committed
Fix GraphQL empty list default handling
1 parent 912af8c commit 8431860

5 files changed

Lines changed: 38 additions & 17 deletions

File tree

src/datamodel_code_generator/model/pydantic/base_model.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,6 @@ def _get_strict_field_constraint_value(self, constraint: str, value: Any) -> Any
129129
def _get_default_as_pydantic_model(self) -> str | None: # noqa: PLR0911, PLR0912
130130
if isinstance(self.default, WrappedDefault):
131131
return f"lambda :{self.default!r}"
132-
# Handle the case where self.data_type.is_list is True directly (e.g., GraphQL)
133132
if self.data_type.is_list and len(self.data_type.data_types) == 1:
134133
data_type_child = self.data_type.data_types[0]
135134
if (
@@ -234,7 +233,7 @@ def __str__(self) -> str: # noqa: PLR0912
234233
elif isinstance(discriminator, dict): # pragma: no cover
235234
data["discriminator"] = discriminator["propertyName"]
236235

237-
if self.required:
236+
if self.required and not self.has_default:
238237
default_factory = None
239238
elif self.default is not UNDEFINED and self.default is not None and "default_factory" not in data:
240239
default_factory = self._get_default_as_pydantic_model()
@@ -263,7 +262,7 @@ def __str__(self) -> str: # noqa: PLR0912
263262

264263
if self.use_annotated:
265264
field_arguments = self._process_annotated_field_arguments(field_arguments)
266-
elif self.required:
265+
elif self.required and not default_factory:
267266
field_arguments = ["...", *field_arguments]
268267
elif not default_factory:
269268
default_repr = repr_set_sorted(self.default) if isinstance(self.default, set) else repr(self.default)

tests/data/expected/main/graphql/empty_list_default.py

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,27 @@
88

99
from pydantic import BaseModel, Field
1010

11+
type Boolean = bool
12+
"""
13+
The `Boolean` scalar type represents `true` or `false`.
14+
"""
15+
16+
17+
type String = str
18+
"""
19+
The `String` scalar type represents textual data, represented as UTF-8 character sequences. The String type is most often used by GraphQL to represent free-form human-readable text.
20+
"""
21+
1122

1223
class Container(BaseModel):
13-
name: str
24+
name: String
1425
typename__: Literal['Container'] | None = Field('Container', alias='__typename')
1526

1627

1728
class PodSpec(BaseModel):
1829
container_list: list[Container] = Field(default_factory=list)
1930
container_list_or_none: list[Container | None] = Field(default_factory=list)
20-
container_or_none_list_or_none: list[Container | None] | None = Field(default_factory=list)
21-
typename__: Literal['PodSpec'] | None = Field('PodSpec', alias='__typename')
31+
container_or_none_list_or_none: list[Container | None] | None = Field(
32+
default_factory=list
33+
)
34+
typename__: Literal['PodSpec'] | None = Field('PodSpec', alias='__typename')

tests/data/expected/main/graphql/pydantic_v2_empty_list_default.py

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,27 @@
88

99
from pydantic import BaseModel, Field
1010

11+
type Boolean = bool
12+
"""
13+
The `Boolean` scalar type represents `true` or `false`.
14+
"""
15+
16+
17+
type String = str
18+
"""
19+
The `String` scalar type represents textual data, represented as UTF-8 character sequences. The String type is most often used by GraphQL to represent free-form human-readable text.
20+
"""
21+
1122

1223
class Container(BaseModel):
13-
name: str
24+
name: String
1425
typename__: Literal['Container'] | None = Field('Container', alias='__typename')
1526

1627

1728
class PodSpec(BaseModel):
1829
container_list: list[Container] = Field(default_factory=list)
1930
container_list_or_none: list[Container | None] = Field(default_factory=list)
20-
container_or_none_list_or_none: list[Container | None] | None = Field(default_factory=list)
21-
typename__: Literal['PodSpec'] | None = Field('PodSpec', alias='__typename')
31+
container_or_none_list_or_none: list[Container | None] | None = Field(
32+
default_factory=list
33+
)
34+
typename__: Literal['PodSpec'] | None = Field('PodSpec', alias='__typename')

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

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,12 @@
44

55
from __future__ import annotations
66

7-
from typing import List, Optional
8-
97
from pydantic import BaseModel, Field
108

119

1210
class Container(BaseModel):
13-
name: Optional[str] = None
11+
name: str | None = None
1412

1513

1614
class PodSpec(BaseModel):
17-
containers: Optional[List[Container]] = Field(default_factory=list)
15+
containers: list[Container] | None = Field(default_factory=list)

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

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,12 @@
44

55
from __future__ import annotations
66

7-
from typing import List, Optional
8-
97
from pydantic import BaseModel, Field
108

119

1210
class Container(BaseModel):
13-
name: Optional[str] = None
11+
name: str | None = None
1412

1513

1614
class PodSpec(BaseModel):
17-
containers: Optional[List[Container]] = Field(default_factory=list)
15+
containers: list[Container] | None = Field(default_factory=list)

0 commit comments

Comments
 (0)