Skip to content

Commit 637a1bd

Browse files
committed
Support ClassVar for Pydantic v2
1 parent da32bb7 commit 637a1bd

5 files changed

Lines changed: 49 additions & 1 deletion

File tree

src/datamodel_code_generator/model/pydantic_v2/base_model.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
IMPORT_VALIDATION_INFO,
3232
IMPORT_VALIDATOR_FUNCTION_WRAP_HANDLER,
3333
)
34+
from datamodel_code_generator.model.imports import IMPORT_CLASSVAR
3435
from datamodel_code_generator.reference import ModelResolver
3536
from datamodel_code_generator.types import chain_as_tuple
3637
from datamodel_code_generator.util import field_validator, model_validate, model_validator
@@ -187,11 +188,21 @@ def _has_discriminator_in_data_type(self) -> bool:
187188
"""Check if any nested DataType has a discriminator."""
188189
return any(dt.discriminator for dt in self.data_type.all_data_types)
189190

191+
@property
192+
def class_var_type_hint(self) -> str:
193+
return f"ClassVar[{self.type_hint}]"
194+
195+
@property
196+
def is_class_var(self) -> bool:
197+
return self.extras.get("x-is_classvar") is True
198+
190199
@property
191200
def imports(self) -> tuple[Import, ...]:
192201
"""Get all required imports including AliasChoices and Field for discriminator."""
193202
base_imports = super().imports
194203
extra_imports: list[Import] = []
204+
if self.is_class_var:
205+
extra_imports.append(IMPORT_CLASSVAR)
195206
if self.validation_aliases:
196207
from datamodel_code_generator.model.pydantic_v2.imports import IMPORT_ALIAS_CHOICES # noqa: PLC0415
197208

src/datamodel_code_generator/model/template/pydantic_v2/BaseModel.jinja2

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@ class {{ class_name }}({{ base_class }}):{% if comment is defined %} # {{ comme
1919
{{ line }}
2020
{%- endfor %}
2121
{%- for field in fields %}
22-
{%- if not field.annotated and field.field %}
22+
{%- if field.is_class_var and field.represented_default %}
23+
{{ field.name }}: {{ field.class_var_type_hint }} = {{ field.represented_default }}
24+
{%- elif not field.annotated and field.field %}
2325
{{ field.name }}: {{ field.type_hint }} = {{ field.field }}
2426
{%- else %}
2527
{%- if field.annotated %}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# generated by datamodel-codegen:
2+
# filename: has_classvar_extra.json
3+
# timestamp: 2019-07-26T00:00:00+00:00
4+
5+
from __future__ import annotations
6+
7+
from typing import ClassVar
8+
9+
from pydantic import BaseModel, Field
10+
11+
12+
class Model(BaseModel):
13+
namespace: ClassVar[str | None] = 'test'
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"type": "object",
3+
"properties": {
4+
"namespace": {
5+
"type": "string",
6+
"x-is_classvar": true,
7+
"default": "test"
8+
}
9+
}
10+
}

tests/main/jsonschema/test_main_jsonschema.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8001,6 +8001,18 @@ def test_validators_requires_pydantic_v2(output_file: Path, tmp_path: Path, caps
80018001
)
80028002

80038003

8004+
def test_jsonschema_classvar_extra_pydantic_v2(output_file: Path) -> None:
8005+
"""Test default value handling."""
8006+
run_main_and_assert(
8007+
input_path=JSON_SCHEMA_DATA_PATH / "has_classvar_extra.json",
8008+
output_path=output_file,
8009+
input_file_type="jsonschema",
8010+
assert_func=assert_file_content,
8011+
expected_file="has_classvar_extra.py",
8012+
extra_args=["--output-model-type", "pydantic_v2.BaseModel", "--field-include-all-keys"],
8013+
)
8014+
8015+
80048016
@PYDANTIC_V2_SKIP
80058017
def test_unique_items_enum_set(output_file: Path) -> None:
80068018
"""Test set with enum items does not add __hash__ to enum (already hashable)."""

0 commit comments

Comments
 (0)