Skip to content

Commit cab3215

Browse files
authored
Merge branch 'main' into fix-rootmodel-regex-engine
2 parents 167c75b + ad69407 commit cab3215

30 files changed

+641
-46
lines changed

docs/cli-reference/field-customization.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -585,7 +585,7 @@ The `--empty-enum-field-name` flag configures the code generation behavior.
585585
"\n",
586586
"\r\n",
587587
"\t",
588-
"\b",
588+
"\\x08",
589589
null,
590590
"\\"
591591
]
@@ -613,8 +613,8 @@ The `--empty-enum-field-name` flag configures the code generation behavior.
613613
field_ = '\n'
614614
field__ = '\r\n'
615615
field__1 = '\t'
616-
field__2 = '\b'
617-
field__3 = '\\'
616+
field_x08 = '\\x08'
617+
field__2 = '\\'
618618

619619

620620
class Model(BaseModel):
@@ -2225,7 +2225,7 @@ The `--special-field-name-prefix` flag configures the code generation behavior.
22252225
"\n",
22262226
"\r\n",
22272227
"\t",
2228-
"\b",
2228+
"\\x08",
22292229
null,
22302230
"\\"
22312231
]
@@ -2253,8 +2253,8 @@ The `--special-field-name-prefix` flag configures the code generation behavior.
22532253
special__1 = '\n'
22542254
special__ = '\r\n'
22552255
special__2 = '\t'
2256-
special__3 = '\b'
2257-
special__4 = '\\'
2256+
special_x08 = '\\x08'
2257+
special__3 = '\\'
22582258

22592259

22602260
class Model(BaseModel):

docs/cli-reference/model-customization.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2671,9 +2671,9 @@ Generate dataclasses with keyword-only fields (Python 3.10+).
26712671

26722672
The `--keyword-only` flag generates dataclasses where all fields must be
26732673
specified as keyword arguments (kw_only=True). This is only available for
2674-
Python 3.10+. When combined with `--frozen`, it creates immutable dataclasses
2675-
with keyword-only arguments, improving code clarity and preventing positional
2676-
argument errors.
2674+
Python 3.10+. When combined with `--frozen-dataclasses`, it creates immutable
2675+
dataclasses with keyword-only arguments, improving code clarity and preventing
2676+
positional argument errors.
26772677

