datamodel-code-generator 0.11.12__py3-none-any.whl → 0.45.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.
Files changed (73) hide show
  1. datamodel_code_generator/__init__.py +654 -185
  2. datamodel_code_generator/__main__.py +872 -388
  3. datamodel_code_generator/arguments.py +798 -0
  4. datamodel_code_generator/cli_options.py +295 -0
  5. datamodel_code_generator/format.py +292 -54
  6. datamodel_code_generator/http.py +85 -10
  7. datamodel_code_generator/imports.py +152 -43
  8. datamodel_code_generator/model/__init__.py +138 -1
  9. datamodel_code_generator/model/base.py +531 -120
  10. datamodel_code_generator/model/dataclass.py +211 -0
  11. datamodel_code_generator/model/enum.py +133 -12
  12. datamodel_code_generator/model/imports.py +22 -0
  13. datamodel_code_generator/model/msgspec.py +462 -0
  14. datamodel_code_generator/model/pydantic/__init__.py +30 -25
  15. datamodel_code_generator/model/pydantic/base_model.py +304 -100
  16. datamodel_code_generator/model/pydantic/custom_root_type.py +11 -2
  17. datamodel_code_generator/model/pydantic/dataclass.py +15 -4
  18. datamodel_code_generator/model/pydantic/imports.py +40 -27
  19. datamodel_code_generator/model/pydantic/types.py +188 -96
  20. datamodel_code_generator/model/pydantic_v2/__init__.py +51 -0
  21. datamodel_code_generator/model/pydantic_v2/base_model.py +268 -0
  22. datamodel_code_generator/model/pydantic_v2/imports.py +15 -0
  23. datamodel_code_generator/model/pydantic_v2/root_model.py +35 -0
  24. datamodel_code_generator/model/pydantic_v2/types.py +143 -0
  25. datamodel_code_generator/model/scalar.py +124 -0
  26. datamodel_code_generator/model/template/Enum.jinja2 +15 -2
  27. datamodel_code_generator/model/template/ScalarTypeAliasAnnotation.jinja2 +6 -0
  28. datamodel_code_generator/model/template/ScalarTypeAliasType.jinja2 +6 -0
  29. datamodel_code_generator/model/template/ScalarTypeStatement.jinja2 +6 -0
  30. datamodel_code_generator/model/template/TypeAliasAnnotation.jinja2 +20 -0
  31. datamodel_code_generator/model/template/TypeAliasType.jinja2 +20 -0
  32. datamodel_code_generator/model/template/TypeStatement.jinja2 +20 -0
  33. datamodel_code_generator/model/template/TypedDict.jinja2 +5 -0
  34. datamodel_code_generator/model/template/TypedDictClass.jinja2 +25 -0
  35. datamodel_code_generator/model/template/TypedDictFunction.jinja2 +24 -0
  36. datamodel_code_generator/model/template/UnionTypeAliasAnnotation.jinja2 +10 -0
  37. datamodel_code_generator/model/template/UnionTypeAliasType.jinja2 +10 -0
  38. datamodel_code_generator/model/template/UnionTypeStatement.jinja2 +10 -0
  39. datamodel_code_generator/model/template/dataclass.jinja2 +50 -0
  40. datamodel_code_generator/model/template/msgspec.jinja2 +55 -0
  41. datamodel_code_generator/model/template/pydantic/BaseModel.jinja2 +17 -4
  42. datamodel_code_generator/model/template/pydantic/BaseModel_root.jinja2 +12 -4
  43. datamodel_code_generator/model/template/pydantic/Config.jinja2 +1 -1
  44. datamodel_code_generator/model/template/pydantic/dataclass.jinja2 +15 -2
  45. datamodel_code_generator/model/template/pydantic_v2/BaseModel.jinja2 +57 -0
  46. datamodel_code_generator/model/template/pydantic_v2/ConfigDict.jinja2 +5 -0
  47. datamodel_code_generator/model/template/pydantic_v2/RootModel.jinja2 +48 -0
  48. datamodel_code_generator/model/type_alias.py +70 -0
  49. datamodel_code_generator/model/typed_dict.py +161 -0
  50. datamodel_code_generator/model/types.py +106 -0
  51. datamodel_code_generator/model/union.py +105 -0
  52. datamodel_code_generator/parser/__init__.py +30 -12
  53. datamodel_code_generator/parser/_graph.py +67 -0
  54. datamodel_code_generator/parser/_scc.py +171 -0
  55. datamodel_code_generator/parser/base.py +2426 -380
  56. datamodel_code_generator/parser/graphql.py +652 -0
  57. datamodel_code_generator/parser/jsonschema.py +2518 -647
  58. datamodel_code_generator/parser/openapi.py +631 -222
  59. datamodel_code_generator/py.typed +0 -0
  60. datamodel_code_generator/pydantic_patch.py +28 -0
  61. datamodel_code_generator/reference.py +672 -290
  62. datamodel_code_generator/types.py +521 -145
  63. datamodel_code_generator/util.py +155 -0
  64. datamodel_code_generator/watch.py +65 -0
  65. datamodel_code_generator-0.45.0.dist-info/METADATA +301 -0
  66. datamodel_code_generator-0.45.0.dist-info/RECORD +69 -0
  67. {datamodel_code_generator-0.11.12.dist-info → datamodel_code_generator-0.45.0.dist-info}/WHEEL +1 -1
  68. datamodel_code_generator-0.45.0.dist-info/entry_points.txt +2 -0
  69. datamodel_code_generator/version.py +0 -1
  70. datamodel_code_generator-0.11.12.dist-info/METADATA +0 -440
  71. datamodel_code_generator-0.11.12.dist-info/RECORD +0 -31
  72. datamodel_code_generator-0.11.12.dist-info/entry_points.txt +0 -3
  73. {datamodel_code_generator-0.11.12.dist-info → datamodel_code_generator-0.45.0.dist-info/licenses}/LICENSE +0 -0
