datamodel-code-generator
datamodel-code-generator copied to clipboard
"--field-constraints" produces extra "RootModel"s that don't get collapsed by "--collapse-root-models"
Describe the bug
Sometimes "--collapse-root-models" works without "--field-constraints" but fails when using it.
I found this when converting docker compose's spec to pydantic v2 model. I've condensed the problematic part as a schema.
To Reproduce
Example schema:
{
"properties": {
"service": {
"id": "#/definitions/service",
"type": "object",
"properties": {
"annotations": {
"$ref": "#/definitions/list_or_dict"
}
}
}
},
"additionalProperties": false,
"definitions": {
"list_or_dict": {
"oneOf": [
{
"type": "object",
"patternProperties": {
".+": {
"type": [
"string",
"number",
"boolean",
"null"
]
}
}
},
{
"type": "array",
"items": {
"type": "string"
}
}
]
}
}
}
Used commandline:
datamodel-codegen --input test.json --output-model-type pydantic_v2.BaseModel --field-constraints --collapse-root-models --output test.py
I get:
from __future__ import annotations
from typing import Dict, List, Optional, Union
from pydantic import BaseModel, ConfigDict, RootModel
class ListOrDict1(RootModel[List[str]]):
root: List[str]
class Service(BaseModel):
annotations: Optional[
Union[Dict[str, Optional[Union[str, float, bool]]], ListOrDict1]
] = None
class Model(BaseModel):
model_config = ConfigDict(
extra="forbid",
)
service: Optional[Service] = None
I expect RootModel be collapsed when using "--collapse-root-models".
When I use this command: (without --field-constraints, but with constr)
datamodel-codegen --input test.json --output-model-type pydantic_v2.BaseModel --collapse-root-models --output test.py
It produces the following result:
from __future__ import annotations
from typing import Dict, List, Optional, Union
from pydantic import BaseModel, ConfigDict, constr
class Service(BaseModel):
annotations: Optional[
Union[Dict[constr(pattern=r'.+'), Optional[Union[str, float, bool]]], List[str]]
] = None
class Model(BaseModel):
model_config = ConfigDict(
extra='forbid',
)
service: Optional[Service] = None
As you can see, there is no more RootModel. However this is not optimal because pyright doesn't like constr(...) being a type expression.
Version:
- OS: Debian 12
- Python version: 3.12.7
- datamodel-code-generator version: 0.26.2