Skip to content

--use-type-alias + --use-annotated + --enum-field-as-literal all generates callable TypeAliasType in default_factory #3009

@keyz

Description

@keyz

Describe the bug

Version

  • datamodel-code-generator: 0.54.0
  • Python: 3.12.12

Summary

When all of these options are used together:

  • --use-type-alias
  • --use-annotated
  • --enum-field-as-literal all

a defaulted $ref to an enum-like schema can generate code that calls a Python 3.12 type alias as if it were a constructor.

That produces invalid generated code like:

type Mode = Literal["default", "plan"]

class Model(BaseModel):
    mode: Annotated[Mode | None, Field(default_factory=lambda: Mode("default"))]
                                                             # ^ Object of type "TypeAliasType" is not callable

To Reproduce

Example schema:

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "type": "object",
  "definitions": {
    "Mode": {
      "type": "string",
      "enum": ["default", "plan"]
    }
  },
  "properties": {
    "mode": {
      "$ref": "#/definitions/Mode",
      "default": "default"
    }
  }
}

Used commandline:

$ datamodel-codegen \
  --input repro.json \
  --input-file-type jsonschema \
  --output out.py \
  --output-model-type pydantic_v2.BaseModel \
  --target-python-version 3.12 \
  --enum-field-as-literal all \
  --use-type-alias \
  --use-annotated

Expected behavior
The generated default should not call a type alias.

Perhaps just this?

mode: Annotated[Mode | None, Field(default_factory=lambda: "default")]

Version:

  • OS: [e.g. iOS]: macOS
  • Python version: 3.12.12
  • datamodel-code-generator version: [e.g. 22] 0.54.0

Additional context
This seems specific to the interaction of these flags:

  • Without --use-type-alias, generation uses a wrapper model and works.
  • Without --use-annotated, generation emits = "default" and works.
  • Without --enum-field-as-literal all, generation uses an enum class and works.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions