datamodel-code-generator icon indicating copy to clipboard operation
datamodel-code-generator copied to clipboard

output-model-type `pydantic_2.BaseModel` with `Field()` generates invalid pydantic v2 classes

Open luminoso opened this issue 1 year ago • 3 comments

Describe the bug

Generating "pydantic_v2.BaseModel with Field() generates an impossible solution for current pydantic v2 implementation.

To Reproduce

Example schema:

{
  "$schema": "http://json-schema.org/draft-07/schema",
  "properties": {
    "Settings": {
      "title": "having a title will force a Field()",
      "properties": {
        "name": {
          "type": "string"
        }
      },
      "required": ["name"],
      "type": "object"
    }
  },
  "required": ["Settings"],
  "type": "object"
}

Used commandline:

$ datamodel-codegen --input-file-type jsonschema --output-model-type "pydantic_v2.BaseModel" --input sample.json --output generated_classes.py

Expected behavior The generated class should work when running with pydantic v2.

Version:

  • OS: Fedora 38 - Linux-6.1.50-200.fc38.x86_64-x86_64-with-glibc2.37
  • Python version: 3.11.4 (main, Jun 7 2023, 00:00:00) [GCC 13.1.1 20230511 (Red Hat 13.1.1-2)]
  • datamodel-code-generator version: 0.21.4

Additional context The generate class is the following:

from __future__ import annotations

from pydantic import BaseModel, Field


class Settings(BaseModel):
    name: str


class Model(BaseModel):
    Settings: Settings = Field(
        ..., title='having a title will force field defined with Field()'
    )

Which is exactly the same as the one generated with --output-model-type "pydantic.BaseModel". However, due to pydantic v2 limitations, the generated class will lead to a pydantic v2 error: RecursionError: maximum recursion depth exceeded

The pydantic v1 and v2 behaviour duality has been reported at pydantic repository: https://github.com/pydantic/pydantic/issues/7327

To make datamodel-code-generator work with the current pydantic v2 implementation, as suggested by https://github.com/pydantic/pydantic/issues/7327#issuecomment-1706012608, generated classes must have a different name from the field names, like so:

from __future__ import annotations

from pydantic import BaseModel, Field


class Settings_(BaseModel):
    name: str


class Model(BaseModel):
    Settings: Settings_ = Field(
        ..., title='having a title will force field defined with Field()'
    )

In which, having a class name that doesn't collide with field name, makes the generated class to work with pydantic v2.

luminoso avatar Sep 05 '23 08:09 luminoso

Thank you for creating the issue. I didn't know the behavior. I will fix it.

I may change the field name instead of the Model name.

koxudaxi avatar Oct 04 '23 17:10 koxudaxi

🤔 Any updates ?

Ps7ch3 avatar Oct 23 '23 09:10 Ps7ch3

I had the same issue. I solved it by using the --use-annotated flag. However, I still it would be helpful if the root cause is addressed.

tcrapts-ictu avatar Jan 11 '24 12:01 tcrapts-ictu