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

Enum fields generate default value using string type instead of enum causing pydantic serializer warning

Open devmonkey22 opened this issue 8 months ago • 2 comments

Describe the bug A generated model with an enum field generates its default value using string type instead of enum value causes pydantic serializer warnings:

.../env/lib/python3.10/site-packages/pydantic/main.py:477: UserWarning: Pydantic serializer warnings:
    Expected `enum` but got `str` with value `'synced'` - serialized value may not be as expected
    return self.__pydantic_serializer__.to_json(

The model output is:

status: Optional[Status] = Field("synced", title="Status")

Manually updating the model output to the following fixes the warning:

status: Optional[Status] = Field(Status.synced, title="Status")

To Reproduce

Example schema:


"components": {
	"schemas": {
		"settings.Setting": {
			"type": "object",
			"properties": {
				"status": {
					"title": "Status",
					"type": "string",
					"enum": [
						"uninitialized",
						"synced",
						"pending",
						"dispatched"
					],
					"default": "synced"
				},
			}
		}
	}
}

Used commandline alternative:

codegen.generate(
	SCHEMA_FILE,
	output=BASE_MODEL_OUTPUT_DIR,

	input_file_type=codegen.InputFileType.OpenAPI,
	output_model_type=codegen.DataModelType.PydanticV2BaseModel,
	target_python_version=codegen.PythonVersion.PY_310,
	base_class="sdk.ProjectBaseModel",
	custom_file_header=file_header,

	use_schema_description=True,
	use_field_description=True,
	use_subclass_enum=True,
	use_double_quotes=True,
	openapi_scopes=[codegen.OpenAPIScope.Schemas]
)

Expected behavior

Output the model with field as:

status: Optional[Status] = Field(Status.synced, title="Status")

Version:

  • OS: Ubuntu 22.04
  • Python version: 3.10
  • datamodel-code-generator version: 0.28.4

devmonkey22 avatar Mar 20 '25 21:03 devmonkey22

Not sure why this is not the default behaviour, but you can get what you expect by using the --set-default-enum-member flag.

kjagiello avatar May 09 '25 08:05 kjagiello

Thanks @kjagiello . The output is super close to what I need, but it generates an incorrect module path to the enum for me.

Without --set-default-enum-member:

# models/settings.py

class Status(StrEnum):
    pending = "pending"
    accepted = "accepted"

class Setting(BaseModel):
    ...
    status: Optional[Status] = Field("accepted")

With --set-default-enum-member:

# models/settings.py

class Status(StrEnum):
    pending = "pending"
    accepted = "accepted"

class Setting(BaseModel):
    ...
    status: Optional[Status] = Field(settings.Status.accepted)

From within the settings.py file, the path settings.Status.accepted is invalid and should have been just Status.accepted.

devmonkey22 avatar May 22 '25 12:05 devmonkey22