datamodel-code-generator 0.28.5__py3-none-any.whl → 0.30.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.

@@ -287,6 +287,7 @@ def generate( # noqa: PLR0912, PLR0913, PLR0914, PLR0915
287
287
  keyword_only: bool = False,
288
288
  no_alias: bool = False,
289
289
  formatters: list[Formatter] = DEFAULT_FORMATTERS,
290
+ parent_scoped_naming: bool = False,
290
291
  ) -> None:
291
292
  remote_text_cache: DefaultPutDict[str, str] = DefaultPutDict()
292
293
  if isinstance(input_, str):
@@ -482,6 +483,8 @@ def generate( # noqa: PLR0912, PLR0913, PLR0914, PLR0915
482
483
  keyword_only=keyword_only,
483
484
  no_alias=no_alias,
484
485
  formatters=formatters,
486
+ encoding=encoding,
487
+ parent_scoped_naming=parent_scoped_naming,
485
488
  **kwargs,
486
489
  )
487
490
 
@@ -314,6 +314,7 @@ class Config(BaseModel):
314
314
  keyword_only: bool = False
315
315
  no_alias: bool = False
316
316
  formatters: list[Formatter] = DEFAULT_FORMATTERS
317
+ parent_scoped_naming: bool = False
317
318
 
318
319
  def merge_args(self, args: Namespace) -> None:
319
320
  set_args = {f: getattr(args, f) for f in self.get_fields() if getattr(args, f) is not None}
@@ -329,7 +330,7 @@ class Config(BaseModel):
329
330
  setattr(self, field_name, getattr(parsed_args, field_name))
330
331
 
331
332
 
332
- def _get_pyproject_toml_config(source: Path) -> dict[str, Any] | None:
333
+ def _get_pyproject_toml_config(source: Path) -> dict[str, Any]:
333
334
  """Find and return the [tool.datamodel-codgen] section of the closest
334
335
  pyproject.toml if it exists.
335
336
  """
@@ -339,14 +340,20 @@ def _get_pyproject_toml_config(source: Path) -> dict[str, Any] | None:
339
340
  if (current_path / "pyproject.toml").is_file():
340
341
  pyproject_toml = load_toml(current_path / "pyproject.toml")
341
342
  if "datamodel-codegen" in pyproject_toml.get("tool", {}):
342
- return pyproject_toml["tool"]["datamodel-codegen"]
343
+ pyproject_config = pyproject_toml["tool"]["datamodel-codegen"]
344
+ # Convert options from kebap- to snake-case
345
+ pyproject_config = {k.replace("-", "_"): v for k, v in pyproject_config.items()}
346
+ # Replace US-american spelling if present (ignore if british spelling is present)
347
+ if "capitalize_enum_members" in pyproject_config and "capitalise_enum_members" not in pyproject_config:
348
+ pyproject_config["capitalise_enum_members"] = pyproject_config.pop("capitalize_enum_members")
349
+ return pyproject_config
343
350
 
344
351
  if (current_path / ".git").exists():
345
352
  # Stop early if we see a git repository root.
346
- return None
353
+ return {}
347
354
 
348
355
  current_path = current_path.parent
349
- return None
356
+ return {}
350
357
 
351
358
 
352
359
  def main(args: Sequence[str] | None = None) -> Exit: # noqa: PLR0911, PLR0912, PLR0915
@@ -367,13 +374,9 @@ def main(args: Sequence[str] | None = None) -> Exit: # noqa: PLR0911, PLR0912,
367
374
  sys.exit(0)
368
375
 
369
376
  pyproject_config = _get_pyproject_toml_config(Path.cwd())
370
- if pyproject_config is not None:
371
- pyproject_toml = {k.replace("-", "_"): v for k, v in pyproject_config.items()}
372
- else:
373
- pyproject_toml = {}
374
377
 
375
378
  try:
376
- config = Config.parse_obj(pyproject_toml)
379
+ config = Config.parse_obj(pyproject_config)
377
380
  config.merge_args(namespace)
378
381
  except Error as e:
379
382
  print(e.message, file=sys.stderr) # noqa: T201
@@ -523,6 +526,7 @@ def main(args: Sequence[str] | None = None) -> Exit: # noqa: PLR0911, PLR0912,
523
526
  keyword_only=config.keyword_only,
524
527
  no_alias=config.no_alias,
525
528
  formatters=config.formatters,
529
+ parent_scoped_naming=config.parent_scoped_naming,
526
530
  )
527
531
  except InvalidClassNameError as e:
528
532
  print(f"{e} You have to set `--class-name` option", file=sys.stderr) # noqa: T201