26782678
**Related:** [`--frozen-dataclasses`](model-customization.md#frozen-dataclasses), [`--output-model-type`](model-customization.md#output-model-type), [`--target-python-version`](model-customization.md#target-python-version)
26792679

docs/cli-reference/template-customization.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1255,7 +1255,7 @@ The `--disable-timestamp` flag configures the code generation behavior.
12551255
},
12561256
"comment": {
12571257
"type": "string",
1258-
"pattern": "[^\b\f\n\r\t\\\\a+.?'\"|()]+$"
1258+
"pattern": "[^\\x08\\f\\n\\r\\t\\\\a+.?'\"|()]+$"
12591259
}
12601260
}
12611261
}
@@ -1283,7 +1283,7 @@ The `--disable-timestamp` flag configures the code generation behavior.
12831283
constr(regex=r'(^arn:([^:]*):([^:]*):([^:]*):(|\*|[\d]{12}):(.+)$)|^\*$') | None
12841284
) = None
12851285
tel: constr(regex=r'^(\([0-9]{3}\))?[0-9]{3}-[0-9]{4}$') | None = None
1286-
comment: constr(regex=r'[^\b\f\n\r\t\\a+.?\'"|()]+$') | None = None
1286+
comment: constr(regex=r'[^\x08\f\n\r\t\\a+.?\'"|()]+$') | None = None
12871287
```
12881288

12891289
---

src/datamodel_code_generator/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,7 @@ class OpenAPIScope(Enum):
243243
Tags = "tags"
244244
Parameters = "parameters"
245245
Webhooks = "webhooks"
246+
RequestBodies = "requestbodies"
246247

247248

248249
class AllExportsScope(Enum):

src/datamodel_code_generator/parser/base.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1805,6 +1805,8 @@ def __change_field_name(
18051805
for model in models:
18061806
if "Enum" in model.base_class:
18071807
continue
1808+
if not model.BASE_CLASS:
1809+
continue
18081810

18091811
for field in model.fields:
18101812
filed_name = field.name
@@ -1890,11 +1892,11 @@ def __is_new_required_field(self, field: DataModelFieldBase, inherited: set[str]
18901892

18911893
@classmethod
18921894
def __update_type_aliases(cls, models: list[DataModel]) -> None:
1893-
"""Update type aliases to properly handle forward references per PEP 484."""
1895+
"""Update type aliases and RootModels to properly handle forward references per PEP 484."""
18941896
model_index: dict[str, int] = {m.class_name: i for i, m in enumerate(models)}
18951897

18961898
for i, model in enumerate(models):
1897-
if not isinstance(model, TypeAliasBase):
1899+
if not isinstance(model, (TypeAliasBase, pydantic_model_v2.RootModel)):
18981900
continue
18991901
if isinstance(model, TypeStatement):
19001902
continue

src/datamodel_code_generator/parser/openapi.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -819,6 +819,29 @@ def parse_raw(self) -> None:
819819
webhooks: dict[str, dict[str, Any]] = specification.get("webhooks", {})
820820
self._process_path_items(webhooks, path_parts, "webhooks", [], security, strip_leading_slash=False)
821821

822+
if OpenAPIScope.RequestBodies in self.open_api_scopes:
823+
request_bodies: dict[str, Any] = specification.get("components", {}).get("requestBodies", {})
824+
for body_name, raw_body in request_bodies.items():
825+
resolved_body = self.get_ref_model(raw_body["$ref"]) if "$ref" in raw_body else raw_body
826+
content = resolved_body.get("content", {})
827+
for media_type, media_obj in content.items():
828+
schema = media_obj.get("schema")
829+
if not schema:
830+
continue
831+
self.parse_raw_obj(
832+
body_name,
833+
schema,
834+
[
835+
*path_parts,
836+
"#/components",
837+
"requestBodies",
838+
body_name,
839+
"content",
840+
media_type,
841+
"schema",
842+
],
843+
)
844+
822845
self._resolve_unparsed_json_pointer()
823846

824847
def _collect_discriminator_schemas(self) -> None:
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
# generated by datamodel-codegen:
2+
# filename: union.graphql
3+
# timestamp: 2019-07-26T00:00:00+00:00
4+
5+
from __future__ import annotations
6+
7+
from typing import Literal, Union
8+
9+
from pydantic import BaseModel, Field
10+
from typing_extensions import TypeAliasType
11+
12+
Boolean = TypeAliasType("Boolean", bool)
13+
"""
14+
The `Boolean` scalar type represents `true` or `false`.
15+
"""
16+
17+
18+
ID = TypeAliasType("ID", str)
19+
"""
20+
The `ID` scalar type represents a unique identifier, often used to refetch an object or as key for a cache. The ID type appears in a JSON response as a String; however, it is not intended to be human-readable. When expected as an input type, any string (such as `"4"`) or integer (such as `4`) input value will be accepted as an ID.
21+
"""
22+
23+
24+
Int = TypeAliasType("Int", int)
25+
"""
26+
The `Int` scalar type represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1.
27+
"""
28+
29+
30+
String = TypeAliasType("String", str)
31+
"""
32+
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.
33+
"""
34+
35+
36+
class IResource(BaseModel):
37+
id: ID
38+
typename__: Literal['IResource'] | None = Field('IResource', alias='__typename')
39+
40+
41+
class Car(IResource):
42+
id: ID
43+
passenger_capacity: Int = Field(..., alias='passengerCapacity')
44+
typename__: Literal['Car'] | None = Field('Car', alias='__typename')
45+
46+
47+
class Employee(IResource):
48+
first_name: String | None = Field(None, alias='firstName')
49+
id: ID
50+
last_name: String | None = Field(None, alias='lastName')
51+
typename__: Literal['Employee'] | None = Field('Employee', alias='__typename')
52+
53+
54+
Resource = TypeAliasType(
55+
"Resource",
56+
Union[
57+
'Car',
58+
'Employee',
59+
],
60+
)
61+
62+
63+
TechnicalResource = TypeAliasType("TechnicalResource", Car)

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,4 @@ class Info(BaseModel):
1717
constr(regex=r'(^arn:([^:]*):([^:]*):([^:]*):(|\*|[\d]{12}):(.+)$)|^\*$') | None
1818
) = None
1919
tel: constr(regex=r'^(\([0-9]{3}\))?[0-9]{3}-[0-9]{4}$') | None = None
20-
comment: constr(regex=r'[^\b\f\n\r\t\\a+.?\'"|()]+$') | None = None
20+
comment: constr(regex=r'[^\x08\f\n\r\t\\a+.?\'"|()]+$') | None = None

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ class ModelEnum(Enum):
1616
field__1 = '\n'
1717
field__ = '\r\n'
1818
field__2 = '\t'
19-
field__3 = '\b'
20-
field__4 = '\\'
19+
field_x08 = '\\x08'
20+
field__3 = '\\'
2121

2222

2323
class Model(BaseModel):

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ class ModelEnum(Enum):
1616
field_ = '\n'
1717
field__ = '\r\n'
1818
field__1 = '\t'
19-
field__2 = '\b'
20-
field__3 = '\\'
19+
field_x08 = '\\x08'
20+
field__2 = '\\'
2121

2222

2323
class Model(BaseModel):

0 commit comments

Comments
 (0)