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.
- datamodel_code_generator/__init__.py +654 -185
- datamodel_code_generator/__main__.py +872 -388
- datamodel_code_generator/arguments.py +798 -0
- datamodel_code_generator/cli_options.py +295 -0
- datamodel_code_generator/format.py +292 -54
- datamodel_code_generator/http.py +85 -10
- datamodel_code_generator/imports.py +152 -43
- datamodel_code_generator/model/__init__.py +138 -1
- datamodel_code_generator/model/base.py +531 -120
- datamodel_code_generator/model/dataclass.py +211 -0
- datamodel_code_generator/model/enum.py +133 -12
- datamodel_code_generator/model/imports.py +22 -0
- datamodel_code_generator/model/msgspec.py +462 -0
- datamodel_code_generator/model/pydantic/__init__.py +30 -25
- datamodel_code_generator/model/pydantic/base_model.py +304 -100
- datamodel_code_generator/model/pydantic/custom_root_type.py +11 -2
- datamodel_code_generator/model/pydantic/dataclass.py +15 -4
- datamodel_code_generator/model/pydantic/imports.py +40 -27
- datamodel_code_generator/model/pydantic/types.py +188 -96
- datamodel_code_generator/model/pydantic_v2/__init__.py +51 -0
- datamodel_code_generator/model/pydantic_v2/base_model.py +268 -0
- datamodel_code_generator/model/pydantic_v2/imports.py +15 -0
- datamodel_code_generator/model/pydantic_v2/root_model.py +35 -0
- datamodel_code_generator/model/pydantic_v2/types.py +143 -0
- datamodel_code_generator/model/scalar.py +124 -0
- datamodel_code_generator/model/template/Enum.jinja2 +15 -2
- datamodel_code_generator/model/template/ScalarTypeAliasAnnotation.jinja2 +6 -0
- datamodel_code_generator/model/template/ScalarTypeAliasType.jinja2 +6 -0
- datamodel_code_generator/model/template/ScalarTypeStatement.jinja2 +6 -0
- datamodel_code_generator/model/template/TypeAliasAnnotation.jinja2 +20 -0
- datamodel_code_generator/model/template/TypeAliasType.jinja2 +20 -0
- datamodel_code_generator/model/template/TypeStatement.jinja2 +20 -0
- datamodel_code_generator/model/template/TypedDict.jinja2 +5 -0
- datamodel_code_generator/model/template/TypedDictClass.jinja2 +25 -0
- datamodel_code_generator/model/template/TypedDictFunction.jinja2 +24 -0
- datamodel_code_generator/model/template/UnionTypeAliasAnnotation.jinja2 +10 -0
- datamodel_code_generator/model/template/UnionTypeAliasType.jinja2 +10 -0
- datamodel_code_generator/model/template/UnionTypeStatement.jinja2 +10 -0
- datamodel_code_generator/model/template/dataclass.jinja2 +50 -0
- datamodel_code_generator/model/template/msgspec.jinja2 +55 -0
- datamodel_code_generator/model/template/pydantic/BaseModel.jinja2 +17 -4
- datamodel_code_generator/model/template/pydantic/BaseModel_root.jinja2 +12 -4
- datamodel_code_generator/model/template/pydantic/Config.jinja2 +1 -1
- datamodel_code_generator/model/template/pydantic/dataclass.jinja2 +15 -2
- datamodel_code_generator/model/template/pydantic_v2/BaseModel.jinja2 +57 -0
- datamodel_code_generator/model/template/pydantic_v2/ConfigDict.jinja2 +5 -0
- datamodel_code_generator/model/template/pydantic_v2/RootModel.jinja2 +48 -0
- datamodel_code_generator/model/type_alias.py +70 -0
- datamodel_code_generator/model/typed_dict.py +161 -0
- datamodel_code_generator/model/types.py +106 -0
- datamodel_code_generator/model/union.py +105 -0
- datamodel_code_generator/parser/__init__.py +30 -12
- datamodel_code_generator/parser/_graph.py +67 -0
- datamodel_code_generator/parser/_scc.py +171 -0
- datamodel_code_generator/parser/base.py +2426 -380
- datamodel_code_generator/parser/graphql.py +652 -0
- datamodel_code_generator/parser/jsonschema.py +2518 -647
- datamodel_code_generator/parser/openapi.py +631 -222
- datamodel_code_generator/py.typed +0 -0
- datamodel_code_generator/pydantic_patch.py +28 -0
- datamodel_code_generator/reference.py +672 -290
- datamodel_code_generator/types.py +521 -145
- datamodel_code_generator/util.py +155 -0
- datamodel_code_generator/watch.py +65 -0
- datamodel_code_generator-0.45.0.dist-info/METADATA +301 -0
- datamodel_code_generator-0.45.0.dist-info/RECORD +69 -0
- {datamodel_code_generator-0.11.12.dist-info → datamodel_code_generator-0.45.0.dist-info}/WHEEL +1 -1
- datamodel_code_generator-0.45.0.dist-info/entry_points.txt +2 -0
- datamodel_code_generator/version.py +0 -1
- datamodel_code_generator-0.11.12.dist-info/METADATA +0 -440
- datamodel_code_generator-0.11.12.dist-info/RECORD +0 -31
- datamodel_code_generator-0.11.12.dist-info/entry_points.txt +0 -3
- {datamodel_code_generator-0.11.12.dist-info → datamodel_code_generator-0.45.0.dist-info/licenses}/LICENSE +0 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{%- macro get_type_annotation(_field) -%}
|
|
2
|
+
{%- if _field.annotated -%}
|
|
3
|
+
{{ _field.annotated }}
|
|
4
|
+
{%- elif _field.field -%}
|
|
5
|
+
Annotated[{{ _field.type_hint }}, {{ _field.field }}]
|
|
6
|
+
{%- else -%}
|
|
7
|
+
{{ _field.type_hint }}
|
|
8
|
+
{%- endif -%}
|
|
9
|
+
{%- endmacro -%}
|
|
10
|
+
|
|
11
|
+
type {{ class_name }} = {{ get_type_annotation(fields[0]) }}{% if comment is defined %} # {{ comment }}{% endif %}
|
|
12
|
+
{%- if description %}
|
|
13
|
+
"""
|
|
14
|
+
{{ description | indent(0) }}
|
|
15
|
+
"""
|
|
16
|
+
{%- elif fields and fields[0].docstring %}
|
|
17
|
+
"""
|
|
18
|
+
{{ fields[0].docstring | indent(0) }}
|
|
19
|
+
"""
|
|
20
|
+
{%- endif %}
|
|
@@ -0,0 +1,25 @@
|
|
|
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
|
+
{%- if field.use_inline_field_description and not loop.last %}
|
|
17
|
+
|
|
18
|
+
{% endif %}
|
|
19
|
+
{%- elif field.inline_field_docstring %}
|
|
20
|
+
{{ field.inline_field_docstring }}
|
|
21
|
+
{%- if not loop.last %}
|
|
22
|
+
|
|
23
|
+
{% endif %}
|
|
24
|
+
{%- endif %}
|
|
25
|
+
{%- endfor -%}
|
|
@@ -0,0 +1,24 @@
|
|
|
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
|
+
{%- if field.use_inline_field_description and not loop.last %}
|
|
14
|
+
|
|
15
|
+
{% endif %}
|
|
16
|
+
{%- elif field.inline_field_docstring %}
|
|
17
|
+
{{ field.inline_field_docstring }}
|
|
18
|
+
{%- if not loop.last %}
|
|
19
|
+
|
|
20
|
+
{% endif %}
|
|
21
|
+
{%- endif %}
|
|
22
|
+
{%- endfor -%}
|
|
23
|
+
})
|
|
24
|
+
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{%- if description %}
|
|
2
|
+
# {{ description | replace('\n', '\n# ') }}
|
|
3
|
+
{%- endif %}
|
|
4
|
+
{%- if fields|length > 1 %}
|
|
5
|
+
{{ class_name }}: TypeAlias = Union[
|
|
6
|
+
{%- for field in fields %}
|
|
7
|
+
'{{ field.name }}',
|
|
8
|
+
{%- endfor %}
|
|
9
|
+
]{% else %}
|
|
10
|
+
{{ class_name }}: TypeAlias = {{ fields[0].name }}{% endif %}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{%- if description %}
|
|
2
|
+
# {{ description | replace('\n', '\n# ') }}
|
|
3
|
+
{%- endif %}
|
|
4
|
+
{%- if fields|length > 1 %}
|
|
5
|
+
{{ class_name }} = TypeAliasType("{{ class_name }}", Union[
|
|
6
|
+
{%- for field in fields %}
|
|
7
|
+
'{{ field.name }}',
|
|
8
|
+
{%- endfor %}
|
|
9
|
+
]){% else %}
|
|
10
|
+
{{ class_name }} = TypeAliasType("{{ class_name }}", {{ fields[0].name }}){% endif %}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{%- if description %}
|
|
2
|
+
# {{ description | replace('\n', '\n# ') }}
|
|
3
|
+
{%- endif %}
|
|
4
|
+
{%- if fields|length > 1 %}
|
|
5
|
+
type {{ class_name }} = Union[
|
|
6
|
+
{%- for field in fields %}
|
|
7
|
+
'{{ field.name }}',
|
|
8
|
+
{%- endfor %}
|
|
9
|
+
]{% else %}
|
|
10
|
+
type {{ class_name }} = {{ fields[0].name }}{% endif %}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{% for decorator in decorators -%}
|
|
2
|
+
{{ decorator }}
|
|
3
|
+
{% endfor -%}
|
|
4
|
+
{%- set args = [] %}
|
|
5
|
+
{%- for k, v in (dataclass_arguments or {}).items() %}
|
|
6
|
+
{%- if v is not none and v is not false %}
|
|
7
|
+
{%- set _ = args.append(k ~ '=' ~ (v|pprint)) %}
|
|
8
|
+
{%- endif %}
|
|
9
|
+
{%- endfor %}
|
|
10
|
+
{%- if args %}
|
|
11
|
+
@dataclass({{ args | join(', ') }})
|
|
12
|
+
{%- else %}
|
|
13
|
+
@dataclass
|
|
14
|
+
{%- endif %}
|
|
15
|
+
{%- if base_class %}
|
|
16
|
+
class {{ class_name }}({{ base_class }}):
|
|
17
|
+
{%- else %}
|
|
18
|
+
class {{ class_name }}:
|
|
19
|
+
{%- endif %}
|
|
20
|
+
{%- if description %}
|
|
21
|
+
"""
|
|
22
|
+
{{ description | indent(4) }}
|
|
23
|
+
"""
|
|
24
|
+
{%- endif %}
|
|
25
|
+
{%- if not fields and not description %}
|
|
26
|
+
pass
|
|
27
|
+
{%- endif %}
|
|
28
|
+
{%- for field in fields -%}
|
|
29
|
+
{%- if field.field %}
|
|
30
|
+
{{ field.name }}: {{ field.type_hint }} = {{ field.field }}
|
|
31
|
+
{%- else %}
|
|
32
|
+
{{ field.name }}: {{ field.type_hint }}
|
|
33
|
+
{%- if not (field.required or (field.represented_default == 'None' and field.strip_default_none))
|
|
34
|
+
%} = {{ field.represented_default }}
|
|
35
|
+
{%- endif -%}
|
|
36
|
+
{%- endif %}
|
|
37
|
+
{%- if field.docstring %}
|
|
38
|
+
"""
|
|
39
|
+
{{ field.docstring | indent(4) }}
|
|
40
|
+
"""
|
|
41
|
+
{%- if field.use_inline_field_description and not loop.last %}
|
|
42
|
+
|
|
43
|
+
{% endif %}
|
|
44
|
+
{%- elif field.inline_field_docstring %}
|
|
45
|
+
{{ field.inline_field_docstring }}
|
|
46
|
+
{%- if not loop.last %}
|
|
47
|
+
|
|
48
|
+
{% endif %}
|
|
49
|
+
{%- endif %}
|
|
50
|
+
{%- endfor -%}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
{% for decorator in decorators -%}
|
|
2
|
+
{{ decorator }}
|
|
3
|
+
{% endfor -%}
|
|
4
|
+
{%- if base_class %}
|
|
5
|
+
class {{ class_name }}({{ base_class }}{%- for key, value in (base_class_kwargs|default({})).items() -%}
|
|
6
|
+
, {{ key }}={{ value }}
|
|
7
|
+
{%- endfor -%}):
|
|
8
|
+
{%- else %}
|
|
9
|
+
class {{ class_name }}:
|
|
10
|
+
{%- endif %}
|
|
11
|
+
{%- if description %}
|
|
12
|
+
"""
|
|
13
|
+
{{ description | indent(4) }}
|
|
14
|
+
"""
|
|
15
|
+
{%- endif %}
|
|
16
|
+
{%- set ns = namespace(has_rendered_field=false) -%}
|
|
17
|
+
{%- for field in fields -%}
|
|
18
|
+
{%- if field.extras.get('is_classvar') %}
|
|
19
|
+
{#- Skip fields with is_classvar=True - they are managed by msgspec tag_field -#}
|
|
20
|
+
{%- elif not field.annotated and field.field %}
|
|
21
|
+
{%- set ns.has_rendered_field = true %}
|
|
22
|
+
{{ field.name }}: {{ field.type_hint }} = {{ field.field }}
|
|
23
|
+
{%- else %}
|
|
24
|
+
{%- set ns.has_rendered_field = true %}
|
|
25
|
+
{%- if field.annotated and not field.field %}
|
|
26
|
+
{{ field.name }}: {{ field.annotated }}
|
|
27
|
+
{%- elif field.annotated and field.field %}
|
|
28
|
+
{{ field.name }}: {{ field.annotated }} = {{ field.field }}
|
|
29
|
+
{%- else %}
|
|
30
|
+
{{ field.name }}: {{ field.type_hint }}
|
|
31
|
+
{%- endif %}
|
|
32
|
+
{%- if not field.field and (not field.required or field.data_type.is_optional or field.nullable)
|
|
33
|
+
%} = {{ field.represented_default }}
|
|
34
|
+
{%- endif -%}
|
|
35
|
+
{%- endif %}
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
{%- if not field.extras.get('is_classvar') and field.docstring %}
|
|
40
|
+
"""
|
|
41
|
+
{{ field.docstring | indent(4) }}
|
|
42
|
+
"""
|
|
43
|
+
{%- if field.use_inline_field_description and not loop.last %}
|
|
44
|
+
|
|
45
|
+
{% endif %}
|
|
46
|
+
{%- elif not field.extras.get('is_classvar') and field.inline_field_docstring %}
|
|
47
|
+
{{ field.inline_field_docstring }}
|
|
48
|
+
{%- if not loop.last %}
|
|
49
|
+
|
|
50
|
+
{% endif %}
|
|
51
|
+
{%- endif %}
|
|
52
|
+
{%- endfor -%}
|
|
53
|
+
{%- if not ns.has_rendered_field and not description %}
|
|
54
|
+
pass
|
|
55
|
+
{%- endif -%}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{% for decorator in decorators -%}
|
|
2
2
|
{{ decorator }}
|
|
3
3
|
{% endfor -%}
|
|
4
|
-
class {{ class_name }}({{ base_class }}):
|
|
4
|
+
class {{ class_name }}({{ base_class }}):{% if comment is defined %} # {{ comment }}{% endif %}
|
|
5
5
|
{%- if description %}
|
|
6
6
|
"""
|
|
7
|
-
{{ description }}
|
|
7
|
+
{{ description | indent(4) }}
|
|
8
8
|
"""
|
|
9
9
|
{%- endif %}
|
|
10
|
-
{%- if not fields %}
|
|
10
|
+
{%- if not fields and not description %}
|
|
11
11
|
pass
|
|
12
12
|
{%- endif %}
|
|
13
13
|
{%- if config %}
|
|
@@ -24,10 +24,23 @@ class {{ class_name }}({{ base_class }}):
|
|
|
24
24
|
{%- else %}
|
|
25
25
|
{{ field.name }}: {{ field.type_hint }}
|
|
26
26
|
{%- endif %}
|
|
27
|
-
{%- if not (field.required or (field.represented_default == 'None' and field.strip_default_none))
|
|
27
|
+
{%- if not field.has_default_factory_in_field and not (field.required or (field.represented_default == 'None' and field.strip_default_none))
|
|
28
28
|
%} = {{ field.represented_default }}
|
|
29
29
|
{%- endif -%}
|
|
30
30
|
{%- endif %}
|
|
31
|
+
{%- if field.docstring %}
|
|
32
|
+
"""
|
|
33
|
+
{{ field.docstring | indent(4) }}
|
|
34
|
+
"""
|
|
35
|
+
{%- if field.use_inline_field_description and not loop.last %}
|
|
36
|
+
|
|
37
|
+
{% endif %}
|
|
38
|
+
{%- elif field.inline_field_docstring %}
|
|
39
|
+
{{ field.inline_field_docstring }}
|
|
40
|
+
{%- if not loop.last %}
|
|
41
|
+
|
|
42
|
+
{% endif %}
|
|
43
|
+
{%- endif %}
|
|
31
44
|
{%- for method in methods -%}
|
|
32
45
|
{{ method }}
|
|
33
46
|
{%- endfor -%}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{% for decorator in decorators -%}
|
|
2
2
|
{{ decorator }}
|
|
3
3
|
{% endfor -%}
|
|
4
|
-
class {{ class_name }}({{ base_class }}):
|
|
4
|
+
class {{ class_name }}({{ base_class }}):{% if comment is defined %} # {{ comment }}{% endif %}
|
|
5
5
|
{%- if description %}
|
|
6
6
|
"""
|
|
7
|
-
{{ description }}
|
|
7
|
+
{{ description | indent(4) }}
|
|
8
8
|
"""
|
|
9
9
|
{%- endif %}
|
|
10
10
|
{%- if config %}
|
|
@@ -12,7 +12,7 @@ class {{ class_name }}({{ base_class }}):
|
|
|
12
12
|
{% include 'Config.jinja2' %}
|
|
13
13
|
{%- endfilter %}
|
|
14
14
|
{%- endif %}
|
|
15
|
-
{%- if not fields %}
|
|
15
|
+
{%- if not fields and not description %}
|
|
16
16
|
pass
|
|
17
17
|
{%- else %}
|
|
18
18
|
{%- set field = fields[0] %}
|
|
@@ -24,8 +24,16 @@ class {{ class_name }}({{ base_class }}):
|
|
|
24
24
|
{%- else %}
|
|
25
25
|
__root__: {{ field.type_hint }}
|
|
26
26
|
{%- endif %}
|
|
27
|
-
{%- if not (field.required or (field.represented_default == 'None' and field.strip_default_none))
|
|
27
|
+
{%- if not field.has_default_factory_in_field and not (field.required or (field.represented_default == 'None' and field.strip_default_none))
|
|
28
28
|
%} = {{ field.represented_default }}
|
|
29
29
|
{%- endif -%}
|
|
30
30
|
{%- endif %}
|
|
31
|
+
{%- if field.docstring %}
|
|
32
|
+
"""
|
|
33
|
+
{{ field.docstring | indent(4) }}
|
|
34
|
+
"""
|
|
35
|
+
{%- elif field.inline_field_docstring %}
|
|
36
|
+
{{ field.inline_field_docstring }}
|
|
37
|
+
|
|
38
|
+
{%- endif %}
|
|
31
39
|
{%- endif %}
|
|
@@ -9,7 +9,7 @@ class {{ class_name }}:
|
|
|
9
9
|
{%- endif %}
|
|
10
10
|
{%- if description %}
|
|
11
11
|
"""
|
|
12
|
-
{{ description }}
|
|
12
|
+
{{ description | indent(4) }}
|
|
13
13
|
"""
|
|
14
14
|
{%- endif %}
|
|
15
15
|
{%- if not fields %}
|
|
@@ -21,4 +21,17 @@ class {{ class_name }}:
|
|
|
21
21
|
{%- else %}
|
|
22
22
|
{{ field.name }}: {{ field.type_hint }}
|
|
23
23
|
{%- endif %}
|
|
24
|
-
{%-
|
|
24
|
+
{%- if field.docstring %}
|
|
25
|
+
"""
|
|
26
|
+
{{ field.docstring | indent(4) }}
|
|
27
|
+
"""
|
|
28
|
+
{%- if field.use_inline_field_description and not loop.last %}
|
|
29
|
+
|
|
30
|
+
{% endif %}
|
|
31
|
+
{%- elif field.inline_field_docstring %}
|
|
32
|
+
{{ field.inline_field_docstring }}
|
|
33
|
+
{%- if not loop.last %}
|
|
34
|
+
|
|
35
|
+
{% endif %}
|
|
36
|
+
{%- endif %}
|
|
37
|
+
{%- endfor -%}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
{% if base_class != "BaseModel" and "," not in base_class and not fields and not config and not description -%}
|
|
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
|
+
|
|
9
|
+
{% for decorator in decorators -%}
|
|
10
|
+
{{ decorator }}
|
|
11
|
+
{% endfor -%}
|
|
12
|
+
class {{ class_name }}({{ base_class }}):{% if comment is defined %} # {{ comment }}{% endif %}
|
|
13
|
+
{%- if description %}
|
|
14
|
+
"""
|
|
15
|
+
{{ description | indent(4) }}
|
|
16
|
+
"""
|
|
17
|
+
{%- endif %}
|
|
18
|
+
{%- if not fields and not description %}
|
|
19
|
+
pass
|
|
20
|
+
{%- endif %}
|
|
21
|
+
{%- if config %}
|
|
22
|
+
{%- filter indent(4) %}
|
|
23
|
+
{% include 'ConfigDict.jinja2' %}
|
|
24
|
+
{%- endfilter %}
|
|
25
|
+
{%- endif %}
|
|
26
|
+
{%- for field in fields %}
|
|
27
|
+
{%- if not field.annotated and field.field %}
|
|
28
|
+
{{ field.name }}: {{ field.type_hint }} = {{ field.field }}
|
|
29
|
+
{%- else %}
|
|
30
|
+
{%- if field.annotated %}
|
|
31
|
+
{{ field.name }}: {{ field.annotated }}
|
|
32
|
+
{%- else %}
|
|
33
|
+
{{ field.name }}: {{ field.type_hint }}
|
|
34
|
+
{%- endif %}
|
|
35
|
+
{%- if not field.has_default_factory_in_field and (not (field.required or (field.represented_default == 'None' and field.strip_default_none)) or field.data_type.is_optional)
|
|
36
|
+
%} = {{ field.represented_default }}
|
|
37
|
+
{%- endif -%}
|
|
38
|
+
{%- endif %}
|
|
39
|
+
{%- if field.docstring %}
|
|
40
|
+
"""
|
|
41
|
+
{{ field.docstring | indent(4) }}
|
|
42
|
+
"""
|
|
43
|
+
{%- if field.use_inline_field_description and not loop.last %}
|
|
44
|
+
|
|
45
|
+
{% endif %}
|
|
46
|
+
{%- elif field.inline_field_docstring %}
|
|
47
|
+
{{ field.inline_field_docstring }}
|
|
48
|
+
{%- if not loop.last %}
|
|
49
|
+
|
|
50
|
+
{% endif %}
|
|
51
|
+
{%- endif %}
|
|
52
|
+
{%- for method in methods -%}
|
|
53
|
+
{{ method }}
|
|
54
|
+
{%- endfor -%}
|
|
55
|
+
{%- endfor -%}
|
|
56
|
+
|
|
57
|
+
{%- endif %}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{%- macro get_type_hint(_fields) -%}
|
|
2
|
+
{%- if _fields -%}
|
|
3
|
+
{#There will only ever be a single field for RootModel#}
|
|
4
|
+
{{- _fields[0].type_hint}}
|
|
5
|
+
{%- endif -%}
|
|
6
|
+
{%- endmacro -%}
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
{% for decorator in decorators -%}
|
|
10
|
+
{{ decorator }}
|
|
11
|
+
{% endfor -%}
|
|
12
|
+
|
|
13
|
+
class {{ class_name }}({{ base_class }}{%- if fields -%}[{{get_type_hint(fields)}}]{%- endif -%}):{% if comment is defined %} # {{ comment }}{% endif %}
|
|
14
|
+
{%- if description %}
|
|
15
|
+
"""
|
|
16
|
+
{{ description | indent(4) }}
|
|
17
|
+
"""
|
|
18
|
+
{%- endif %}
|
|
19
|
+
{%- if config %}
|
|
20
|
+
{%- filter indent(4) %}
|
|
21
|
+
{% include 'ConfigDict.jinja2' %}
|
|
22
|
+
{%- endfilter %}
|
|
23
|
+
{%- endif %}
|
|
24
|
+
{%- if not fields and not description %}
|
|
25
|
+
pass
|
|
26
|
+
{%- else %}
|
|
27
|
+
{%- set field = fields[0] %}
|
|
28
|
+
{%- if not field.annotated and field.field %}
|
|
29
|
+
root: {{ field.type_hint }} = {{ field.field }}
|
|
30
|
+
{%- else %}
|
|
31
|
+
{%- if field.annotated %}
|
|
32
|
+
root: {{ field.annotated }}
|
|
33
|
+
{%- else %}
|
|
34
|
+
root: {{ field.type_hint }}
|
|
35
|
+
{%- endif %}
|
|
36
|
+
{%- if not field.has_default_factory_in_field and not (field.required or (field.represented_default == 'None' and field.strip_default_none))
|
|
37
|
+
%} = {{ field.represented_default }}
|
|
38
|
+
{%- endif -%}
|
|
39
|
+
{%- endif %}
|
|
40
|
+
{%- if field.docstring %}
|
|
41
|
+
"""
|
|
42
|
+
{{ field.docstring | indent(4) }}
|
|
43
|
+
"""
|
|
44
|
+
{%- elif field.inline_field_docstring %}
|
|
45
|
+
{{ field.inline_field_docstring }}
|
|
46
|
+
|
|
47
|
+
{%- endif %}
|
|
48
|
+
{%- endif %}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"""Type alias model generators.
|
|
2
|
+
|
|
3
|
+
Provides classes for generating type aliases using different Python syntax:
|
|
4
|
+
TypeAlias annotation, TypeAliasType, and type statement (Python 3.12+).
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from typing import ClassVar
|
|
10
|
+
|
|
11
|
+
from datamodel_code_generator.imports import (
|
|
12
|
+
IMPORT_ANNOTATED,
|
|
13
|
+
IMPORT_TYPE_ALIAS,
|
|
14
|
+
IMPORT_TYPE_ALIAS_BACKPORT,
|
|
15
|
+
IMPORT_TYPE_ALIAS_TYPE,
|
|
16
|
+
Import,
|
|
17
|
+
)
|
|
18
|
+
from datamodel_code_generator.model import DataModel
|
|
19
|
+
from datamodel_code_generator.types import chain_as_tuple
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class TypeAliasBase(DataModel):
|
|
23
|
+
"""Base class for all type alias implementations."""
|
|
24
|
+
|
|
25
|
+
IS_ALIAS: bool = True
|
|
26
|
+
|
|
27
|
+
@property
|
|
28
|
+
def imports(self) -> tuple[Import, ...]:
|
|
29
|
+
"""Get imports including Annotated if needed."""
|
|
30
|
+
imports = super().imports
|
|
31
|
+
if self.fields and (self.fields[0].annotated or self.fields[0].field):
|
|
32
|
+
imports = chain_as_tuple(imports, (IMPORT_ANNOTATED,))
|
|
33
|
+
|
|
34
|
+
return imports
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class TypeAlias(TypeAliasBase):
|
|
38
|
+
"""TypeAlias annotation for Python 3.10+ (Name: TypeAlias = type)."""
|
|
39
|
+
|
|
40
|
+
TEMPLATE_FILE_PATH: ClassVar[str] = "TypeAliasAnnotation.jinja2"
|
|
41
|
+
BASE_CLASS: ClassVar[str] = ""
|
|
42
|
+
DEFAULT_IMPORTS: ClassVar[tuple[Import, ...]] = (IMPORT_TYPE_ALIAS,)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class TypeAliasBackport(TypeAliasBase):
|
|
46
|
+
"""TypeAlias annotation for Python 3.9 (Name: TypeAlias = type) using typing_extensions."""
|
|
47
|
+
|
|
48
|
+
TEMPLATE_FILE_PATH: ClassVar[str] = "TypeAliasAnnotation.jinja2"
|
|
49
|
+
BASE_CLASS: ClassVar[str] = ""
|
|
50
|
+
DEFAULT_IMPORTS: ClassVar[tuple[Import, ...]] = (IMPORT_TYPE_ALIAS_BACKPORT,)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class TypeAliasTypeBackport(TypeAliasBase):
|
|
54
|
+
"""TypeAliasType for Python 3.9-3.11 (Name = TypeAliasType("Name", type))."""
|
|
55
|
+
|
|
56
|
+
TEMPLATE_FILE_PATH: ClassVar[str] = "TypeAliasType.jinja2"
|
|
57
|
+
BASE_CLASS: ClassVar[str] = ""
|
|
58
|
+
DEFAULT_IMPORTS: ClassVar[tuple[Import, ...]] = (IMPORT_TYPE_ALIAS_TYPE,)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
class TypeStatement(TypeAliasBase):
|
|
62
|
+
"""Type statement for Python 3.12+ (type Name = type).
|
|
63
|
+
|
|
64
|
+
Note: Python 3.12+ type statements use deferred evaluation,
|
|
65
|
+
so forward references don't need to be quoted.
|
|
66
|
+
"""
|
|
67
|
+
|
|
68
|
+
TEMPLATE_FILE_PATH: ClassVar[str] = "TypeStatement.jinja2"
|
|
69
|
+
BASE_CLASS: ClassVar[str] = ""
|
|
70
|
+
DEFAULT_IMPORTS: ClassVar[tuple[Import, ...]] = ()
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
"""TypedDict model generator.
|
|
2
|
+
|
|
3
|
+
Generates Python TypedDict classes for use with type checkers.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
import keyword
|
|
9
|
+
from typing import TYPE_CHECKING, Any, ClassVar
|
|
10
|
+
|
|
11
|
+
from datamodel_code_generator.model import DataModel, DataModelFieldBase
|
|
12
|
+
from datamodel_code_generator.model.base import UNDEFINED
|
|
13
|
+
from datamodel_code_generator.model.imports import (
|
|
14
|
+
IMPORT_NOT_REQUIRED,
|
|
15
|
+
IMPORT_NOT_REQUIRED_BACKPORT,
|
|
16
|
+
IMPORT_TYPED_DICT,
|
|
17
|
+
)
|
|
18
|
+
from datamodel_code_generator.types import NOT_REQUIRED_PREFIX
|
|
19
|
+
|
|
20
|
+
if TYPE_CHECKING:
|
|
21
|
+
from collections import defaultdict
|
|
22
|
+
from collections.abc import Iterator
|
|
23
|
+
from pathlib import Path
|
|
24
|
+
|
|
25
|
+
from datamodel_code_generator.imports import Import
|
|
26
|
+
from datamodel_code_generator.reference import Reference
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
escape_characters = str.maketrans({
|
|
30
|
+
"\\": r"\\",
|
|
31
|
+
"'": r"\'",
|
|
32
|
+
"\b": r"\b",
|
|
33
|
+
"\f": r"\f",
|
|
34
|
+
"\n": r"\n",
|
|
35
|
+
"\r": r"\r",
|
|
36
|
+
"\t": r"\t",
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def _is_valid_field_name(field: DataModelFieldBase) -> bool:
|
|
41
|
+
name = field.original_name or field.name
|
|
42
|
+
if name is None: # pragma: no cover
|
|
43
|
+
return False
|
|
44
|
+
return name.isidentifier() and not keyword.iskeyword(name)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class TypedDict(DataModel):
|
|
48
|
+
"""DataModel implementation for Python TypedDict."""
|
|
49
|
+
|
|
50
|
+
TEMPLATE_FILE_PATH: ClassVar[str] = "TypedDict.jinja2"
|
|
51
|
+
BASE_CLASS: ClassVar[str] = "typing.TypedDict"
|
|
52
|
+
DEFAULT_IMPORTS: ClassVar[tuple[Import, ...]] = (IMPORT_TYPED_DICT,)
|
|
53
|
+
|
|
54
|
+
def __init__( # noqa: PLR0913
|
|
55
|
+
self,
|
|
56
|
+
*,
|
|
57
|
+
reference: Reference,
|
|
58
|
+
fields: list[DataModelFieldBase],
|
|
59
|
+
decorators: list[str] | None = None,
|
|
60
|
+
base_classes: list[Reference] | None = None,
|
|
61
|
+
custom_base_class: str | None = None,
|
|
62
|
+
custom_template_dir: Path | None = None,
|
|
63
|
+
extra_template_data: defaultdict[str, dict[str, Any]] | None = None,
|
|
64
|
+
methods: list[str] | None = None,
|
|
65
|
+
path: Path | None = None,
|
|
66
|
+
description: str | None = None,
|
|
67
|
+
default: Any = UNDEFINED,
|
|
68
|
+
nullable: bool = False,
|
|
69
|
+
keyword_only: bool = False,
|
|
70
|
+
treat_dot_as_module: bool = False,
|
|
71
|
+
) -> None:
|
|
72
|
+
"""Initialize TypedDict model."""
|
|
73
|
+
super().__init__(
|
|
74
|
+
reference=reference,
|
|
75
|
+
fields=fields,
|
|
76
|
+
decorators=decorators,
|
|
77
|
+
base_classes=base_classes,
|
|
78
|
+
custom_base_class=custom_base_class,
|
|
79
|
+
custom_template_dir=custom_template_dir,
|
|
80
|
+
extra_template_data=extra_template_data,
|
|
81
|
+
methods=methods,
|
|
82
|
+
path=path,
|
|
83
|
+
description=description,
|
|
84
|
+
default=default,
|
|
85
|
+
nullable=nullable,
|
|
86
|
+
keyword_only=keyword_only,
|
|
87
|
+
treat_dot_as_module=treat_dot_as_module,
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
@property
|
|
91
|
+
def is_functional_syntax(self) -> bool:
|
|
92
|
+
"""Check if TypedDict requires functional syntax."""
|
|
93
|
+
return any(not _is_valid_field_name(f) for f in self.fields)
|
|
94
|
+
|
|
95
|
+
@property
|
|
96
|
+
def all_fields(self) -> Iterator[DataModelFieldBase]:
|
|
97
|
+
"""Iterate over all fields including inherited ones."""
|
|
98
|
+
yield from self.iter_all_fields()
|
|
99
|
+
|
|
100
|
+
def render(self, *, class_name: str | None = None) -> str:
|
|
101
|
+
"""Render TypedDict class with appropriate syntax."""
|
|
102
|
+
return self._render(
|
|
103
|
+
class_name=class_name or self.class_name,
|
|
104
|
+
fields=self.fields,
|
|
105
|
+
decorators=self.decorators,
|
|
106
|
+
base_class=self.base_class,
|
|
107
|
+
methods=self.methods,
|
|
108
|
+
description=self.description,
|
|
109
|
+
is_functional_syntax=self.is_functional_syntax,
|
|
110
|
+
all_fields=self.all_fields,
|
|
111
|
+
**self.extra_template_data,
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
class DataModelField(DataModelFieldBase):
|
|
116
|
+
"""Field implementation for TypedDict models."""
|
|
117
|
+
|
|
118
|
+
DEFAULT_IMPORTS: ClassVar[tuple[Import, ...]] = (IMPORT_NOT_REQUIRED,)
|
|
119
|
+
|
|
120
|
+
def process_const(self) -> None:
|
|
121
|
+
"""Process const field constraint using literal type."""
|
|
122
|
+
self._process_const_as_literal()
|
|
123
|
+
|
|
124
|
+
@property
|
|
125
|
+
def key(self) -> str:
|
|
126
|
+
"""Get escaped field key for TypedDict."""
|
|
127
|
+
return (self.original_name or self.name or "").translate( # pragma: no cover
|
|
128
|
+
escape_characters
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
@property
|
|
132
|
+
def type_hint(self) -> str:
|
|
133
|
+
"""Get type hint with NotRequired wrapper if needed."""
|
|
134
|
+
type_hint = super().type_hint
|
|
135
|
+
if self._not_required:
|
|
136
|
+
return f"{NOT_REQUIRED_PREFIX}{type_hint}]"
|
|
137
|
+
return type_hint
|
|
138
|
+
|
|
139
|
+
@property
|
|
140
|
+
def _not_required(self) -> bool:
|
|
141
|
+
"""Check if field should be marked as NotRequired."""
|
|
142
|
+
return not self.required and isinstance(self.parent, TypedDict)
|
|
143
|
+
|
|
144
|
+
@property
|
|
145
|
+
def fall_back_to_nullable(self) -> bool:
|
|
146
|
+
"""Check if field should fall back to nullable."""
|
|
147
|
+
return not self._not_required
|
|
148
|
+
|
|
149
|
+
@property
|
|
150
|
+
def imports(self) -> tuple[Import, ...]:
|
|
151
|
+
"""Get imports including NotRequired if needed."""
|
|
152
|
+
return (
|
|
153
|
+
*super().imports,
|
|
154
|
+
*(self.DEFAULT_IMPORTS if self._not_required else ()),
|
|
155
|
+
)
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
class DataModelFieldBackport(DataModelField):
|
|
159
|
+
"""Field implementation for TypedDict models using typing_extensions."""
|
|
160
|
+
|
|
161
|
+
DEFAULT_IMPORTS: ClassVar[tuple[Import, ...]] = (IMPORT_NOT_REQUIRED_BACKPORT,)
|