@@ -202,6 +202,12 @@ model_options.add_argument(
202
202
  choices=[i.value for i in DatetimeClassType],
203
203
  default=None,
204
204
  )
205
+ model_options.add_argument(
206
+ "--parent-scoped-naming",
207
+ help="Set name of models defined inline from the parent model",
208
+ action="store_true",
209
+ default=None,
210
+ )
205
211
 
206
212
  # ======================================================================================
207
213
  # Typing options for generated models
@@ -1,3 +1,11 @@
1
+ {% if base_class != "BaseModel" and "," not in base_class and not fields and not config -%}
2
+
3
+ {# if this is just going to be `class Foo(Bar): pass`, then might as well just make Foo
4
+ an alias for Bar: every pydantic model class consumes considerable memory. #}
5
+ {{ class_name }} = {{ base_class }}
6
+
7
+ {% else -%}
8
+
1
9
  {% for decorator in decorators -%}
2
10
  {{ decorator }}
3
11
  {% endfor -%}
@@ -37,3 +45,5 @@ class {{ class_name }}({{ base_class }}):{% if comment is defined %} # {{ comme
37
45
  {{ method }}
38
46
  {%- endfor -%}
39
47
  {%- endfor -%}
48
+
49
+ {%- endif %}
@@ -377,6 +377,7 @@ class Parser(ABC):
377
377
  keyword_only: bool = False,
378
378
  no_alias: bool = False,
379
379
  formatters: list[Formatter] = DEFAULT_FORMATTERS,
380
+ parent_scoped_naming: bool = False,
380
381
  ) -> None:
381
382
  self.keyword_only = keyword_only
382
383
  self.data_type_manager: DataTypeManager = data_type_manager_type(
@@ -463,6 +464,7 @@ class Parser(ABC):
463
464
  remove_special_field_name_prefix=remove_special_field_name_prefix,
464
465
  capitalise_enum_members=capitalise_enum_members,
465
466
  no_alias=no_alias,
467
+ parent_scoped_naming=parent_scoped_naming,
466
468
  )
467
469
  self.class_name: str | None = class_name
468
470
  self.wrap_string_literal: bool | None = wrap_string_literal
@@ -949,10 +951,14 @@ class Parser(ABC):
949
951
  model_field.constraints = ConstraintsBase.merge_constraints(
950
952
  root_type_field.constraints, model_field.constraints
951
953
  )
952
- if isinstance(
953
- root_type_field,
954
- pydantic_model.DataModelField,
955
- ) and not model_field.extras.get("discriminator"):
954
+ if (
955
+ isinstance(
956
+ root_type_field,
957
+ pydantic_model.DataModelField,
958
+ )
959
+ and not model_field.extras.get("discriminator")
960
+ and not any(t.is_list for t in model_field.data_type.data_types)
961
+ ):
956
962
  discriminator = root_type_field.extras.get("discriminator")
957
963
  if discriminator:
958
964
  model_field.extras["discriminator"] = discriminator
@@ -1148,7 +1154,7 @@ class Parser(ABC):
1148
1154
  else:
1149
1155
  r.append(item)
1150
1156
 
1151
- r = r[:-2] + [f"{r[-2]}.{r[-1]}"]
1157
+ r = [*r[:-2], f"{r[-2]}.{r[-1]}"]
1152
1158
  return tuple(r)
1153
1159
 
1154
1160
  results = {process(k): v for k, v in results.items()}
@@ -1184,6 +1190,24 @@ class Parser(ABC):
1184
1190
  class_name=True,
1185
1191
  ).name
1186
1192
 
1193
+ def __alias_shadowed_imports( # noqa: PLR6301
1194
+ self,
1195
+ models: list[DataModel],
1196
+ all_model_field_names: set[str],
1197
+ ) -> None:
1198
+ for model in models:
1199
+ for model_field in model.fields:
1200
+ if model_field.data_type.type in all_model_field_names:
1201
+ alias = model_field.data_type.type + "_aliased"
1202
+ model_field.data_type.type = alias
1203
+ if model_field.data_type.import_: # pragma: no cover
1204
+ model_field.data_type.import_ = Import(
1205
+ from_=model_field.data_type.import_.from_,
1206
+ import_=model_field.data_type.import_.import_,
1207
+ alias=alias,
1208
+ reference_path=model_field.data_type.import_.reference_path,
1209
+ )
1210
+
1187
1211
  def parse( # noqa: PLR0912, PLR0914, PLR0915
1188
1212
  self,
1189
1213
  with_import: bool | None = True, # noqa: FBT001, FBT002
@@ -1278,6 +1302,7 @@ class Parser(ABC):
1278
1302
  all_module_fields = {field.name for model in models for field in model.fields if field.name is not None}
1279
1303
  scoped_model_resolver = ModelResolver(exclude_names=all_module_fields)
1280
1304
 
1305
+ self.__alias_shadowed_imports(models, all_module_fields)
1281
1306
  self.__override_required_field(models)
1282
1307
  self.__replace_unique_list_to_set(models)
1283
1308
  self.__change_from_import(models, imports, scoped_model_resolver, init)
@@ -154,6 +154,7 @@ class GraphQLParser(Parser):
154
154
  keyword_only: bool = False,
155
155
  no_alias: bool = False,
156
156
  formatters: list[Formatter] = DEFAULT_FORMATTERS,
157
+ parent_scoped_naming: bool = False,
157
158
  ) -> None:
