Describe the bug
With --enum-field-as-literal=all + --use-type-alias on a Pydantic v2 OpenAPI spec, named enum schemas in components.schemas only become a top-level TypeAliasType("Name", Literal[...]) if they are referenced from at least one operation parameter. Enums referenced only from another schema's properties are inlined at every reference site, with the original name reduced to a Field(title="<Name>") hint.
This contradicts the resolution claimed for #1285 in PR #2505, which describes the combination as producing a named alias for any enum schema regardless of how it is referenced.
To reproduce
EnumFromParam is referenced from a query parameter; EnumFromProperty is referenced from a schema property.
Example schema:
{
"openapi": "3.0.3",
"info": { "title": "repro", "version": "0.0.1" },
"paths": {
"/things": {
"get": {
"parameters": [
{
"name": "ownership",
"in": "query",
"schema": { "$ref": "#/components/schemas/EnumFromParam" }
}
],
"responses": {
"200": {
"description": "ok",
"content": {
"application/json": {
"schema": { "$ref": "#/components/schemas/Thing" }
}
}
}
}
}
}
},
"components": {
"schemas": {
"EnumFromParam": { "type": "string", "enum": ["a", "b"] },
"EnumFromProperty": { "type": "string", "enum": ["x", "y"] },
"Thing": {
"type": "object",
"properties": {
"kind": { "$ref": "#/components/schemas/EnumFromProperty" }
}
}
}
}
}
Used command line:
$ datamodel-codegen \
--input repro.json \
--input-file-type openapi \
--output out.py \
--target-python-version 3.11 \
--output-model-type pydantic_v2.BaseModel \
--use-annotated \
--use-union-operator \
--enum-field-as-literal all \
--use-type-alias
Observed output:
EnumFromParam = TypeAliasType("EnumFromParam", Literal['a', 'b'])
class Thing(BaseModel):
kind: Annotated[Literal['x', 'y'] | None, Field(title='EnumFromProperty')] = None
Expected behavior
Both named enum schemas should produce a top-level alias, identically — not just the parameter-referenced one:
EnumFromParam = TypeAliasType("EnumFromParam", Literal['a', 'b'])
EnumFromProperty = TypeAliasType("EnumFromProperty", Literal['x', 'y'])
class Thing(BaseModel):
kind: EnumFromProperty | None = None
Version
- OS: Fedora Linux 43
- Python version: 3.11
- datamodel-code-generator version: 0.56.0
Additional context
Variations that don't change the behavior: --collapse-root-models on/off, --reuse-model, removing --use-schema-description, stripping title/description from the enum schema. --enum-field-as-literal=one instead of all falls back to class Name(StrEnum): ... for every named enum.
Without a stable named alias, the enum's value list is duplicated at every reference site (painful for large enums — e.g. an ErrorType with hundreds of members) and downstream code can't import the name to reuse in its own annotations. The Field(title=...) hint is documentation-only.
Two possible fixes:
- Make
--enum-field-as-literal=all + --use-type-alias emit a named alias for every enum schema in components.schemas, regardless of how it is referenced.
- Or add a dedicated flag (e.g.
--enum-as-literal-alias) that emits Name: TypeAlias = Literal[...] for named enum schemas only, independently of --use-type-alias.
Related: #1285, #2505 (original request and the PR that was supposed to cover this), #3009, #3092 (related bugs blocking adjacent workarounds).
Describe the bug
With
--enum-field-as-literal=all+--use-type-aliason a Pydantic v2 OpenAPI spec, named enum schemas incomponents.schemasonly become a top-levelTypeAliasType("Name", Literal[...])if they are referenced from at least one operation parameter. Enums referenced only from another schema's properties are inlined at every reference site, with the original name reduced to aField(title="<Name>")hint.This contradicts the resolution claimed for #1285 in PR #2505, which describes the combination as producing a named alias for any enum schema regardless of how it is referenced.
To reproduce
EnumFromParamis referenced from a query parameter;EnumFromPropertyis referenced from a schema property.Example schema:
{ "openapi": "3.0.3", "info": { "title": "repro", "version": "0.0.1" }, "paths": { "/things": { "get": { "parameters": [ { "name": "ownership", "in": "query", "schema": { "$ref": "#/components/schemas/EnumFromParam" } } ], "responses": { "200": { "description": "ok", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Thing" } } } } } } } }, "components": { "schemas": { "EnumFromParam": { "type": "string", "enum": ["a", "b"] }, "EnumFromProperty": { "type": "string", "enum": ["x", "y"] }, "Thing": { "type": "object", "properties": { "kind": { "$ref": "#/components/schemas/EnumFromProperty" } } } } } }Used command line:
Observed output:
Expected behavior
Both named enum schemas should produce a top-level alias, identically — not just the parameter-referenced one:
Version
Additional context
Variations that don't change the behavior:
--collapse-root-modelson/off,--reuse-model, removing--use-schema-description, strippingtitle/descriptionfrom the enum schema.--enum-field-as-literal=oneinstead ofallfalls back toclass Name(StrEnum): ...for every named enum.Without a stable named alias, the enum's value list is duplicated at every reference site (painful for large enums — e.g. an
ErrorTypewith hundreds of members) and downstream code can't import the name to reuse in its own annotations. TheField(title=...)hint is documentation-only.Two possible fixes:
--enum-field-as-literal=all+--use-type-aliasemit a named alias for every enum schema incomponents.schemas, regardless of how it is referenced.--enum-as-literal-alias) that emitsName: TypeAlias = Literal[...]for named enum schemas only, independently of--use-type-alias.Related: #1285, #2505 (original request and the PR that was supposed to cover this), #3009, #3092 (related bugs blocking adjacent workarounds).