@@ -0,0 +1,211 @@
1
+ """Python dataclass model generator.
2
+
3
+ Generates Python dataclasses using the @dataclass decorator.
4
+ """
5
+
6
+ from __future__ import annotations
7
+
8
+ from typing import TYPE_CHECKING, Any, ClassVar, Optional
9
+
10
+ from datamodel_code_generator import DataclassArguments, DatetimeClassType, PythonVersion, PythonVersionMin
11
+ from datamodel_code_generator.imports import (
12
+ IMPORT_DATE,
13
+ IMPORT_DATETIME,
14
+ IMPORT_TIME,
15
+ IMPORT_TIMEDELTA,
16
+ Import,
17
+ )
18
+ from datamodel_code_generator.model import DataModel, DataModelFieldBase
19
+ from datamodel_code_generator.model.base import UNDEFINED
20
+ from datamodel_code_generator.model.imports import IMPORT_DATACLASS, IMPORT_FIELD
21
+ from datamodel_code_generator.model.pydantic.base_model import Constraints # noqa: TC001 # needed for pydantic
22
+ from datamodel_code_generator.model.types import DataTypeManager as _DataTypeManager
23
+ from datamodel_code_generator.model.types import type_map_factory
24
+ from datamodel_code_generator.types import DataType, StrictTypes, Types, chain_as_tuple
25
+
26
+ if TYPE_CHECKING:
27
+ from collections import defaultdict
28
+ from collections.abc import Sequence
29
+ from pathlib import Path
30
+
31
+ from datamodel_code_generator.reference import Reference
32
+
33
+
34
+ def has_field_assignment(field: DataModelFieldBase) -> bool:
35
+ """Check if a dataclass field has a default value or field() assignment."""
36
+ return bool(field.field) or not (
37
+ field.required or (field.represented_default == "None" and field.strip_default_none)
38
+ )
39
+
40
+
41
+ class DataClass(DataModel):
42
+ """DataModel implementation for Python dataclasses."""
43
+
44
+ TEMPLATE_FILE_PATH: ClassVar[str] = "dataclass.jinja2"
45
+ DEFAULT_IMPORTS: ClassVar[tuple[Import, ...]] = (IMPORT_DATACLASS,)
46
+
47
+ def __init__( # noqa: PLR0913
48
+ self,
49
+ *,
50
+ reference: Reference,
51
+ fields: list[DataModelFieldBase],
52
+ decorators: list[str] | None = None,
53
+ base_classes: list[Reference] | None = None,
54
+ custom_base_class: str | None = None,
55
+ custom_template_dir: Path | None = None,
56
+ extra_template_data: defaultdict[str, dict[str, Any]] | None = None,
57
+ methods: list[str] | None = None,
58
+ path: Path | None = None,
59
+ description: str | None = None,
60
+ default: Any = UNDEFINED,
61
+ nullable: bool = False,
62
+ keyword_only: bool = False,
63
+ frozen: bool = False,
64
+ treat_dot_as_module: bool = False,
65
+ dataclass_arguments: DataclassArguments | None = None,
66
+ ) -> None:
67
+ """Initialize dataclass with fields sorted by field assignment requirement."""
68
+ super().__init__(
69
+ reference=reference,
70
+ fields=sorted(fields, key=has_field_assignment),
71
+ decorators=decorators,
72
+ base_classes=base_classes,
73
+ custom_base_class=custom_base_class,
74
+ custom_template_dir=custom_template_dir,
75
+ extra_template_data=extra_template_data,
76
+ methods=methods,
77
+ path=path,
78
+ description=description,
79
+ default=default,
80
+ nullable=nullable,
81
+ keyword_only=keyword_only,
82
+ frozen=frozen,
83
+ treat_dot_as_module=treat_dot_as_module,
84
+ )
85
+ if dataclass_arguments is not None:
86
+ self.dataclass_arguments = dataclass_arguments
87
+ else:
88
+ self.dataclass_arguments = {}
89
+ if frozen:
90
+ self.dataclass_arguments["frozen"] = True
91
+ if keyword_only:
92
+ self.dataclass_arguments["kw_only"] = True
93
+
94
+
95
+ class DataModelField(DataModelFieldBase):
96
+ """Field implementation for dataclass models."""
97
+
98
+ _FIELD_KEYS: ClassVar[set[str]] = {
99
+ "default_factory",
100
+ "init",
101
+ "repr",
102
+ "hash",
103
+ "compare",
104
+ "metadata",
105
+ "kw_only",
106
+ }
107
+ constraints: Optional[Constraints] = None # noqa: UP045
108
+
109
+ def process_const(self) -> None:
110
+ """Process const field constraint using literal type."""
111
+ self._process_const_as_literal()
112
+
113
+ @property
114
+ def imports(self) -> tuple[Import, ...]:
115
+ """Get imports including field() if needed."""
116
+ field = self.field
117
+ if field and field.startswith("field("):
118
+ return chain_as_tuple(super().imports, (IMPORT_FIELD,))
119
+ return super().imports
120
+
121
+ @property
122
+ def field(self) -> str | None:
123
+ """For backwards compatibility."""
124
+ result = str(self)
125
+ if not result:
126
+ return None
127
+ return result
128
+
129
+ def __str__(self) -> str:
130
+ """Generate field() call or default value representation."""
131
+ data: dict[str, Any] = {k: v for k, v in self.extras.items() if k in self._FIELD_KEYS}
132
+
133
+ if self.default != UNDEFINED and self.default is not None:
134
+ data["default"] = self.default
135
+
136
+ if self.required:
137
+ data = {
138
+ k: v
139
+ for k, v in data.items()
140
+ if k
141
+ not in {
142
+ "default",
143
+ "default_factory",
144
+ }
145
+ }
146
+
147
+ if not data:
148
+ return ""
149
+
150
+ if len(data) == 1 and "default" in data:
151
+ default = data["default"]
152
+
153
+ if isinstance(default, (list, dict, set)):
154
+ if default:
155
+ from datamodel_code_generator.model.base import repr_set_sorted # noqa: PLC0415
156
+
157
+ default_repr = repr_set_sorted(default) if isinstance(default, set) else repr(default)
158
+ return f"field(default_factory=lambda: {default_repr})"
159
+ return f"field(default_factory={type(default).__name__})"
160
+ return repr(default)
161
+ kwargs = [f"{k}={v if k == 'default_factory' else repr(v)}" for k, v in data.items()]
162
+ return f"field({', '.join(kwargs)})"
163
+
164
+
165
+ class DataTypeManager(_DataTypeManager):
166
+ """Type manager for dataclass models."""
167
+
168
+ def __init__( # noqa: PLR0913, PLR0917
169
+ self,
170
+ python_version: PythonVersion = PythonVersionMin,
171
+ use_standard_collections: bool = False, # noqa: FBT001, FBT002
172
+ use_generic_container_types: bool = False, # noqa: FBT001, FBT002
173
+ strict_types: Sequence[StrictTypes] | None = None,
174
+ use_non_positive_negative_number_constrained_types: bool = False, # noqa: FBT001, FBT002
175
+ use_decimal_for_multiple_of: bool = False, # noqa: FBT001, FBT002
176
+ use_union_operator: bool = False, # noqa: FBT001, FBT002
177
+ use_pendulum: bool = False, # noqa: FBT001, FBT002
178
+ target_datetime_class: DatetimeClassType = DatetimeClassType.Datetime,
179
+ treat_dot_as_module: bool = False, # noqa: FBT001, FBT002
180
+ use_serialize_as_any: bool = False, # noqa: FBT001, FBT002
181
+ ) -> None:
182
+ """Initialize type manager with datetime type mapping."""
183
+ super().__init__(
184
+ python_version,
185
+ use_standard_collections,
186
+ use_generic_container_types,
187
+ strict_types,
188
+ use_non_positive_negative_number_constrained_types,
189
+ use_decimal_for_multiple_of,
190
+ use_union_operator,
191
+ use_pendulum,
192
+ target_datetime_class,
193
+ treat_dot_as_module,
194
+ use_serialize_as_any,
195
+ )
196
+
197
+ datetime_map = (
198
+ {
199
+ Types.time: self.data_type.from_import(IMPORT_TIME),
200
+ Types.date: self.data_type.from_import(IMPORT_DATE),
201
+ Types.date_time: self.data_type.from_import(IMPORT_DATETIME),
202
+ Types.timedelta: self.data_type.from_import(IMPORT_TIMEDELTA),
203
+ }
204
+ if target_datetime_class is DatetimeClassType.Datetime
205
+ else {}
206
+ )
207
+
208
+ self.type_map: dict[Types, DataType] = {
209
+ **type_map_factory(self.data_type),
210
+ **datetime_map,
211
+ }
@@ -1,38 +1,159 @@
1
- from typing import Any, ClassVar, Optional, Tuple
1
+ """Enumeration model generator.
2
2
 
3
- from datamodel_code_generator.imports import IMPORT_ANY, IMPORT_ENUM, Import
3
+ Provides Enum, StrEnum, and specialized enum classes for code generation.
4
+ """
5
+
6
+ from __future__ import annotations
7
+
8
+ from typing import TYPE_CHECKING, Any, ClassVar, Optional
9
+
10
+ from datamodel_code_generator.imports import IMPORT_ANY, IMPORT_ENUM, IMPORT_INT_ENUM, IMPORT_STR_ENUM, Import
4
11
  from datamodel_code_generator.model import DataModel, DataModelFieldBase