158
159
  super().__init__(
159
160
  source=source,
@@ -228,6 +229,7 @@ class GraphQLParser(Parser):
228
229
  keyword_only=keyword_only,
229
230
  no_alias=no_alias,
230
231
  formatters=formatters,
232
+ parent_scoped_naming=parent_scoped_naming,
231
233
  )
232
234
 
233
235
  self.data_model_scalar_type = data_model_scalar_type
@@ -423,6 +423,7 @@ class JsonSchemaParser(Parser):
423
423
  keyword_only: bool = False,
424
424
  no_alias: bool = False,
425
425
  formatters: list[Formatter] = DEFAULT_FORMATTERS,
426
+ parent_scoped_naming: bool = False,
426
427
  ) -> None:
427
428
  super().__init__(
428
429
  source=source,
@@ -497,6 +498,7 @@ class JsonSchemaParser(Parser):
497
498
  keyword_only=keyword_only,
498
499
  no_alias=no_alias,
499
500
  formatters=formatters,
501
+ parent_scoped_naming=parent_scoped_naming,
500
502
  )
501
503
 
502
504
  self.remote_object_cache: DefaultPutDict[str, dict[str, Any]] = DefaultPutDict()
@@ -216,6 +216,7 @@ class OpenAPIParser(JsonSchemaParser):
216
216
  keyword_only: bool = False,
217
217
  no_alias: bool = False,
218
218
  formatters: list[Formatter] = DEFAULT_FORMATTERS,
219
+ parent_scoped_naming: bool = False,
219
220
  ) -> None:
220
221
  super().__init__(
221
222
  source=source,
@@ -290,6 +291,7 @@ class OpenAPIParser(JsonSchemaParser):
290
291
  keyword_only=keyword_only,
291
292
  no_alias=no_alias,
292
293
  formatters=formatters,
294
+ parent_scoped_naming=parent_scoped_naming,
293
295
  )
294
296
  self.open_api_scopes: list[OpenAPIScope] = openapi_scopes or [OpenAPIScope.Schemas]
295
297
 
@@ -318,6 +318,7 @@ class ModelResolver: # noqa: PLR0904
318
318
  capitalise_enum_members: bool = False, # noqa: FBT001, FBT002
319
319
  no_alias: bool = False, # noqa: FBT001, FBT002
320
320
  remove_suffix_number: bool = False, # noqa: FBT001, FBT002
321
+ parent_scoped_naming: bool = False, # noqa: FBT001, FBT002
321
322
  ) -> None:
322
323
  self.references: dict[str, Reference] = {}
323
324
  self._current_root: Sequence[str] = []
@@ -351,6 +352,7 @@ class ModelResolver: # noqa: PLR0904
351
352
  self._base_path: Path = base_path or Path.cwd()
352
353
  self._current_base_path: Path | None = self._base_path
353
354
  self.remove_suffix_number: bool = remove_suffix_number
355
+ self.parent_scoped_naming = parent_scoped_naming
354
356
 
355
357
  @property
356
358
  def current_base_path(self) -> Path | None:
@@ -512,6 +514,19 @@ class ModelResolver: # noqa: PLR0904
512
514
  self.references[path] = reference
513
515
  return reference
514
516
 
517
+ def _check_parent_scope_option(self, name: str, path: Sequence[str]) -> str:
518
+ if self.parent_scoped_naming:
519
+ parent_reference = None
520
+ parent_path = path[:-1]
521
+ while parent_path:
522
+ parent_reference = self.references.get(self.join_path(parent_path))
523
+ if parent_reference is not None:
524
+ break
525
+ parent_path = parent_path[:-1]
526
+ if parent_reference:
527
+ name = f"{parent_reference.name}_{name}"
528
+ return name
529
+
515
530
  def add( # noqa: PLR0913
516
531
  self,
517
532
  path: Sequence[str],
@@ -533,6 +548,7 @@ class ModelResolver: # noqa: PLR0904
533
548
  name = original_name
534
549
  duplicate_name: str | None = None
535
550
  if class_name:
551
+ name = self._check_parent_scope_option(name, path)
536
552
  name, duplicate_name = self.get_class_name(
537
553
  name=name,
538
554
  unique=unique,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: datamodel-code-generator
3
- Version: 0.28.5
3
+ Version: 0.30.0
4
4
  Summary: Datamodel Code Generator
5
5
  Project-URL: Homepage, https://github.com/koxudaxi/datamodel-code-generator
6
6
  Project-URL: Source, https://github.com/koxudaxi/datamodel-code-generator
@@ -21,7 +21,7 @@ Requires-Python: >=3.9
21
21
  Requires-Dist: argcomplete<4,>=2.10.1
22
22
  Requires-Dist: black>=19.10b0
23
23
  Requires-Dist: genson<2,>=1.2.1
24
- Requires-Dist: inflect<6,>=4.1
24
+ Requires-Dist: inflect<8,>=4.1
25
25
  Requires-Dist: isort<7,>=4.3.21
26
26
  Requires-Dist: jinja2<4,>=2.10.1
27
27
  Requires-Dist: packaging
@@ -512,6 +512,8 @@ Model customization:
512
512
  Choose Datetime class between AwareDatetime, NaiveDatetime or
513
513
  datetime. Each output model has its default mapping (for example
514
514
  pydantic: datetime, dataclass: str, ...)
515
+ --parent-scoped-naming
516
+ Set name of models defined inline from the parent model
515
517
  --reuse-model Reuse models on the field when a module has the model with the same
516
518
  content
517
519
  --target-python-version {3.9,3.10,3.11,3.12,3.13}
@@ -1,12 +1,12 @@
1
- datamodel_code_generator/__init__.py,sha256=sguYwixd5tfTNpa0TwfKFiYqEgwunUaVY2Aea7mCavk,20327
2
- datamodel_code_generator/__main__.py,sha256=LMD988WjkqmzWjHXoNiiEI3KFnrq3kupbyiObDf1HpA,22137
3
- datamodel_code_generator/arguments.py,sha256=LQyCC7tsDdy7ie7nbQVVW_79usVumX8O5pd99ZZ51ds,16466
1
+ datamodel_code_generator/__init__.py,sha256=2h8FA8O_x1VGRVlXKJHt3jwuC34MIEnmHwHv-zGuF_I,20445
2
+ datamodel_code_generator/__main__.py,sha256=rF1Se8R0rfqDmJ4_INBdOYlU7G4XIthPCe3ldDwtgQI,22608
3
+ datamodel_code_generator/arguments.py,sha256=xPAnid2-dC_Hj4o1hY9fL13NMJl5wCPphTsCHZ3QeNQ,16637
4
4
  datamodel_code_generator/format.py,sha256=zvX0KH1uWwGnTYoVM4KhAuKZn5erjkH5eyi4t3leirw,8962
5
5
  datamodel_code_generator/http.py,sha256=LE94GC7I9D8lWIg_YAGWedfy0XNxOXTmiYKuNMTwouo,887
6
6
  datamodel_code_generator/imports.py,sha256=Nq83WbEGCegntg3WX4VbKfzAIs84alZ7IrYyNPrlUbc,5517
7
7
  datamodel_code_generator/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
8
  datamodel_code_generator/pydantic_patch.py,sha256=co1IUDvZqQ-xEZ3C9gbV-BVm2Cin1vfyZNr2Dr0LdHY,718
9
- datamodel_code_generator/reference.py,sha256=cnD6gGevRomez1dr16-KBz-GgDN8gCMQZqpwmb16CwA,26021
9
+ datamodel_code_generator/reference.py,sha256=OobfjN5hWaKzv4ECdCPc9Q3ODkoG93B4qaKlzDEcDrY,26748
10
10
  datamodel_code_generator/types.py,sha256=fobUZnNTOGpzF4qZMraoLogVkAU7zBdFVG-8SOFoDD4,21163
11
11
  datamodel_code_generator/util.py,sha256=mZW8-6CbFe6T4IY5OM9Av6cH-0VknQGe2eIKjTM6Jzo,2729
12
12
  datamodel_code_generator/model/__init__.py,sha256=pJlJ1juQ-Gv17ZKXy6OAfJSSoOAmYQ7QCbdneu1BENU,3594
@@ -44,16 +44,16 @@ datamodel_code_generator/model/template/pydantic/BaseModel.jinja2,sha256=sYZa-47
44
44
  datamodel_code_generator/model/template/pydantic/BaseModel_root.jinja2,sha256=WDdTXYNTrkIw-B4OvPVxOaETTknLs0zdNuq_iDQ2Bcw,1000
45
45
  datamodel_code_generator/model/template/pydantic/Config.jinja2,sha256=Ik028qdqQhDfEP207TCbwVv2b5Do1-nRNDPKzBHKzwM,135
46
46
  datamodel_code_generator/model/template/pydantic/dataclass.jinja2,sha256=hM4OZTVhtOokqlPNSdh5drhBXfQLPvbyO88jipSPr5Y,629
47
- datamodel_code_generator/model/template/pydantic_v2/BaseModel.jinja2,sha256=XdSCvA0hSdjkMtI9CA3M-2xBgieCOV-sWIfQvJPnJ4I,1119
47
+ datamodel_code_generator/model/template/pydantic_v2/BaseModel.jinja2,sha256=i1Wg9W20c4UGUkGJUf2rjuRNO52zLbktndfYupgJA78,1442
48
48
  datamodel_code_generator/model/template/pydantic_v2/ConfigDict.jinja2,sha256=xHvBYrh__32O1xRCSl6_u5zbyYIjB8a5k8fZiTo0spY,149
49
49
  datamodel_code_generator/model/template/pydantic_v2/RootModel.jinja2,sha256=XQBlML7Hm5hN6_AExENNvVc_yxNWijcIfTTbbmegCpE,1223
50
50
  datamodel_code_generator/parser/__init__.py,sha256=3XtFcDPocaetfjmWFqj_CubqNCDipb7vXZHsYKdJXXU,851
51
- datamodel_code_generator/parser/base.py,sha256=COceRiOHtaOOS0gvDvKLNboxD4KY0ofJdmSdoyPBfNw,60618
52
- datamodel_code_generator/parser/graphql.py,sha256=ODbkMp42fYh8kH81KNeAffcFTmJb6_hgMyCsLUmdpMo,22585
53
- datamodel_code_generator/parser/jsonschema.py,sha256=J5Ec5Vf4LGjCRWPraBmpTkepq-tN0ri5MKB9bUSDdFc,69912
54
- datamodel_code_generator/parser/openapi.py,sha256=MfHSVfwq7qx_YEOiNel-ABbwISdH-kp87Q09WeNr_5w,27180
55
- datamodel_code_generator-0.28.5.dist-info/METADATA,sha256=UVX-nQFVHIBUGD1dqfDNsZ4qw4eOyiOsQI8MzkGrKUs,25189
56
- datamodel_code_generator-0.28.5.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
57
- datamodel_code_generator-0.28.5.dist-info/entry_points.txt,sha256=cJVcHiEViQMANaoM5C1xR5hzmyCqH6hHHMpV8W00in8,77
58
- datamodel_code_generator-0.28.5.dist-info/licenses/LICENSE,sha256=K54Lwc6_jduycsy8oFFjQEeSSuEiqvVIjCGIXOMnuTQ,1068
59
- datamodel_code_generator-0.28.5.dist-info/RECORD,,
51
+ datamodel_code_generator/parser/base.py,sha256=iI57e61U2YgG9K8vuBjw72dM034bgsBrfOFL1zG7Y-w,61839
52
+ datamodel_code_generator/parser/graphql.py,sha256=scotG-q8zTS40i5rP9HfhriSVhXVnxEKtuBoXvbzECg,22684
53
+ datamodel_code_generator/parser/jsonschema.py,sha256=bwXNvXjG8tiUPCNZsEXbo2TlCYJVKIzeYWEKfvlPzo8,70011
54
+ datamodel_code_generator/parser/openapi.py,sha256=3IWF40DK0a710rVqXCod7Hi3Fh9u7neD4YR_kn_6VD4,27279
55
+ datamodel_code_generator-0.30.0.dist-info/METADATA,sha256=u9lGxU2--PWj6uTxDi6AA-Dvyw06mhn2KQy_j4ewbds,25294
56
+ datamodel_code_generator-0.30.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
57
+ datamodel_code_generator-0.30.0.dist-info/entry_points.txt,sha256=cJVcHiEViQMANaoM5C1xR5hzmyCqH6hHHMpV8W00in8,77
58
+ datamodel_code_generator-0.30.0.dist-info/licenses/LICENSE,sha256=K54Lwc6_jduycsy8oFFjQEeSSuEiqvVIjCGIXOMnuTQ,1068
59
+ datamodel_code_generator-0.30.0.dist-info/RECORD,,