datamodel-code-generator 0.27.2__py3-none-any.whl → 0.28.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of datamodel-code-generator might be problematic. Click here for more details.
- datamodel_code_generator/__init__.py +168 -196
- datamodel_code_generator/__main__.py +146 -189
- datamodel_code_generator/arguments.py +227 -230
- datamodel_code_generator/format.py +77 -129
- datamodel_code_generator/http.py +12 -10
- datamodel_code_generator/imports.py +59 -65
- datamodel_code_generator/model/__init__.py +28 -31
- datamodel_code_generator/model/base.py +100 -144
- datamodel_code_generator/model/dataclass.py +62 -70
- datamodel_code_generator/model/enum.py +34 -30
- datamodel_code_generator/model/imports.py +13 -11
- datamodel_code_generator/model/msgspec.py +116 -138
- datamodel_code_generator/model/pydantic/__init__.py +18 -28
- datamodel_code_generator/model/pydantic/base_model.py +121 -140
- datamodel_code_generator/model/pydantic/custom_root_type.py +2 -2
- datamodel_code_generator/model/pydantic/dataclass.py +6 -4
- datamodel_code_generator/model/pydantic/imports.py +35 -33
- datamodel_code_generator/model/pydantic/types.py +91 -119
- datamodel_code_generator/model/pydantic_v2/__init__.py +21 -18
- datamodel_code_generator/model/pydantic_v2/base_model.py +118 -127
- datamodel_code_generator/model/pydantic_v2/imports.py +5 -3
- datamodel_code_generator/model/pydantic_v2/root_model.py +6 -6
- datamodel_code_generator/model/pydantic_v2/types.py +11 -7
- datamodel_code_generator/model/rootmodel.py +1 -1
- datamodel_code_generator/model/scalar.py +33 -32
- datamodel_code_generator/model/typed_dict.py +41 -51
- datamodel_code_generator/model/types.py +24 -19
- datamodel_code_generator/model/union.py +21 -17
- datamodel_code_generator/parser/__init__.py +16 -12
- datamodel_code_generator/parser/base.py +327 -515
- datamodel_code_generator/parser/graphql.py +87 -119
- datamodel_code_generator/parser/jsonschema.py +438 -607
- datamodel_code_generator/parser/openapi.py +180 -220
- datamodel_code_generator/pydantic_patch.py +8 -9
- datamodel_code_generator/reference.py +199 -297
- datamodel_code_generator/types.py +149 -215
- datamodel_code_generator/util.py +23 -36
- {datamodel_code_generator-0.27.2.dist-info → datamodel_code_generator-0.28.0.dist-info}/METADATA +10 -5
- datamodel_code_generator-0.28.0.dist-info/RECORD +59 -0
- datamodel_code_generator-0.27.2.dist-info/RECORD +0 -59
- {datamodel_code_generator-0.27.2.dist-info → datamodel_code_generator-0.28.0.dist-info}/WHEEL +0 -0
- {datamodel_code_generator-0.27.2.dist-info → datamodel_code_generator-0.28.0.dist-info}/entry_points.txt +0 -0
- {datamodel_code_generator-0.27.2.dist-info → datamodel_code_generator-0.28.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
#! /usr/bin/env python
|
|
2
|
-
|
|
3
1
|
"""
|
|
4
2
|
Main function.
|
|
5
3
|
"""
|
|
@@ -11,30 +9,17 @@ import signal
|
|
|
11
9
|
import sys
|
|
12
10
|
import warnings
|
|
13
11
|
from collections import defaultdict
|
|
12
|
+
from collections.abc import Sequence # noqa: TC003 # pydantic needs it
|
|
14
13
|
from enum import IntEnum
|
|
15
14
|
from io import TextIOBase
|
|
16
15
|
from pathlib import Path
|
|
17
|
-
from typing import
|
|
18
|
-
TYPE_CHECKING,
|
|
19
|
-
Any,
|
|
20
|
-
DefaultDict,
|
|
21
|
-
Dict,
|
|
22
|
-
List,
|
|
23
|
-
Optional,
|
|
24
|
-
Sequence,
|
|
25
|
-
Set,
|
|
26
|
-
Tuple,
|
|
27
|
-
Union,
|
|
28
|
-
cast,
|
|
29
|
-
)
|
|
16
|
+
from typing import TYPE_CHECKING, Any, Optional, Union, cast
|
|
30
17
|
from urllib.parse import ParseResult, urlparse
|
|
31
18
|
|
|
32
19
|
import argcomplete
|
|
33
20
|
import black
|
|
34
21
|
from pydantic import BaseModel
|
|
35
22
|
|
|
36
|
-
from datamodel_code_generator.model.pydantic_v2 import UnionMode
|
|
37
|
-
|
|
38
23
|
if TYPE_CHECKING:
|
|
39
24
|
from argparse import Namespace
|
|
40
25
|
|
|
@@ -53,11 +38,13 @@ from datamodel_code_generator.arguments import DEFAULT_ENCODING, arg_parser, nam
|
|
|
53
38
|
from datamodel_code_generator.format import (
|
|
54
39
|
DatetimeClassType,
|
|
55
40
|
PythonVersion,
|
|
41
|
+
PythonVersionMin,
|
|
56
42
|
is_supported_in_black,
|
|
57
43
|
)
|
|
58
|
-
from datamodel_code_generator.
|
|
44
|
+
from datamodel_code_generator.model.pydantic_v2 import UnionMode # noqa: TC001 # needed for pydantic
|
|
45
|
+
from datamodel_code_generator.parser import LiteralType # noqa: TC001 # needed for pydantic
|
|
59
46
|
from datamodel_code_generator.reference import is_url
|
|
60
|
-
from datamodel_code_generator.types import StrictTypes
|
|
47
|
+
from datamodel_code_generator.types import StrictTypes # noqa: TC001 # needed for pydantic
|
|
61
48
|
from datamodel_code_generator.util import (
|
|
62
49
|
PYDANTIC_V2,
|
|
63
50
|
ConfigDict,
|
|
@@ -77,7 +64,7 @@ class Exit(IntEnum):
|
|
|
77
64
|
|
|
78
65
|
|
|
79
66
|
def sig_int_handler(_: int, __: Any) -> None: # pragma: no cover
|
|
80
|
-
exit(Exit.OK)
|
|
67
|
+
sys.exit(Exit.OK)
|
|
81
68
|
|
|
82
69
|
|
|
83
70
|
signal.signal(signal.SIGINT, sig_int_handler)
|
|
@@ -85,7 +72,7 @@ signal.signal(signal.SIGINT, sig_int_handler)
|
|
|
85
72
|
|
|
86
73
|
class Config(BaseModel):
|
|
87
74
|
if PYDANTIC_V2:
|
|
88
|
-
model_config = ConfigDict(arbitrary_types_allowed=True) # pyright: ignore
|
|
75
|
+
model_config = ConfigDict(arbitrary_types_allowed=True) # pyright: ignore[reportAssignmentType]
|
|
89
76
|
|
|
90
77
|
def get(self, item: str) -> Any:
|
|
91
78
|
return getattr(self, item)
|
|
@@ -96,7 +83,7 @@ class Config(BaseModel):
|
|
|
96
83
|
if TYPE_CHECKING:
|
|
97
84
|
|
|
98
85
|
@classmethod
|
|
99
|
-
def get_fields(cls) ->
|
|
86
|
+
def get_fields(cls) -> dict[str, Any]: ...
|
|
100
87
|
|
|
101
88
|
else:
|
|
102
89
|
|
|
@@ -105,164 +92,140 @@ class Config(BaseModel):
|
|
|
105
92
|
return cls.model_validate(obj)
|
|
106
93
|
|
|
107
94
|
@classmethod
|
|
108
|
-
def get_fields(cls) ->
|
|
95
|
+
def get_fields(cls) -> dict[str, Any]:
|
|
109
96
|
return cls.model_fields
|
|
110
97
|
|
|
111
98
|
else:
|
|
112
99
|
|
|
113
100
|
class Config:
|
|
114
|
-
# validate_assignment = True
|
|
115
101
|
# Pydantic 1.5.1 doesn't support validate_assignment correctly
|
|
116
102
|
arbitrary_types_allowed = (TextIOBase,)
|
|
117
103
|
|
|
118
104
|
if not TYPE_CHECKING:
|
|
119
105
|
|
|
120
106
|
@classmethod
|
|
121
|
-
def get_fields(cls) ->
|
|
107
|
+
def get_fields(cls) -> dict[str, Any]:
|
|
122
108
|
return cls.__fields__
|
|
123
109
|
|
|
124
|
-
@field_validator(
|
|
125
|
-
|
|
126
|
-
)
|
|
127
|
-
def validate_file(cls, value: Any) -> Optional[TextIOBase]:
|
|
110
|
+
@field_validator("aliases", "extra_template_data", "custom_formatters_kwargs", mode="before")
|
|
111
|
+
def validate_file(cls, value: Any) -> TextIOBase | None: # noqa: N805
|
|
128
112
|
if value is None or isinstance(value, TextIOBase):
|
|
129
113
|
return value
|
|
130
|
-
return cast(TextIOBase, Path(value).expanduser().resolve().open(
|
|
114
|
+
return cast("TextIOBase", Path(value).expanduser().resolve().open("rt"))
|
|
131
115
|
|
|
132
116
|
@field_validator(
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
mode=
|
|
117
|
+
"input",
|
|
118
|
+
"output",
|
|
119
|
+
"custom_template_dir",
|
|
120
|
+
"custom_file_header_path",
|
|
121
|
+
mode="before",
|
|
138
122
|
)
|
|
139
|
-
def validate_path(cls, value: Any) ->
|
|
123
|
+
def validate_path(cls, value: Any) -> Path | None: # noqa: N805
|
|
140
124
|
if value is None or isinstance(value, Path):
|
|
141
125
|
return value # pragma: no cover
|
|
142
126
|
return Path(value).expanduser().resolve()
|
|
143
127
|
|
|
144
|
-
@field_validator(
|
|
145
|
-
def validate_url(cls, value: Any) ->
|
|
128
|
+
@field_validator("url", mode="before")
|
|
129
|
+
def validate_url(cls, value: Any) -> ParseResult | None: # noqa: N805
|
|
146
130
|
if isinstance(value, str) and is_url(value): # pragma: no cover
|
|
147
131
|
return urlparse(value)
|
|
148
|
-
|
|
132
|
+
if value is None: # pragma: no cover
|
|
149
133
|
return None
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
if values.get('use_generic_container_types'):
|
|
159
|
-
target_python_version: PythonVersion = values['target_python_version']
|
|
160
|
-
if target_python_version == target_python_version.PY_36:
|
|
161
|
-
raise Error(
|
|
162
|
-
f'`--use-generic-container-types` can not be used with `--target-python-version` {target_python_version.PY_36.value}.\n'
|
|
163
|
-
' The version will be not supported in a future version'
|
|
164
|
-
)
|
|
134
|
+
msg = f"This protocol doesn't support only http/https. --input={value}"
|
|
135
|
+
raise Error(msg) # pragma: no cover
|
|
136
|
+
|
|
137
|
+
@model_validator()
|
|
138
|
+
def validate_original_field_name_delimiter(cls, values: dict[str, Any]) -> dict[str, Any]: # noqa: N805
|
|
139
|
+
if values.get("original_field_name_delimiter") is not None and not values.get("snake_case_field"):
|
|
140
|
+
msg = "`--original-field-name-delimiter` can not be used without `--snake-case-field`."
|
|
141
|
+
raise Error(msg)
|
|
165
142
|
return values
|
|
166
143
|
|
|
167
|
-
@model_validator(
|
|
168
|
-
def
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
if not values.get('snake_case_field'):
|
|
173
|
-
raise Error(
|
|
174
|
-
'`--original-field-name-delimiter` can not be used without `--snake-case-field`.'
|
|
175
|
-
)
|
|
144
|
+
@model_validator()
|
|
145
|
+
def validate_custom_file_header(cls, values: dict[str, Any]) -> dict[str, Any]: # noqa: N805
|
|
146
|
+
if values.get("custom_file_header") and values.get("custom_file_header_path"):
|
|
147
|
+
msg = "`--custom_file_header_path` can not be used with `--custom_file_header`."
|
|
148
|
+
raise Error(msg) # pragma: no cover
|
|
176
149
|
return values
|
|
177
150
|
|
|
178
|
-
@model_validator(
|
|
179
|
-
def
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
'`--custom_file_header_path` can not be used with `--custom_file_header`.'
|
|
183
|
-
) # pragma: no cover
|
|
184
|
-
return values
|
|
185
|
-
|
|
186
|
-
@model_validator(mode='after')
|
|
187
|
-
def validate_keyword_only(cls, values: Dict[str, Any]) -> Dict[str, Any]:
|
|
188
|
-
output_model_type: DataModelType = values.get('output_model_type') # pyright: ignore [reportAssignmentType]
|
|
189
|
-
python_target: PythonVersion = values.get('target_python_version') # pyright: ignore [reportAssignmentType]
|
|
151
|
+
@model_validator()
|
|
152
|
+
def validate_keyword_only(cls, values: dict[str, Any]) -> dict[str, Any]: # noqa: N805
|
|
153
|
+
output_model_type: DataModelType = values.get("output_model_type") # pyright: ignore[reportAssignmentType]
|
|
154
|
+
python_target: PythonVersion = values.get("target_python_version") # pyright: ignore[reportAssignmentType]
|
|
190
155
|
if (
|
|
191
|
-
values.get(
|
|
156
|
+
values.get("keyword_only")
|
|
192
157
|
and output_model_type == DataModelType.DataclassesDataclass
|
|
193
158
|
and not python_target.has_kw_only_dataclass
|
|
194
159
|
):
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
)
|
|
160
|
+
msg = f"`--keyword-only` requires `--target-python-version` {PythonVersion.PY_310.value} or higher."
|
|
161
|
+
raise Error(msg)
|
|
198
162
|
return values
|
|
199
163
|
|
|
200
|
-
@model_validator(
|
|
201
|
-
def validate_output_datetime_class(cls, values:
|
|
202
|
-
datetime_class_type:
|
|
203
|
-
'output_datetime_class'
|
|
204
|
-
)
|
|
164
|
+
@model_validator()
|
|
165
|
+
def validate_output_datetime_class(cls, values: dict[str, Any]) -> dict[str, Any]: # noqa: N805
|
|
166
|
+
datetime_class_type: DatetimeClassType | None = values.get("output_datetime_class")
|
|
205
167
|
if (
|
|
206
168
|
datetime_class_type
|
|
207
169
|
and datetime_class_type is not DatetimeClassType.Datetime
|
|
208
|
-
and values.get(
|
|
170
|
+
and values.get("output_model_type") == DataModelType.DataclassesDataclass
|
|
209
171
|
):
|
|
210
|
-
|
|
172
|
+
msg = (
|
|
211
173
|
'`--output-datetime-class` only allows "datetime" for '
|
|
212
|
-
f
|
|
174
|
+
f"`--output-model-type` {DataModelType.DataclassesDataclass.value}"
|
|
213
175
|
)
|
|
176
|
+
raise Error(msg)
|
|
214
177
|
return values
|
|
215
178
|
|
|
216
179
|
# Pydantic 1.5.1 doesn't support each_item=True correctly
|
|
217
|
-
@field_validator(
|
|
218
|
-
def validate_http_headers(cls, value: Any) ->
|
|
219
|
-
def validate_each_item(each_item: Any) ->
|
|
180
|
+
@field_validator("http_headers", mode="before")
|
|
181
|
+
def validate_http_headers(cls, value: Any) -> list[tuple[str, str]] | None: # noqa: N805
|
|
182
|
+
def validate_each_item(each_item: Any) -> tuple[str, str]:
|
|
220
183
|
if isinstance(each_item, str): # pragma: no cover
|
|
221
184
|
try:
|
|
222
|
-
field_name, field_value = each_item.split(
|
|
185
|
+
field_name, field_value = each_item.split(":", maxsplit=1)
|
|
223
186
|
return field_name, field_value.lstrip()
|
|
224
|
-
except ValueError:
|
|
225
|
-
|
|
187
|
+
except ValueError as exc:
|
|
188
|
+
msg = f"Invalid http header: {each_item!r}"
|
|
189
|
+
raise Error(msg) from exc
|
|
226
190
|
return each_item # pragma: no cover
|
|
227
191
|
|
|
228
192
|
if isinstance(value, list):
|
|
229
193
|
return [validate_each_item(each_item) for each_item in value]
|
|
230
194
|
return value # pragma: no cover
|
|
231
195
|
|
|
232
|
-
@field_validator(
|
|
233
|
-
def validate_http_query_parameters(
|
|
234
|
-
|
|
235
|
-
) -> Optional[List[Tuple[str, str]]]:
|
|
236
|
-
def validate_each_item(each_item: Any) -> Tuple[str, str]:
|
|
196
|
+
@field_validator("http_query_parameters", mode="before")
|
|
197
|
+
def validate_http_query_parameters(cls, value: Any) -> list[tuple[str, str]] | None: # noqa: N805
|
|
198
|
+
def validate_each_item(each_item: Any) -> tuple[str, str]:
|
|
237
199
|
if isinstance(each_item, str): # pragma: no cover
|
|
238
200
|
try:
|
|
239
|
-
field_name, field_value = each_item.split(
|
|
201
|
+
field_name, field_value = each_item.split("=", maxsplit=1)
|
|
240
202
|
return field_name, field_value.lstrip()
|
|
241
|
-
except ValueError:
|
|
242
|
-
|
|
203
|
+
except ValueError as exc:
|
|
204
|
+
msg = f"Invalid http query parameter: {each_item!r}"
|
|
205
|
+
raise Error(msg) from exc
|
|
243
206
|
return each_item # pragma: no cover
|
|
244
207
|
|
|
245
208
|
if isinstance(value, list):
|
|
246
209
|
return [validate_each_item(each_item) for each_item in value]
|
|
247
210
|
return value # pragma: no cover
|
|
248
211
|
|
|
249
|
-
@model_validator(mode=
|
|
250
|
-
def validate_additional_imports(cls, values:
|
|
251
|
-
additional_imports = values.get(
|
|
212
|
+
@model_validator(mode="before")
|
|
213
|
+
def validate_additional_imports(cls, values: dict[str, Any]) -> dict[str, Any]: # noqa: N805
|
|
214
|
+
additional_imports = values.get("additional_imports")
|
|
252
215
|
if additional_imports is not None:
|
|
253
|
-
values[
|
|
216
|
+
values["additional_imports"] = additional_imports.split(",")
|
|
254
217
|
return values
|
|
255
218
|
|
|
256
|
-
@model_validator(mode=
|
|
257
|
-
def validate_custom_formatters(cls, values:
|
|
258
|
-
custom_formatters = values.get(
|
|
219
|
+
@model_validator(mode="before")
|
|
220
|
+
def validate_custom_formatters(cls, values: dict[str, Any]) -> dict[str, Any]: # noqa: N805
|
|
221
|
+
custom_formatters = values.get("custom_formatters")
|
|
259
222
|
if custom_formatters is not None:
|
|
260
|
-
values[
|
|
223
|
+
values["custom_formatters"] = custom_formatters.split(",")
|
|
261
224
|
return values
|
|
262
225
|
|
|
263
226
|
if PYDANTIC_V2:
|
|
264
227
|
|
|
265
|
-
@model_validator(
|
|
228
|
+
@model_validator() # pyright: ignore[reportArgumentType]
|
|
266
229
|
def validate_root(self: Self) -> Self:
|
|
267
230
|
if self.use_annotated:
|
|
268
231
|
self.field_constraints = True
|
|
@@ -270,42 +233,42 @@ class Config(BaseModel):
|
|
|
270
233
|
|
|
271
234
|
else:
|
|
272
235
|
|
|
273
|
-
@model_validator(
|
|
274
|
-
def validate_root(cls, values: Any) -> Any:
|
|
275
|
-
if values.get(
|
|
276
|
-
values[
|
|
236
|
+
@model_validator()
|
|
237
|
+
def validate_root(cls, values: Any) -> Any: # noqa: N805
|
|
238
|
+
if values.get("use_annotated"):
|
|
239
|
+
values["field_constraints"] = True
|
|
277
240
|
return values
|
|
278
241
|
|
|
279
|
-
input: Optional[Union[Path, str]] = None
|
|
242
|
+
input: Optional[Union[Path, str]] = None # noqa: UP007, UP045
|
|
280
243
|
input_file_type: InputFileType = InputFileType.Auto
|
|
281
244
|
output_model_type: DataModelType = DataModelType.PydanticBaseModel
|
|
282
|
-
output: Optional[Path] = None
|
|
245
|
+
output: Optional[Path] = None # noqa: UP045
|
|
283
246
|
debug: bool = False
|
|
284
247
|
disable_warnings: bool = False
|
|
285
|
-
target_python_version: PythonVersion =
|
|
286
|
-
base_class: str =
|
|
287
|
-
additional_imports: Optional[
|
|
288
|
-
custom_template_dir: Optional[Path] = None
|
|
289
|
-
extra_template_data: Optional[TextIOBase] = None
|
|
248
|
+
target_python_version: PythonVersion = PythonVersionMin
|
|
249
|
+
base_class: str = ""
|
|
250
|
+
additional_imports: Optional[list[str]] = None # noqa: UP045
|
|
251
|
+
custom_template_dir: Optional[Path] = None # noqa: UP045
|
|
252
|
+
extra_template_data: Optional[TextIOBase] = None # noqa: UP045
|
|
290
253
|
validation: bool = False
|
|
291
254
|
field_constraints: bool = False
|
|
292
255
|
snake_case_field: bool = False
|
|
293
256
|
strip_default_none: bool = False
|
|
294
|
-
aliases: Optional[TextIOBase] = None
|
|
257
|
+
aliases: Optional[TextIOBase] = None # noqa: UP045
|
|
295
258
|
disable_timestamp: bool = False
|
|
296
259
|
enable_version_header: bool = False
|
|
297
260
|
allow_population_by_field_name: bool = False
|
|
298
261
|
allow_extra_fields: bool = False
|
|
299
262
|
use_default: bool = False
|
|
300
263
|
force_optional: bool = False
|
|
301
|
-
class_name: Optional[str] = None
|
|
264
|
+
class_name: Optional[str] = None # noqa: UP045
|
|
302
265
|
use_standard_collections: bool = False
|
|
303
266
|
use_schema_description: bool = False
|
|
304
267
|
use_field_description: bool = False
|
|
305
268
|
use_default_kwarg: bool = False
|
|
306
269
|
reuse_model: bool = False
|
|
307
270
|
encoding: str = DEFAULT_ENCODING
|
|
308
|
-
enum_field_as_literal: Optional[LiteralType] = None
|
|
271
|
+
enum_field_as_literal: Optional[LiteralType] = None # noqa: UP045
|
|
309
272
|
use_one_literal_as_default: bool = False
|
|
310
273
|
set_default_enum_member: bool = False
|
|
311
274
|
use_subclass_enum: bool = False
|
|
@@ -313,73 +276,69 @@ class Config(BaseModel):
|
|
|
313
276
|
use_generic_container_types: bool = False
|
|
314
277
|
use_union_operator: bool = False
|
|
315
278
|
enable_faux_immutability: bool = False
|
|
316
|
-
url: Optional[ParseResult] = None
|
|
279
|
+
url: Optional[ParseResult] = None # noqa: UP045
|
|
317
280
|
disable_appending_item_suffix: bool = False
|
|
318
|
-
strict_types:
|
|
319
|
-
empty_enum_field_name: Optional[str] = None
|
|
320
|
-
field_extra_keys: Optional[
|
|
281
|
+
strict_types: list[StrictTypes] = []
|
|
282
|
+
empty_enum_field_name: Optional[str] = None # noqa: UP045
|
|
283
|
+
field_extra_keys: Optional[set[str]] = None # noqa: UP045
|
|
321
284
|
field_include_all_keys: bool = False
|
|
322
|
-
field_extra_keys_without_x_prefix: Optional[
|
|
323
|
-
openapi_scopes: Optional[
|
|
324
|
-
wrap_string_literal: Optional[bool] = None
|
|
285
|
+
field_extra_keys_without_x_prefix: Optional[set[str]] = None # noqa: UP045
|
|
286
|
+
openapi_scopes: Optional[list[OpenAPIScope]] = [OpenAPIScope.Schemas] # noqa: UP045
|
|
287
|
+
wrap_string_literal: Optional[bool] = None # noqa: UP045
|
|
325
288
|
use_title_as_name: bool = False
|
|
326
289
|
use_operation_id_as_name: bool = False
|
|
327
290
|
use_unique_items_as_set: bool = False
|
|
328
|
-
http_headers: Optional[Sequence[
|
|
291
|
+
http_headers: Optional[Sequence[tuple[str, str]]] = None # noqa: UP045
|
|
329
292
|
http_ignore_tls: bool = False
|
|
330
293
|
use_annotated: bool = False
|
|
331
294
|
use_non_positive_negative_number_constrained_types: bool = False
|
|
332
|
-
original_field_name_delimiter: Optional[str] = None
|
|
295
|
+
original_field_name_delimiter: Optional[str] = None # noqa: UP045
|
|
333
296
|
use_double_quotes: bool = False
|
|
334
297
|
collapse_root_models: bool = False
|
|
335
|
-
special_field_name_prefix: Optional[str] = None
|
|
298
|
+
special_field_name_prefix: Optional[str] = None # noqa: UP045
|
|
336
299
|
remove_special_field_name_prefix: bool = False
|
|
337
300
|
capitalise_enum_members: bool = False
|
|
338
301
|
keep_model_order: bool = False
|
|
339
|
-
custom_file_header: Optional[str] = None
|
|
340
|
-
custom_file_header_path: Optional[Path] = None
|
|
341
|
-
custom_formatters: Optional[
|
|
342
|
-
custom_formatters_kwargs: Optional[TextIOBase] = None
|
|
302
|
+
custom_file_header: Optional[str] = None # noqa: UP045
|
|
303
|
+
custom_file_header_path: Optional[Path] = None # noqa: UP045
|
|
304
|
+
custom_formatters: Optional[list[str]] = None # noqa: UP045
|
|
305
|
+
custom_formatters_kwargs: Optional[TextIOBase] = None # noqa: UP045
|
|
343
306
|
use_pendulum: bool = False
|
|
344
|
-
http_query_parameters: Optional[Sequence[
|
|
307
|
+
http_query_parameters: Optional[Sequence[tuple[str, str]]] = None # noqa: UP045
|
|
345
308
|
treat_dot_as_module: bool = False
|
|
346
309
|
use_exact_imports: bool = False
|
|
347
|
-
union_mode: Optional[UnionMode] = None
|
|
348
|
-
output_datetime_class: Optional[DatetimeClassType] = None
|
|
310
|
+
union_mode: Optional[UnionMode] = None # noqa: UP045
|
|
311
|
+
output_datetime_class: Optional[DatetimeClassType] = None # noqa: UP045
|
|
349
312
|
keyword_only: bool = False
|
|
350
313
|
no_alias: bool = False
|
|
351
314
|
|
|
352
315
|
def merge_args(self, args: Namespace) -> None:
|
|
353
|
-
set_args = {
|
|
354
|
-
f: getattr(args, f)
|
|
355
|
-
for f in self.get_fields()
|
|
356
|
-
if getattr(args, f) is not None
|
|
357
|
-
}
|
|
316
|
+
set_args = {f: getattr(args, f) for f in self.get_fields() if getattr(args, f) is not None}
|
|
358
317
|
|
|
359
|
-
if set_args.get(
|
|
360
|
-
set_args[
|
|
318
|
+
if set_args.get("output_model_type") == DataModelType.MsgspecStruct.value:
|
|
319
|
+
set_args["use_annotated"] = True
|
|
361
320
|
|
|
362
|
-
if set_args.get(
|
|
363
|
-
set_args[
|
|
321
|
+
if set_args.get("use_annotated"):
|
|
322
|
+
set_args["field_constraints"] = True
|
|
364
323
|
|
|
365
324
|
parsed_args = Config.parse_obj(set_args)
|
|
366
325
|
for field_name in set_args:
|
|
367
326
|
setattr(self, field_name, getattr(parsed_args, field_name))
|
|
368
327
|
|
|
369
328
|
|
|
370
|
-
def _get_pyproject_toml_config(source: Path) ->
|
|
329
|
+
def _get_pyproject_toml_config(source: Path) -> dict[str, Any] | None:
|
|
371
330
|
"""Find and return the [tool.datamodel-codgen] section of the closest
|
|
372
331
|
pyproject.toml if it exists.
|
|
373
332
|
"""
|
|
374
333
|
|
|
375
334
|
current_path = source
|
|
376
335
|
while current_path != current_path.parent:
|
|
377
|
-
if (current_path /
|
|
378
|
-
pyproject_toml = load_toml(current_path /
|
|
379
|
-
if
|
|
380
|
-
return pyproject_toml[
|
|
336
|
+
if (current_path / "pyproject.toml").is_file():
|
|
337
|
+
pyproject_toml = load_toml(current_path / "pyproject.toml")
|
|
338
|
+
if "datamodel-codegen" in pyproject_toml.get("tool", {}):
|
|
339
|
+
return pyproject_toml["tool"]["datamodel-codegen"]
|
|
381
340
|
|
|
382
|
-
if (current_path /
|
|
341
|
+
if (current_path / ".git").exists():
|
|
383
342
|
# Stop early if we see a git repository root.
|
|
384
343
|
return None
|
|
385
344
|
|
|
@@ -387,7 +346,7 @@ def _get_pyproject_toml_config(source: Path) -> Optional[Dict[str, Any]]:
|
|
|
387
346
|
return None
|
|
388
347
|
|
|
389
348
|
|
|
390
|
-
def main(args:
|
|
349
|
+
def main(args: Sequence[str] | None = None) -> Exit: # noqa: PLR0911, PLR0912, PLR0915
|
|
391
350
|
"""Main function."""
|
|
392
351
|
|
|
393
352
|
# add cli completion support
|
|
@@ -399,14 +358,14 @@ def main(args: Optional[Sequence[str]] = None) -> Exit:
|
|
|
399
358
|
arg_parser.parse_args(args, namespace=namespace)
|
|
400
359
|
|
|
401
360
|
if namespace.version:
|
|
402
|
-
from datamodel_code_generator import get_version
|
|
361
|
+
from datamodel_code_generator import get_version # noqa: PLC0415
|
|
403
362
|
|
|
404
|
-
print(get_version())
|
|
405
|
-
exit(0)
|
|
363
|
+
print(get_version()) # noqa: T201
|
|
364
|
+
sys.exit(0)
|
|
406
365
|
|
|
407
|
-
pyproject_config = _get_pyproject_toml_config(Path
|
|
366
|
+
pyproject_config = _get_pyproject_toml_config(Path.cwd())
|
|
408
367
|
if pyproject_config is not None:
|
|
409
|
-
pyproject_toml = {k.replace(
|
|
368
|
+
pyproject_toml = {k.replace("-", "_"): v for k, v in pyproject_config.items()}
|
|
410
369
|
else:
|
|
411
370
|
pyproject_toml = {}
|
|
412
371
|
|
|
@@ -414,22 +373,22 @@ def main(args: Optional[Sequence[str]] = None) -> Exit:
|
|
|
414
373
|
config = Config.parse_obj(pyproject_toml)
|
|
415
374
|
config.merge_args(namespace)
|
|
416
375
|
except Error as e:
|
|
417
|
-
print(e.message, file=sys.stderr)
|
|
376
|
+
print(e.message, file=sys.stderr) # noqa: T201
|
|
418
377
|
return Exit.ERROR
|
|
419
378
|
|
|
420
379
|
if not config.input and not config.url and sys.stdin.isatty():
|
|
421
|
-
print(
|
|
422
|
-
|
|
380
|
+
print( # noqa: T201
|
|
381
|
+
"Not Found Input: require `stdin` or arguments `--input` or `--url`",
|
|
423
382
|
file=sys.stderr,
|
|
424
383
|
)
|
|
425
384
|
arg_parser.print_help()
|
|
426
385
|
return Exit.ERROR
|
|
427
386
|
|
|
428
387
|
if not is_supported_in_black(config.target_python_version): # pragma: no cover
|
|
429
|
-
print(
|
|
430
|
-
f"Installed black doesn't support Python version {config.target_python_version.value}.\n"
|
|
431
|
-
f
|
|
432
|
-
f
|
|
388
|
+
print( # noqa: T201
|
|
389
|
+
f"Installed black doesn't support Python version {config.target_python_version.value}.\n"
|
|
390
|
+
f"You have to install a newer black.\n"
|
|
391
|
+
f"Installed black version: {black.__version__}",
|
|
433
392
|
file=sys.stderr,
|
|
434
393
|
)
|
|
435
394
|
return Exit.ERROR
|
|
@@ -438,18 +397,16 @@ def main(args: Optional[Sequence[str]] = None) -> Exit:
|
|
|
438
397
|
enable_debug_message()
|
|
439
398
|
|
|
440
399
|
if config.disable_warnings:
|
|
441
|
-
warnings.simplefilter(
|
|
442
|
-
extra_template_data:
|
|
400
|
+
warnings.simplefilter("ignore")
|
|
401
|
+
extra_template_data: defaultdict[str, dict[str, Any]] | None
|
|
443
402
|
if config.extra_template_data is None:
|
|
444
403
|
extra_template_data = None
|
|
445
404
|
else:
|
|
446
405
|
with config.extra_template_data as data:
|
|
447
406
|
try:
|
|
448
|
-
extra_template_data = json.load(
|
|
449
|
-
data, object_hook=lambda d: defaultdict(dict, **d)
|
|
450
|
-
)
|
|
407
|
+
extra_template_data = json.load(data, object_hook=lambda d: defaultdict(dict, **d))
|
|
451
408
|
except json.JSONDecodeError as e:
|
|
452
|
-
print(f
|
|
409
|
+
print(f"Unable to load extra template data: {e}", file=sys.stderr) # noqa: T201
|
|
453
410
|
return Exit.ERROR
|
|
454
411
|
|
|
455
412
|
if config.aliases is None:
|
|
@@ -459,12 +416,12 @@ def main(args: Optional[Sequence[str]] = None) -> Exit:
|
|
|
459
416
|
try:
|
|
460
417
|
aliases = json.load(data)
|
|
461
418
|
except json.JSONDecodeError as e:
|
|
462
|
-
print(f
|
|
419
|
+
print(f"Unable to load alias mapping: {e}", file=sys.stderr) # noqa: T201
|
|
463
420
|
return Exit.ERROR
|
|
464
421
|
if not isinstance(aliases, dict) or not all(
|
|
465
422
|
isinstance(k, str) and isinstance(v, str) for k, v in aliases.items()
|
|
466
423
|
):
|
|
467
|
-
print(
|
|
424
|
+
print( # noqa: T201
|
|
468
425
|
'Alias mapping must be a JSON string mapping (e.g. {"from": "to", ...})',
|
|
469
426
|
file=sys.stderr,
|
|
470
427
|
)
|
|
@@ -477,16 +434,15 @@ def main(args: Optional[Sequence[str]] = None) -> Exit:
|
|
|
477
434
|
try:
|
|
478
435
|
custom_formatters_kwargs = json.load(data)
|
|
479
436
|
except json.JSONDecodeError as e: # pragma: no cover
|
|
480
|
-
print(
|
|
481
|
-
f
|
|
437
|
+
print( # noqa: T201
|
|
438
|
+
f"Unable to load custom_formatters_kwargs mapping: {e}",
|
|
482
439
|
file=sys.stderr,
|
|
483
440
|
)
|
|
484
441
|
return Exit.ERROR
|
|
485
442
|
if not isinstance(custom_formatters_kwargs, dict) or not all(
|
|
486
|
-
isinstance(k, str) and isinstance(v, str)
|
|
487
|
-
for k, v in custom_formatters_kwargs.items()
|
|
443
|
+
isinstance(k, str) and isinstance(v, str) for k, v in custom_formatters_kwargs.items()
|
|
488
444
|
): # pragma: no cover
|
|
489
|
-
print(
|
|
445
|
+
print( # noqa: T201
|
|
490
446
|
'Custom formatters kwargs mapping must be a JSON string mapping (e.g. {"from": "to", ...})',
|
|
491
447
|
file=sys.stderr,
|
|
492
448
|
)
|
|
@@ -564,19 +520,20 @@ def main(args: Optional[Sequence[str]] = None) -> Exit:
|
|
|
564
520
|
keyword_only=config.keyword_only,
|
|
565
521
|
no_alias=config.no_alias,
|
|
566
522
|
)
|
|
567
|
-
return Exit.OK
|
|
568
523
|
except InvalidClassNameError as e:
|
|
569
|
-
print(f
|
|
524
|
+
print(f"{e} You have to set `--class-name` option", file=sys.stderr) # noqa: T201
|
|
570
525
|
return Exit.ERROR
|
|
571
526
|
except Error as e:
|
|
572
|
-
print(str(e), file=sys.stderr)
|
|
527
|
+
print(str(e), file=sys.stderr) # noqa: T201
|
|
573
528
|
return Exit.ERROR
|
|
574
|
-
except Exception:
|
|
575
|
-
import traceback
|
|
529
|
+
except Exception: # noqa: BLE001
|
|
530
|
+
import traceback # noqa: PLC0415
|
|
576
531
|
|
|
577
|
-
print(traceback.format_exc(), file=sys.stderr)
|
|
532
|
+
print(traceback.format_exc(), file=sys.stderr) # noqa: T201
|
|
578
533
|
return Exit.ERROR
|
|
534
|
+
else:
|
|
535
|
+
return Exit.OK
|
|
579
536
|
|
|
580
537
|
|
|
581
|
-
if __name__ ==
|
|
538
|
+
if __name__ == "__main__":
|
|
582
539
|
sys.exit(main())
|