12
+ from datamodel_code_generator.model.base import UNDEFINED, BaseClassDataType
5
13
  from datamodel_code_generator.types import DataType, Types
6
14
 
15
+ if TYPE_CHECKING:
16
+ from collections import defaultdict
17
+ from pathlib import Path
18
+
19
+ from datamodel_code_generator.reference import Reference
20
+
21
+
22
+ _INT: str = "int"
23
+ _FLOAT: str = "float"
24
+ _BYTES: str = "bytes"
25
+ _STR: str = "str"
26
+
27
+ SUBCLASS_BASE_CLASSES: dict[Types, str] = {
28
+ Types.int32: _INT,
29
+ Types.int64: _INT,
30
+ Types.integer: _INT,
31
+ Types.float: _FLOAT,
32
+ Types.double: _FLOAT,
33
+ Types.number: _FLOAT,
34
+ Types.byte: _BYTES,
35
+ Types.string: _STR,
36
+ }
37
+
7
38
 
8
39
  class Enum(DataModel):
9
- TEMPLATE_FILE_PATH: ClassVar[str] = 'Enum.jinja2'
10
- BASE_CLASS: ClassVar[str] = 'enum.Enum'
11
- DEFAULT_IMPORTS: ClassVar[Tuple[Import, ...]] = (IMPORT_ENUM,)
40
+ """DataModel implementation for Python enumerations."""
41
+
42
+ TEMPLATE_FILE_PATH: ClassVar[str] = "Enum.jinja2"
43
+ BASE_CLASS: ClassVar[str] = "enum.Enum"
44
+ DEFAULT_IMPORTS: ClassVar[tuple[Import, ...]] = (IMPORT_ENUM,)
45
+
46
+ def __init__( # noqa: PLR0913
47
+ self,
48
+ *,
49
+ reference: Reference,
50
+ fields: list[DataModelFieldBase],
51
+ decorators: list[str] | None = None,
52
+ base_classes: list[Reference] | None = None,
53
+ custom_base_class: str | None = None,
54
+ custom_template_dir: Path | None = None,
55
+ extra_template_data: defaultdict[str, dict[str, Any]] | None = None,
56
+ methods: list[str] | None = None,
57
+ path: Path | None = None,
58
+ description: str | None = None,
59
+ type_: Types | None = None,
60
+ default: Any = UNDEFINED,
61
+ nullable: bool = False,
62
+ keyword_only: bool = False,
63
+ treat_dot_as_module: bool = False,
64
+ ) -> None:
65
+ """Initialize Enum with optional specialized base class based on type."""
66
+ super().__init__(
67
+ reference=reference,
68
+ fields=fields,
69
+ decorators=decorators,
70
+ base_classes=base_classes,
71
+ custom_base_class=custom_base_class,
72
+ custom_template_dir=custom_template_dir,
73
+ extra_template_data=extra_template_data,
74
+ methods=methods,
75
+ path=path,
76
+ description=description,
77
+ default=default,
78
+ nullable=nullable,
79
+ keyword_only=keyword_only,
80
+ treat_dot_as_module=treat_dot_as_module,
81
+ )
82
+ if not base_classes and type_ and (base_class := SUBCLASS_BASE_CLASSES.get(type_)):
83
+ self.base_classes: list[BaseClassDataType] = [
84
+ BaseClassDataType(type=base_class),
85
+ *self.base_classes,
86
+ ]
12
87
 
13
88
  @classmethod
14
89
  def get_data_type(cls, types: Types, **kwargs: Any) -> DataType:
90
+ """Get data type for enum (not implemented)."""
15
91
  raise NotImplementedError
16
92
 
17
- def get_member(self, field: DataModelFieldBase) -> 'Member':
93
+ def get_member(self, field: DataModelFieldBase) -> Member:
94
+ """Create a Member instance for the given field."""
18
95
  return Member(self, field)
19
96
 
20
- def find_member(self, value: Any) -> Optional['Member']:
97
+ def find_member(self, value: Any) -> Member | None:
98
+ """Find enum member matching the given value."""
21
99
  repr_value = repr(value)
22
- for field in self.fields: # pragma: no cover
23
- if field.default == repr_value:
100
+ # Remove surrounding quotes from the string representation
101
+ str_value = str(value).strip("'\"")
102
+
103
+ for field in self.fields:
104
+ # Remove surrounding quotes from field default value
105
+ field_default = str(field.default or "").strip("'\"")
106
+
107
+ # Compare values after removing quotes
108
+ if field_default == str_value:
24
109
  return self.get_member(field)
25
- return None # pragma: no cover
110
+
111
+ # Keep original comparison for backwards compatibility
112
+ if field.default == repr_value: # pragma: no cover
113
+ return self.get_member(field)
114
+
115
+ return None
26
116
 
27
117
  @property
28
- def imports(self) -> Tuple[Import, ...]:
118
+ def imports(self) -> tuple[Import, ...]:
119
+ """Get imports excluding Any."""
29
120
  return tuple(i for i in super().imports if i != IMPORT_ANY)
30
121
 
31
122
 
123
+ class StrEnum(Enum):
124
+ """String enumeration type."""
125
+
126
+ BASE_CLASS: ClassVar[str] = "enum.StrEnum"
127
+ DEFAULT_IMPORTS: ClassVar[tuple[Import, ...]] = (IMPORT_STR_ENUM,)
128
+
129
+
130
+ class IntEnum(Enum):
131
+ """Integer enumeration type."""
132
+
133
+ BASE_CLASS: ClassVar[str] = "enum.IntEnum"
134
+ DEFAULT_IMPORTS: ClassVar[tuple[Import, ...]] = (IMPORT_INT_ENUM,)
135
+
136
+
137
+ SPECIALIZED_ENUM_TYPE_MATCH: dict[Types, type[Enum]] = {
138
+ Types.int32: IntEnum,
139
+ Types.int64: IntEnum,
140
+ Types.integer: IntEnum,
141
+ Types.string: StrEnum,
142
+ }
143
+ """
144
+ Map specialized enum types to their corresponding Enum subclasses.
145
+ """
146
+
147
+
32
148
  class Member:
