datamodel-code-generator
datamodel-code-generator copied to clipboard
Cannot override the template `pydantic_v2/ConfigDict.jinja2`
Describe the bug
So, I was trying to override this ConfigDict.jinja2 template and I placed it at templates/pydantic_v2/ConfigDict.jinja2, but use_enum_values=True is not being added to the ConfigDict of the generated models
To Reproduce
Use this template at templates/pydantic_v2/ConfigDict.jinja2
model_config = ConfigDict(
{%- for field_name, value in config.dict(exclude_unset=True).items() %}
{{ field_name }}={{ value }},
{%- endfor %}
use_enum_values=True,
)
Used commandline:
datamodel-codegen --input test.json --output test.py --use-union-operator --field-constraints --input-file-type=jsonschema --use-standard-collections --use-double-quotes --use-schema-description --capitalise-enum-members --custom-template-dir templates --use-title-as-name --output-model-type=pydantic_v2.BaseModel --extra-template-data templates/data.json
Now, --extra-template-data templates/data.json actually does not help too because only a few fields are supported. This PR https://github.com/koxudaxi/datamodel-code-generator/pull/2134 I created should allow us to specify use_enum_values=True in a file like templates/data.json
{
"#all#": {
"config": {
"use_enum_values": true
}
}
}
I know that it's reading from the templates folder, which I specify, because I can override the Enum.jinja2, which I placed at templates/Enum.jinja2
Where is the bug
I think the problem is that BaseModel.jinja2 includes ConfigDict.jinja2 using just the name {% include 'ConfigDict.jinja2' %}, so it just includes the one in the same directory, not ours.
{% for decorator in decorators -%}
{{ decorator }}
{% endfor -%}
class {{ class_name }}({{ base_class }}):{% if comment is defined %} # {{ comment }}{% endif %}
{%- if description %}
"""
{{ description | indent(4) }}
"""
{%- endif %}
{%- if not fields and not description %}
pass
{%- endif %}
{%- if config %}
{%- filter indent(4) %}
{% include 'ConfigDict.jinja2' %}
{%- endfilter %}
{%- endif %}
{%- for field in fields -%}
{%- if not field.annotated and field.field %}
{{ field.name }}: {{ field.type_hint }} = {{ field.field }}
{%- else %}
{%- if field.annotated %}
{{ field.name }}: {{ field.annotated }}
{%- else %}
{{ field.name }}: {{ field.type_hint }}
{%- endif %}
{%- if not (field.required or (field.represented_default == 'None' and field.strip_default_none)) or field.data_type.is_optional
%} = {{ field.represented_default }}
{%- endif -%}
{%- endif %}
{%- if field.docstring %}
"""
{{ field.docstring | indent(4) }}
"""
{%- endif %}
{%- for method in methods -%}
{{ method }}
{%- endfor -%}
{%- endfor -%}
Possible solution
Right now, the solution would be to override BaseModel.jinja2 to define our ConfigDict class.
Still, I'd expect to be able to override also ConfigDict.jinja2.
Expected behavior
My template overrides the original one.
Version:
- OS: Mac OS Sonoma
- Python version: Python 3.11.9
- datamodel-code-generator version: 0.26.2
I just hit something similar. I was overriding BaseModel, and it tried to open ConfigDict.jinja2 in the same directory, not falling back to the one that ships with DCG. I'm going to guess this would require overloading the Jinja loader and doing some custom logic to first look in the override dir, then fall back to the default dir.