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

a required field with a default should not be generated as an `Optional[type] = default` (pydantic_v2)

Open gloshkajian opened this issue 1 year ago • 4 comments

Describe the bug I have a schema which I think is very clearly saying 'this field is required, and takes a default.' But datamodel-codegen generates a model which accepts None alongside the specified type and its default, which doesn't seem quite right.

To Reproduce

Example schema:

{
    "type": "object",
    "required": ["a", "b"],
    "additionalProperties": false,
    "properties": {
      "a": {
        "type": "string"
      },
      "b": {
        "type": "string",
        "default": "default"
      }
    }
}
  

Used commandline:

$ datamodel-codegen --input test.json --use-default --output-model-type pydantic_v2.BaseModel --output result.json
from __future__ import annotations

from typing import Optional

from pydantic import BaseModel, ConfigDict


class Model(BaseModel):
    model_config = ConfigDict(
        extra='forbid',
    )
    a: str
    b: Optional[str] = 'default'

Expected behavior

b shouldn't be an Optional[str]! Per https://docs.pydantic.dev/latest/migration/#required-optional-and-nullable-fields, that would mean b is required, could be None, but by default is default.

But my schema very clearly says that the field is required, cannot be None (if I wanted to allow null values, I would have defined this field as a oneOf that included a {"type": "null"}), and takes a default of default.

I would expect to get the below.

from __future__ import annotations

from typing import Optional

from pydantic import BaseModel, ConfigDict


class Model(BaseModel):
    model_config = ConfigDict(
        extra='forbid',
    )
    a: str
    b: str = 'default'

which accurately displays my intention...if you give some value for b, it'd better be a string. But if it's not provided, that's okay, use 'default'. Maybe this is related to #670, but I'm not convinced. Pydantic supports the behavior I want already...it's this package which isn't handling it properly.

tldr, if I have a default on a required field, the code generator shouldn't be setting an optional unless null is explicitly in the type definition.

Version:

  • OS: WSL (ubuntu)
  • Python version: 3.10.11
  • datamodel-code-generator version: 0.21.1

gloshkajian avatar Jul 21 '23 03:07 gloshkajian

@gloshkajian Thank you for creating the issue. I'm thinking whether we should change the behavior...

Could you please try --strict-nullable option? you can generate the expected models.

koxudaxi avatar Jul 21 '23 04:07 koxudaxi

@koxudaxi thank you for responding so quickly! Are we sure about strict-nullable? I'm working with jsonschemas, the help flag suggests that this option is only for openapi. I'll try it in a few hours, but not sure this helps me. Side note, I don't think the behavior I want here is (or should be) openapi specific.

gloshkajian avatar Jul 21 '23 05:07 gloshkajian

@gloshkajian you are right. I forget why I wrote only OpenAPI. I will confirm the history.

koxudaxi avatar Jul 21 '23 05:07 koxudaxi

Hi, just checking in on whether there has been any update on this issue? We have a very large JSON schema that we convert to Pydantic V2 and encounter the same, so it becomes a little hard to keep track of which properties should really be Optional and which ones are just Optional because of the bug.

We are using datamodel-code-generator 0.22.0

If the issue is not too complex, I could also try to have a stab at it.

my-tien avatar Oct 19 '23 10:10 my-tien