datamodel-code-generator 0.18.1__tar.gz → 0.20.0__tar.gz

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.

Files changed (43) hide show
  1. {datamodel_code_generator-0.18.1 → datamodel_code_generator-0.20.0}/PKG-INFO +12 -51
  2. {datamodel_code_generator-0.18.1 → datamodel_code_generator-0.20.0}/README.md +10 -43
  3. {datamodel_code_generator-0.18.1 → datamodel_code_generator-0.20.0}/datamodel_code_generator/__init__.py +10 -4
  4. {datamodel_code_generator-0.18.1 → datamodel_code_generator-0.20.0}/datamodel_code_generator/__main__.py +23 -1
  5. {datamodel_code_generator-0.18.1 → datamodel_code_generator-0.20.0}/datamodel_code_generator/format.py +32 -2
  6. {datamodel_code_generator-0.18.1 → datamodel_code_generator-0.20.0}/datamodel_code_generator/imports.py +1 -0
  7. {datamodel_code_generator-0.18.1 → datamodel_code_generator-0.20.0}/datamodel_code_generator/model/__init__.py +17 -3
  8. {datamodel_code_generator-0.18.1 → datamodel_code_generator-0.20.0}/datamodel_code_generator/model/base.py +7 -1
  9. {datamodel_code_generator-0.18.1 → datamodel_code_generator-0.20.0}/datamodel_code_generator/model/dataclass.py +8 -2
  10. datamodel_code_generator-0.20.0/datamodel_code_generator/model/improts.py +8 -0
  11. {datamodel_code_generator-0.18.1 → datamodel_code_generator-0.20.0}/datamodel_code_generator/model/pydantic/types.py +1 -1
  12. datamodel_code_generator-0.20.0/datamodel_code_generator/model/template/TypedDict.jinja2 +5 -0
  13. datamodel_code_generator-0.20.0/datamodel_code_generator/model/template/TypedDictClass.jinja2 +17 -0
  14. datamodel_code_generator-0.20.0/datamodel_code_generator/model/template/TypedDictFunction.jinja2 +16 -0
  15. datamodel_code_generator-0.20.0/datamodel_code_generator/model/typed_dict.py +151 -0
  16. {datamodel_code_generator-0.18.1 → datamodel_code_generator-0.20.0}/datamodel_code_generator/model/types.py +1 -1
  17. {datamodel_code_generator-0.18.1 → datamodel_code_generator-0.20.0}/datamodel_code_generator/parser/base.py +1 -6
  18. {datamodel_code_generator-0.18.1 → datamodel_code_generator-0.20.0}/datamodel_code_generator/parser/jsonschema.py +99 -33
  19. {datamodel_code_generator-0.18.1 → datamodel_code_generator-0.20.0}/datamodel_code_generator/parser/openapi.py +45 -54
  20. {datamodel_code_generator-0.18.1 → datamodel_code_generator-0.20.0}/datamodel_code_generator/types.py +13 -4
  21. datamodel_code_generator-0.20.0/datamodel_code_generator/version.py +1 -0
  22. {datamodel_code_generator-0.18.1 → datamodel_code_generator-0.20.0}/pyproject.toml +5 -7
  23. datamodel_code_generator-0.18.1/datamodel_code_generator/model/improts.py +0 -4
  24. datamodel_code_generator-0.18.1/datamodel_code_generator/version.py +0 -1
  25. {datamodel_code_generator-0.18.1 → datamodel_code_generator-0.20.0}/LICENSE +0 -0
  26. {datamodel_code_generator-0.18.1 → datamodel_code_generator-0.20.0}/datamodel_code_generator/http.py +0 -0
  27. {datamodel_code_generator-0.18.1 → datamodel_code_generator-0.20.0}/datamodel_code_generator/model/enum.py +0 -0
  28. {datamodel_code_generator-0.18.1 → datamodel_code_generator-0.20.0}/datamodel_code_generator/model/pydantic/__init__.py +0 -0
  29. {datamodel_code_generator-0.18.1 → datamodel_code_generator-0.20.0}/datamodel_code_generator/model/pydantic/base_model.py +0 -0
  30. {datamodel_code_generator-0.18.1 → datamodel_code_generator-0.20.0}/datamodel_code_generator/model/pydantic/custom_root_type.py +0 -0
  31. {datamodel_code_generator-0.18.1 → datamodel_code_generator-0.20.0}/datamodel_code_generator/model/pydantic/dataclass.py +0 -0
  32. {datamodel_code_generator-0.18.1 → datamodel_code_generator-0.20.0}/datamodel_code_generator/model/pydantic/imports.py +0 -0
  33. {datamodel_code_generator-0.18.1 → datamodel_code_generator-0.20.0}/datamodel_code_generator/model/rootmodel.py +0 -0
  34. {datamodel_code_generator-0.18.1 → datamodel_code_generator-0.20.0}/datamodel_code_generator/model/template/Enum.jinja2 +0 -0
  35. {datamodel_code_generator-0.18.1 → datamodel_code_generator-0.20.0}/datamodel_code_generator/model/template/dataclass.jinja2 +0 -0
  36. {datamodel_code_generator-0.18.1 → datamodel_code_generator-0.20.0}/datamodel_code_generator/model/template/pydantic/BaseModel.jinja2 +0 -0
  37. {datamodel_code_generator-0.18.1 → datamodel_code_generator-0.20.0}/datamodel_code_generator/model/template/pydantic/BaseModel_root.jinja2 +0 -0
  38. {datamodel_code_generator-0.18.1 → datamodel_code_generator-0.20.0}/datamodel_code_generator/model/template/pydantic/Config.jinja2 +0 -0
  39. {datamodel_code_generator-0.18.1 → datamodel_code_generator-0.20.0}/datamodel_code_generator/model/template/pydantic/dataclass.jinja2 +0 -0
  40. {datamodel_code_generator-0.18.1 → datamodel_code_generator-0.20.0}/datamodel_code_generator/model/template/root.jinja2 +0 -0
  41. {datamodel_code_generator-0.18.1 → datamodel_code_generator-0.20.0}/datamodel_code_generator/parser/__init__.py +0 -0
  42. {datamodel_code_generator-0.18.1 → datamodel_code_generator-0.20.0}/datamodel_code_generator/py.typed +0 -0
  43. {datamodel_code_generator-0.18.1 → datamodel_code_generator-0.20.0}/datamodel_code_generator/reference.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: datamodel-code-generator
3
- Version: 0.18.1
3
+ Version: 0.20.0
4
4
  Summary: Datamodel Code Generator
5
5
  Home-page: https://github.com/koxudaxi/datamodel-code-generator
6
6
  License: MIT
@@ -16,12 +16,6 @@ Classifier: Programming Language :: Python :: 3.8
16
16
  Classifier: Programming Language :: Python :: 3.9
17
17
  Classifier: Programming Language :: Python :: 3.10
18
18
  Classifier: Programming Language :: Python :: 3.11
19
- Classifier: Programming Language :: Python :: 3
20
- Classifier: Programming Language :: Python :: 3.10
21
- Classifier: Programming Language :: Python :: 3.11
22
- Classifier: Programming Language :: Python :: 3.7
23
- Classifier: Programming Language :: Python :: 3.8
24
- Classifier: Programming Language :: Python :: 3.9
25
19
  Classifier: Programming Language :: Python :: Implementation :: CPython
26
20
  Provides-Extra: http
27
21
  Requires-Dist: PySnooper (>=0.4.1,<2.0.0)
@@ -32,7 +26,7 @@ Requires-Dist: httpx ; extra == "http"
32
26
  Requires-Dist: inflect (>=4.1.0,<6.0)
33
27
  Requires-Dist: isort (>=4.3.21,<6.0)
34
28
  Requires-Dist: jinja2 (>=2.10.1,<4.0)
35
- Requires-Dist: openapi-spec-validator (>=0.2.8,<=0.5.1)
29
+ Requires-Dist: openapi-spec-validator (>=0.2.8,<=0.5.2)
36
30
  Requires-Dist: packaging
37
31
  Requires-Dist: prance (>=0.18.2,<1.0)
38
32
  Requires-Dist: pydantic[email] (>=1.10.0,<2.0.0) ; python_version >= "3.11" and python_version < "4.0"
@@ -44,10 +38,11 @@ Description-Content-Type: text/markdown
44
38
 
45
39
  # datamodel-code-generator
46
40
 
47
- This code generator creates [pydantic](https://docs.pydantic.dev/) model and [dataclasses.dataclass](https://docs.python.org/3/library/dataclasses.html) from an openapi file and others.
41
+ This code generator creates [pydantic](https://docs.pydantic.dev/) model, [dataclasses.dataclass](https://docs.python.org/3/library/dataclasses.html) and [typing.TypedDict](https://docs.python.org/3/library/typing.html#typing.TypedDict) from an openapi file and others.
48
42
 
49
43
  [![Build Status](https://github.com/koxudaxi/datamodel-code-generator/workflows/Test/badge.svg)](https://github.com/koxudaxi/datamodel-code-generator/actions?query=workflow%3ATest)
50
44
  [![PyPI version](https://badge.fury.io/py/datamodel-code-generator.svg)](https://pypi.python.org/pypi/datamodel-code-generator)
45
+ [![Conda-forge](https://img.shields.io/conda/v/conda-forge/datamodel-code-generator)](https://anaconda.org/conda-forge/datamodel-code-generator)
51
46
  [![Downloads](https://pepy.tech/badge/datamodel-code-generator/month)](https://pepy.tech/project/datamodel-code-generator)
52
47
  [![PyPI - Python Version](https://img.shields.io/pypi/pyversions/datamodel-code-generator)](https://pypi.python.org/pypi/datamodel-code-generator)
53
48
  [![codecov](https://codecov.io/gh/koxudaxi/datamodel-code-generator/branch/master/graph/badge.svg)](https://codecov.io/gh/koxudaxi/datamodel-code-generator)
@@ -68,7 +63,7 @@ To install `datamodel-code-generator`:
68
63
  $ pip install datamodel-code-generator
69
64
  ```
70
65
 
71
- ## Simple usage
66
+ ## Simple Usage
72
67
  You can generate models from a local file.
73
68
  ```bash
74
69
  $ datamodel-codegen --input api.yaml --output model.py
@@ -278,14 +273,14 @@ class Apis(BaseModel):
278
273
  ```
279
274
  </details>
280
275
 
281
- ## Which project uses it?
282
- These OSS use datamodel-code-generator to generate many models. We can learn about use-cases from these projects.
276
+ ## Projects that use datamodel-code-generator
277
+ These OSS projects use datamodel-code-generator to generate many models. See the following linked projects for real world examples and inspiration.
283
278
  - [Netflix/consoleme](https://github.com/Netflix/consoleme)
284
279
  - *[How do I generate models from the Swagger specification?](https://github.com/Netflix/consoleme/blob/master/docs/gitbook/faq.md#how-do-i-generate-models-from-the-swagger-specification)*
285
280
  - [DataDog/integrations-core](https://github.com/DataDog/integrations-core)
286
281
  - *[Config models](https://github.com/DataDog/integrations-core/blob/master/docs/developer/meta/config-models.md)*
287
282
  - [awslabs/aws-lambda-powertools-python](https://github.com/awslabs/aws-lambda-powertools-python)
288
- - *Not used. But, introduced [advanced-use-cases](https://awslabs.github.io/aws-lambda-powertools-python/2.6.0/utilities/parser/#advanced-use-cases) in the official document*
283
+ - *Recommended for [advanced-use-cases](https://awslabs.github.io/aws-lambda-powertools-python/2.6.0/utilities/parser/#advanced-use-cases) in the official documentation*
289
284
  - [open-metadata/OpenMetadata](https://github.com/open-metadata/OpenMetadata)
290
285
  - [Makefile](https://github.com/open-metadata/OpenMetadata/blob/main/Makefile)
291
286
  - [airbytehq/airbyte](https://github.com/airbytehq/airbyte)
@@ -303,6 +298,7 @@ These OSS use datamodel-code-generator to generate many models. We can learn abo
303
298
  ## Supported output types
304
299
  - [pydantic](https://docs.pydantic.dev/).BaseModel
305
300
  - [dataclasses.dataclass](https://docs.python.org/3/library/dataclasses.html)
301
+ - [typing.TypedDict](https://docs.python.org/3/library/typing.html#typing.TypedDict)
306
302
 
307
303
  ## Installation
308
304
 
@@ -328,7 +324,7 @@ You can genearte models from a URL.
328
324
  ```bash
329
325
  $ datamodel-codegen --url https://<INPUT FILE URL> --output model.py
330
326
  ```
331
- This method needs [http extra option](#http-extra-option)
327
+ This method needs the [http extra option](#http-extra-option)
332
328
 
333
329
 
334
330
  ## All Command Options
@@ -339,7 +335,7 @@ usage: datamodel-codegen [-h] [--input INPUT] [--url URL]
339
335
  [--http-headers HTTP_HEADER [HTTP_HEADER ...]]
340
336
  [--http-ignore-tls]
341
337
  [--input-file-type {auto,openapi,jsonschema,json,yaml,dict,csv}]
342
- [--output-model-type {pydantic.BaseModel,dataclasses.dataclass}]
338
+ [--output-model-type {pydantic.BaseModel,dataclasses.dataclass,typing.TypedDict}]
343
339
  [--openapi-scopes {schemas,paths,tags,parameters} [{schemas,paths,tags,parameters} ...]]
344
340
  [--output OUTPUT] [--base-class BASE_CLASS]
345
341
  [--field-constraints] [--use-annotated]
@@ -390,7 +386,7 @@ options:
390
386
  certificate
391
387
  --input-file-type {auto,openapi,jsonschema,json,yaml,dict,csv}
392
388
  Input file type (default: auto)
393
- --output-model-type {pydantic.BaseModel,dataclasses.dataclass}
389
+ --output-model-type {pydantic.BaseModel,dataclasses.dataclass,typing.TypedDict}
394
390
  Output model type (default: pydantic.BaseModel)
395
391
  --openapi-scopes {schemas,paths,tags,parameters} [{schemas,paths,tags,parameters} ...]
396
392
  Scopes of OpenAPI model generation (default: schemas)
@@ -496,41 +492,6 @@ options:
496
492
  --version show version
497
493
  ```
498
494
 
499
-
500
- ## Implemented list
501
- ### OpenAPI 3 and JsonSchema
502
- #### DataType
503
- - string (include patter/minLength/maxLenght)
504
- - number (include maximum/exclusiveMaximum/minimum/exclusiveMinimum/multipleOf/le/ge)
505
- - integer (include maximum/exclusiveMaximum/minimum/exclusiveMinimum/multipleOf/le/ge)
506
- - boolean
507
- - array
508
- - object
509
-
510
- ##### String Format
511
- - date
512
- - datetime
513
- - time
514
- - password
515
- - email
516
- - idn-email
517
- - uuid (uuid1/uuid2/uuid3/uuid4/uuid5)
518
- - ipv4
519
- - ipv6
520
- - ipv4-network
521
- - ipv6-network
522
- - hostname
523
- - decimal
524
-
525
- #### Other schema
526
- - enum (as enum.Enum or typing.Literal)
527
- - allOf (as Multiple inheritance)
528
- - anyOf (as typing.Union)
529
- - oneOf (as typing.Union)
530
- - $ref ([http extra](#http-extra-option) is required when resolving $ref for remote files.)
531
- - $id (for [JSONSchema](https://json-schema.org/understanding-json-schema/structuring.html#the-id-property))
532
-
533
-
534
495
  ## Related projects
535
496
  ### fastapi-code-generator
536
497
  This code generator creates [FastAPI](https://github.com/tiangolo/fastapi) app from an openapi file.
@@ -1,9 +1,10 @@
1
1
  # datamodel-code-generator
2
2
 
3
- This code generator creates [pydantic](https://docs.pydantic.dev/) model and [dataclasses.dataclass](https://docs.python.org/3/library/dataclasses.html) from an openapi file and others.
3
+ This code generator creates [pydantic](https://docs.pydantic.dev/) model, [dataclasses.dataclass](https://docs.python.org/3/library/dataclasses.html) and [typing.TypedDict](https://docs.python.org/3/library/typing.html#typing.TypedDict) from an openapi file and others.
4
4
 
5
5
  [![Build Status](https://github.com/koxudaxi/datamodel-code-generator/workflows/Test/badge.svg)](https://github.com/koxudaxi/datamodel-code-generator/actions?query=workflow%3ATest)
6
6
  [![PyPI version](https://badge.fury.io/py/datamodel-code-generator.svg)](https://pypi.python.org/pypi/datamodel-code-generator)
7
+ [![Conda-forge](https://img.shields.io/conda/v/conda-forge/datamodel-code-generator)](https://anaconda.org/conda-forge/datamodel-code-generator)
7
8
  [![Downloads](https://pepy.tech/badge/datamodel-code-generator/month)](https://pepy.tech/project/datamodel-code-generator)
8
9
  [![PyPI - Python Version](https://img.shields.io/pypi/pyversions/datamodel-code-generator)](https://pypi.python.org/pypi/datamodel-code-generator)
9
10
  [![codecov](https://codecov.io/gh/koxudaxi/datamodel-code-generator/branch/master/graph/badge.svg)](https://codecov.io/gh/koxudaxi/datamodel-code-generator)
@@ -24,7 +25,7 @@ To install `datamodel-code-generator`:
24
25
  $ pip install datamodel-code-generator
25
26
  ```
26
27
 
27
- ## Simple usage
28
+ ## Simple Usage
28
29
  You can generate models from a local file.
29
30
  ```bash
30
31
  $ datamodel-codegen --input api.yaml --output model.py
@@ -234,14 +235,14 @@ class Apis(BaseModel):
234
235
  ```
235
236
  </details>
236
237
 
237
- ## Which project uses it?
238
- These OSS use datamodel-code-generator to generate many models. We can learn about use-cases from these projects.
238
+ ## Projects that use datamodel-code-generator
239
+ These OSS projects use datamodel-code-generator to generate many models. See the following linked projects for real world examples and inspiration.
239
240
  - [Netflix/consoleme](https://github.com/Netflix/consoleme)
240
241
  - *[How do I generate models from the Swagger specification?](https://github.com/Netflix/consoleme/blob/master/docs/gitbook/faq.md#how-do-i-generate-models-from-the-swagger-specification)*
241
242
  - [DataDog/integrations-core](https://github.com/DataDog/integrations-core)
242
243
  - *[Config models](https://github.com/DataDog/integrations-core/blob/master/docs/developer/meta/config-models.md)*
243
244
  - [awslabs/aws-lambda-powertools-python](https://github.com/awslabs/aws-lambda-powertools-python)
244
- - *Not used. But, introduced [advanced-use-cases](https://awslabs.github.io/aws-lambda-powertools-python/2.6.0/utilities/parser/#advanced-use-cases) in the official document*
245
+ - *Recommended for [advanced-use-cases](https://awslabs.github.io/aws-lambda-powertools-python/2.6.0/utilities/parser/#advanced-use-cases) in the official documentation*
245
246
  - [open-metadata/OpenMetadata](https://github.com/open-metadata/OpenMetadata)
246
247
  - [Makefile](https://github.com/open-metadata/OpenMetadata/blob/main/Makefile)
247
248
  - [airbytehq/airbyte](https://github.com/airbytehq/airbyte)
@@ -259,6 +260,7 @@ These OSS use datamodel-code-generator to generate many models. We can learn abo
259
260
  ## Supported output types
260
261
  - [pydantic](https://docs.pydantic.dev/).BaseModel
261
262
  - [dataclasses.dataclass](https://docs.python.org/3/library/dataclasses.html)
263
+ - [typing.TypedDict](https://docs.python.org/3/library/typing.html#typing.TypedDict)
262
264
 
263
265
  ## Installation
264
266
 
@@ -284,7 +286,7 @@ You can genearte models from a URL.
284
286
  ```bash
285
287
  $ datamodel-codegen --url https://<INPUT FILE URL> --output model.py
286
288
  ```
287
- This method needs [http extra option](#http-extra-option)
289
+ This method needs the [http extra option](#http-extra-option)
288
290
 
289
291
 
290
292
  ## All Command Options
@@ -295,7 +297,7 @@ usage: datamodel-codegen [-h] [--input INPUT] [--url URL]
295
297
  [--http-headers HTTP_HEADER [HTTP_HEADER ...]]
296
298
  [--http-ignore-tls]
297
299
  [--input-file-type {auto,openapi,jsonschema,json,yaml,dict,csv}]
298
- [--output-model-type {pydantic.BaseModel,dataclasses.dataclass}]
300
+ [--output-model-type {pydantic.BaseModel,dataclasses.dataclass,typing.TypedDict}]
299
301
  [--openapi-scopes {schemas,paths,tags,parameters} [{schemas,paths,tags,parameters} ...]]
300
302
  [--output OUTPUT] [--base-class BASE_CLASS]
301
303
  [--field-constraints] [--use-annotated]
@@ -346,7 +348,7 @@ options:
346
348
  certificate
347
349
  --input-file-type {auto,openapi,jsonschema,json,yaml,dict,csv}
348
350
  Input file type (default: auto)
349
- --output-model-type {pydantic.BaseModel,dataclasses.dataclass}
351
+ --output-model-type {pydantic.BaseModel,dataclasses.dataclass,typing.TypedDict}
350
352
  Output model type (default: pydantic.BaseModel)
351
353
  --openapi-scopes {schemas,paths,tags,parameters} [{schemas,paths,tags,parameters} ...]
352
354
  Scopes of OpenAPI model generation (default: schemas)
@@ -452,41 +454,6 @@ options:
452
454
  --version show version
453
455
  ```
454
456
 
455
-
456
- ## Implemented list
457
- ### OpenAPI 3 and JsonSchema
458
- #### DataType
459
- - string (include patter/minLength/maxLenght)
460
- - number (include maximum/exclusiveMaximum/minimum/exclusiveMinimum/multipleOf/le/ge)
461
- - integer (include maximum/exclusiveMaximum/minimum/exclusiveMinimum/multipleOf/le/ge)
462
- - boolean
463
- - array
464
- - object
465
-
466
- ##### String Format
467
- - date
468
- - datetime
469
- - time
470
- - password
471
- - email
472
- - idn-email
473
- - uuid (uuid1/uuid2/uuid3/uuid4/uuid5)
474
- - ipv4
475
- - ipv6
476
- - ipv4-network
477
- - ipv6-network
478
- - hostname
479
- - decimal
480
-
481
- #### Other schema
482
- - enum (as enum.Enum or typing.Literal)
483
- - allOf (as Multiple inheritance)
484
- - anyOf (as typing.Union)
485
- - oneOf (as typing.Union)
486
- - $ref ([http extra](#http-extra-option) is required when resolving $ref for remote files.)
487
- - $id (for [JSONSchema](https://json-schema.org/understanding-json-schema/structuring.html#the-id-property))
488
-
489
-
490
457
  ## Related projects
491
458
  ### fastapi-code-generator
492
459
  This code generator creates [FastAPI](https://github.com/tiangolo/fastapi) app from an openapi file.
@@ -220,6 +220,7 @@ RAW_DATA_TYPES: List[InputFileType] = [
220
220
  class DataModelType(Enum):
221
221
  PydanticBaseModel = 'pydantic.BaseModel'
222
222
  DataclassesDataclass = 'dataclasses.dataclass'
223
+ TypingTypedDict = 'typing.TypedDict'
223
224
 
224
225
 
225
226
  class OpenAPIScope(Enum):
@@ -314,6 +315,7 @@ def generate(
314
315
  capitalise_enum_members: bool = False,
315
316
  keep_model_order: bool = False,
316
317
  custom_file_header: Optional[str] = None,
318
+ custom_file_header_path: Optional[Path] = None,
317
319
  ) -> None:
318
320
  remote_text_cache: DefaultPutDict[str, str] = DefaultPutDict()
319
321
  if isinstance(input_, str):
@@ -397,7 +399,7 @@ def generate(
397
399
 
398
400
  from datamodel_code_generator.model import get_data_model_types
399
401
 
400
- data_model_types = get_data_model_types(output_model_type)
402
+ data_model_types = get_data_model_types(output_model_type, target_python_version)
401
403
  parser = parser_class(
402
404
  source=input_text or input_,
403
405
  data_model_type=data_model_types.data_model,
@@ -427,7 +429,9 @@ def generate(
427
429
  use_field_description=use_field_description,
428
430
  use_default_kwarg=use_default_kwarg,
429
431
  reuse_model=reuse_model,
430
- enum_field_as_literal=enum_field_as_literal,
432
+ enum_field_as_literal=LiteralType.All
433
+ if output_model_type == DataModelType.TypingTypedDict
434
+ else enum_field_as_literal,
431
435
  use_one_literal_as_default=use_one_literal_as_default,
432
436
  set_default_enum_member=set_default_enum_member,
433
437
  use_subclass_enum=use_subclass_enum,
@@ -488,6 +492,9 @@ def generate(
488
492
 
489
493
  timestamp = datetime.now(timezone.utc).replace(microsecond=0).isoformat()
490
494
 
495
+ if custom_file_header is None and custom_file_header_path:
496
+ custom_file_header = custom_file_header_path.read_text(encoding=encoding)
497
+
491
498
  header = """\
492
499
  # generated by datamodel-codegen:
493
500
  # filename: {}"""
@@ -497,8 +504,7 @@ def generate(
497
504
  header += f'\n# version: {get_version()}'
498
505
 
499
506
  file: Optional[IO[Any]]
500
- for path, body_and_filename in modules.items():
501
- body, filename = body_and_filename
507
+ for path, (body, filename) in modules.items():
502
508
  if path is None:
503
509
  file = None
504
510
  else:
@@ -433,6 +433,15 @@ arg_parser.add_argument(
433
433
  arg_parser.add_argument(
434
434
  '--custom-file-header', help='Custom file header', type=str, default=None
435
435
  )
436
+
437
+ arg_parser.add_argument(
438
+ '--custom-file-header-path',
439
+ help='Custom file header file path',
440
+ default=None,
441
+ type=str,
442
+ )
443
+
444
+
436
445
  arg_parser.add_argument('--version', help='show version', action='store_true')
437
446
 
438
447
 
@@ -448,7 +457,9 @@ class Config(BaseModel):
448
457
  return value
449
458
  return cast(TextIOBase, Path(value).expanduser().resolve().open('rt'))
450
459
 
451
- @validator('input', 'output', 'custom_template_dir', pre=True)
460
+ @validator(
461
+ 'input', 'output', 'custom_template_dir', 'custom_file_header_path', pre=True
462
+ )
452
463
  def validate_path(cls, value: Any) -> Optional[Path]:
453
464
  if value is None or isinstance(value, Path):
454
465
  return value # pragma: no cover
@@ -488,6 +499,14 @@ class Config(BaseModel):
488
499
  )
489
500
  return values
490
501
 
502
+ @root_validator
503
+ def validate_custom_file_header(cls, values: Dict[str, Any]) -> Dict[str, Any]:
504
+ if values.get('custom_file_header') and values.get('custom_file_header_path'):
505
+ raise Error(
506
+ '`--custom_file_header_path` can not be used with `--custom_file_header`.'
507
+ ) # pragma: no cover
508
+ return values
509
+
491
510
  # Pydantic 1.5.1 doesn't support each_item=True correctly
492
511
  @validator('http_headers', pre=True)
493
512
  def validate_http_headers(cls, value: Any) -> Optional[List[Tuple[str, str]]]:
@@ -583,6 +602,7 @@ class Config(BaseModel):
583
602
  capitalise_enum_members: bool = False
584
603
  keep_model_order: bool = False
585
604
  custom_file_header: Optional[str] = None
605
+ custom_file_header_path: Optional[Path] = None
586
606
 
587
607
  def merge_args(self, args: Namespace) -> None:
588
608
  set_args = {
@@ -742,6 +762,8 @@ def main(args: Optional[Sequence[str]] = None) -> Exit:
742
762
  remove_special_field_name_prefix=config.remove_special_field_name_prefix,
743
763
  capitalise_enum_members=config.capitalise_enum_members,
744
764
  keep_model_order=config.keep_model_order,
765
+ custom_file_header=config.custom_file_header,
766
+ custom_file_header_path=config.custom_file_header_path,
745
767
  )
746
768
  return Exit.OK
747
769
  except InvalidClassNameError as e:
@@ -9,6 +9,8 @@ import black
9
9
  import isort
10
10
  import toml
11
11
 
12
+ from datamodel_code_generator import cached_property
13
+
12
14
 
13
15
  class PythonVersion(Enum):
14
16
  PY_36 = '3.6'
@@ -18,13 +20,41 @@ class PythonVersion(Enum):
18
20
  PY_310 = '3.10'
19
21
  PY_311 = '3.11'
20
22
 
23
+ @cached_property
24
+ def _is_py_38_or_later(self) -> bool: # pragma: no cover
25
+ return self.value not in {self.PY_36.value, self.PY_37.value} # type: ignore
26
+
27
+ @cached_property
28
+ def _is_py_39_or_later(self) -> bool: # pragma: no cover
29
+ return self.value not in {self.PY_36.value, self.PY_37.value, self.PY_38.value} # type: ignore
30
+
31
+ @cached_property
32
+ def _is_py_310_or_later(self) -> bool: # pragma: no cover
33
+ return self.value not in {self.PY_36.value, self.PY_37.value, self.PY_38.value, self.PY_39.value} # type: ignore
34
+
35
+ @cached_property
36
+ def _is_py_311_or_later(self) -> bool: # pragma: no cover
37
+ return self.value not in {self.PY_36.value, self.PY_37.value, self.PY_38.value, self.PY_39.value, self.PY_310.value} # type: ignore
38
+
21
39
  @property
22
40
  def has_literal_type(self) -> bool:
23
- return self.value not in {self.PY_36.value, self.PY_37.value} # type: ignore
41
+ return self._is_py_38_or_later
24
42
 
25
43
  @property
26
44
  def has_union_operator(self) -> bool: # pragma: no cover
27
- return self.value not in {self.PY_36.value, self.PY_37.value, self.PY_38.value, self.PY_39.value} # type: ignore
45
+ return self._is_py_310_or_later
46
+
47
+ @property
48
+ def has_annotated_type(self) -> bool:
49
+ return self._is_py_39_or_later
50
+
51
+ @property
52
+ def has_typed_dict(self) -> bool:
53
+ return self._is_py_38_or_later
54
+
55
+ @property
56
+ def has_typed_dict_non_required(self) -> bool:
57
+ return self._is_py_311_or_later
28
58
 
29
59
 
30
60
  if TYPE_CHECKING:
@@ -61,6 +61,7 @@ class Imports(DefaultDict[Optional[str], Set[str]]):
61
61
 
62
62
 
63
63
  IMPORT_ANNOTATED = Import.from_full_path('typing.Annotated')
64
+ IMPORT_ANNOTATED_BACKPORT = Import.from_full_path('typing_extensions.Annotated')
64
65
  IMPORT_ANY = Import.from_full_path('typing.Any')
65
66
  IMPORT_LIST = Import.from_full_path('typing.List')
66
67
  IMPORT_UNION = Import.from_full_path('typing.Union')
@@ -6,7 +6,7 @@ from ..types import DataTypeManager as DataTypeManagerABC
6
6
  from .base import ConstraintsBase, DataModel, DataModelFieldBase
7
7
 
8
8
  if TYPE_CHECKING:
9
- from .. import DataModelType
9
+ from .. import DataModelType, PythonVersion
10
10
 
11
11
 
12
12
  class DataModelSet(NamedTuple):
@@ -17,9 +17,11 @@ class DataModelSet(NamedTuple):
17
17
  dump_resolve_reference_action: Optional[Callable[[Iterable[str]], str]]
18
18
 
19
19
 
20
- def get_data_model_types(data_model_type: DataModelType) -> DataModelSet:
20
+ def get_data_model_types(
21
+ data_model_type: DataModelType, target_python_version: PythonVersion
22
+ ) -> DataModelSet:
21
23
  from .. import DataModelType
22
- from . import dataclass, pydantic, rootmodel
24
+ from . import dataclass, pydantic, rootmodel, typed_dict
23
25
  from .types import DataTypeManager
24
26
 
25
27
  if data_model_type == DataModelType.PydanticBaseModel:
@@ -38,6 +40,18 @@ def get_data_model_types(data_model_type: DataModelType) -> DataModelSet:
38
40
  data_type_manager=DataTypeManager,
39
41
  dump_resolve_reference_action=None,
40
42
  )
43
+ elif data_model_type == DataModelType.TypingTypedDict:
44
+ return DataModelSet(
45
+ data_model=typed_dict.TypedDict
46
+ if target_python_version.has_typed_dict
47
+ else typed_dict.TypedDictBackport,
48
+ root_model=rootmodel.RootModel,
49
+ field_model=typed_dict.DataModelField
50
+ if target_python_version.has_typed_dict_non_required
51
+ else typed_dict.DataModelFieldBackport,
52
+ data_type_manager=DataTypeManager,
53
+ dump_resolve_reference_action=None,
54
+ )
41
55
  raise ValueError(
42
56
  f'{data_model_type} is unsupported data model type'
43
57
  ) # pragma: no cover
@@ -25,6 +25,7 @@ from jinja2 import Environment, FileSystemLoader, Template
25
25
  from datamodel_code_generator import cached_property
26
26
  from datamodel_code_generator.imports import (
27
27
  IMPORT_ANNOTATED,
28
+ IMPORT_ANNOTATED_BACKPORT,
28
29
  IMPORT_OPTIONAL,
29
30
  IMPORT_UNION,
30
31
  Import,
@@ -125,7 +126,12 @@ class DataModelFieldBase(_BaseModel):
125
126
  ) and not self.data_type.use_union_operator:
126
127
  imports.append((IMPORT_OPTIONAL,))
127
128
  if self.use_annotated:
128
- imports.append((IMPORT_ANNOTATED,))
129
+ import_annotated = (
130
+ IMPORT_ANNOTATED
131
+ if self.data_type.python_version.has_annotated_type
132
+ else IMPORT_ANNOTATED_BACKPORT
133
+ )
134
+ imports.append((import_annotated,))
129
135
  return chain_as_tuple(*imports)
130
136
 
131
137
  @property
@@ -12,6 +12,13 @@ from datamodel_code_generator.reference import Reference
12
12
  from datamodel_code_generator.types import chain_as_tuple
13
13
 
14
14
 
15
+ def _has_field_assignment(field: DataModelFieldBase) -> bool:
16
+ return bool(field.field) or not (
17
+ field.required
18
+ or (field.represented_default == 'None' and field.strip_default_none)
19
+ )
20
+
21
+
15
22
  class DataClass(DataModel):
16
23
  TEMPLATE_FILE_PATH: ClassVar[str] = 'dataclass.jinja2'
17
24
  DEFAULT_IMPORTS: ClassVar[Tuple[Import, ...]] = (IMPORT_DATACLASS,)
@@ -34,7 +41,7 @@ class DataClass(DataModel):
34
41
  ) -> None:
35
42
  super().__init__(
36
43
  reference=reference,
37
- fields=fields,
44
+ fields=sorted(fields, key=_has_field_assignment, reverse=False),
38
45
  decorators=decorators,
39
46
  base_classes=base_classes,
40
47
  custom_base_class=custom_base_class,
@@ -46,7 +53,6 @@ class DataClass(DataModel):
46
53
  default=default,
47
54
  nullable=nullable,
48
55
  )
49
- self.fields.sort(key=str, reverse=False)
50
56
 
51
57
  @property
52
58
  def imports(self) -> Tuple[Import, ...]:
@@ -0,0 +1,8 @@
1
+ from datamodel_code_generator.imports import Import
2
+
3
+ IMPORT_DATACLASS = Import.from_full_path('dataclasses.dataclass')
4
+ IMPORT_FIELD = Import.from_full_path('dataclasses.field')
5
+ IMPORT_TYPED_DICT = Import.from_full_path('typing.TypedDict')
6
+ IMPORT_TYPED_DICT_BACKPORT = Import.from_full_path('typing_extensions.TypedDict')
7
+ IMPORT_NOT_REQUIRED = Import.from_full_path('typing.NotRequired')
8
+ IMPORT_NOT_REQUIRED_BACKPORT = Import.from_full_path('typing_extensions.NotRequired')
@@ -93,7 +93,7 @@ def type_map_factory(
93
93
  Types.ipv6_network: data_type.from_import(IMPORT_IPV6NETWORKS),
94
94
  Types.boolean: data_type(type='bool'),
95
95
  Types.object: data_type.from_import(IMPORT_ANY, is_dict=True),
96
- Types.null: data_type.from_import(IMPORT_ANY, is_optional=True),
96
+ Types.null: data_type(type='None'),
97
97
  Types.array: data_type.from_import(IMPORT_ANY, is_list=True),
98
98
  Types.any: data_type.from_import(IMPORT_ANY),
99
99
  }
@@ -0,0 +1,5 @@
1
+ {%- if is_functional_syntax %}
2
+ {% include 'TypedDictFunction.jinja2' %}
3
+ {%- else %}
4
+ {% include 'TypedDictClass.jinja2' %}
5
+ {%- endif %}
@@ -0,0 +1,17 @@
1
+ class {{ class_name }}({{ base_class }}):
2
+ {%- if description %}
3
+ """
4
+ {{ description | indent(4) }}
5
+ """
6
+ {%- endif %}
7
+ {%- if not fields and not description %}
8
+ pass
9
+ {%- endif %}
10
+ {%- for field in fields %}
11
+ {{ field.name }}: {{ field.type_hint }}
12
+ {%- if field.docstring %}
13
+ """
14
+ {{ field.docstring | indent(4) }}
15
+ """
16
+ {%- endif %}
17
+ {%- endfor -%}
@@ -0,0 +1,16 @@
1
+ {%- if description %}
2
+ """
3
+ {{ description | indent(4) }}
4
+ """
5
+ {%- endif %}
6
+ {{ class_name }} = TypedDict('{{ class_name }}', {
7
+ {%- for field in all_fields %}
8
+ '{{ field.key }}': {{ field.type_hint }},
9
+ {%- if field.docstring %}
10
+ """
11
+ {{ field.docstring | indent(4) }}
12
+ """
13
+ {%- endif %}
14
+ {%- endfor -%}
15
+ })
16
+