149
+ """Represents an enum member with its parent enum and field."""
150
+
33
151
  def __init__(self, enum: Enum, field: DataModelFieldBase) -> None:
152
+ """Initialize enum member."""
34
153
  self.enum: Enum = enum
35
154
  self.field: DataModelFieldBase = field
155
+ self.alias: Optional[str] = None # noqa: UP045
36
156
 
37
157
  def __repr__(self) -> str:
38
- return f'{self.enum.name}.{self.field.name}'
158
+ """Return string representation of enum member."""
159
+ return f"{self.alias or self.enum.class_name}.{self.field.name}"
@@ -0,0 +1,22 @@
1
+ """Import definitions for model modules.
2
+
3
+ Provides pre-defined Import objects for dataclasses, TypedDict, msgspec, etc.
4
+ """
5
+
6
+ from __future__ import annotations
7
+
8
+ from datamodel_code_generator.imports import Import
9
+
10
+ IMPORT_DATACLASS = Import.from_full_path("dataclasses.dataclass")
11
+ IMPORT_FIELD = Import.from_full_path("dataclasses.field")
12
+ IMPORT_CLASSVAR = Import.from_full_path("typing.ClassVar")
13
+ IMPORT_TYPED_DICT = Import.from_full_path("typing.TypedDict")
14
+ IMPORT_TYPED_DICT_BACKPORT = Import.from_full_path("typing_extensions.TypedDict")
15
+ IMPORT_NOT_REQUIRED = Import.from_full_path("typing.NotRequired")
16
+ IMPORT_NOT_REQUIRED_BACKPORT = Import.from_full_path("typing_extensions.NotRequired")
17
+ IMPORT_MSGSPEC_STRUCT = Import.from_full_path("msgspec.Struct")
18
+ IMPORT_MSGSPEC_FIELD = Import.from_full_path("msgspec.field")
19
+ IMPORT_MSGSPEC_META = Import.from_full_path("msgspec.Meta")
20
+ IMPORT_MSGSPEC_CONVERT = Import.from_full_path("msgspec.convert")
21
+ IMPORT_MSGSPEC_UNSET = Import.from_full_path("msgspec.UNSET")
22
+ IMPORT_MSGSPEC_UNSETTYPE = Import.from_full_path("msgspec.UnsetType")