Pydantic enum field does not get converted to string

Question:

I am trying to restrict one field in a class to an enum. However, when I try to get a dictionary out of class, it doesn’t get converted to string. Instead it retains the enum. I checked pydantic documentation, but couldn’t find anything relevant to my problem.

This code is representative of what I actually need.

from enum import Enum
from pydantic import BaseModel

class S(str, Enum):
    am = 'am'
    pm = 'pm'

class K(BaseModel):
    k: S
    z: str

a = K(k='am', z='rrrr')
print(a.dict()) # {'k': <S.am: 'am'>, 'z': 'rrrr'}

I’m trying to get the .dict() method to return {'k': 'am', 'z': 'rrrr'}

Asked By: ierdna

||

Answers:

You need to use use_enum_values option of model config:

use_enum_values

whether to populate models with the value property of enums, rather than the raw enum. This may be useful if you want to serialise model.dict() later (default: False)

from enum import Enum
from pydantic import BaseModel

class S(str, Enum):
    am='am'
    pm='pm'

class K(BaseModel):
    k:S
    z:str

    class Config:  
        use_enum_values = True  # <--

a = K(k='am', z='rrrr')
print(a.dict())
Answered By: alex_noname

You can use FastAPI’s jsonable_encoder:

from enum import Enum
from pydantic import BaseModel
from fastapi.encoders import jsonable_encoder

class S(str, Enum):
    am = 'am'
    pm = 'pm'

class K(BaseModel):
    k: S
    z: str

a = K(k='am', z='rrrr')
print(jsonable_encoder(a)) # {'k': 'am', 'z': 'rrrr'}
Answered By: y26805

The answer by using Config class is correct but may not be necessary.
It may be inconvenient to repeatedly implement and could be redundant for some readers so I offer easier alternatives and a short explanation.

TL;DR

  • For JSON serialization, no need to do anything. Using (Str,Enum) subclasses is enough without Config.
  • For printable representational string/other feature, create a custom StrEnum class. This was added in 3.11 but since previous versions don’t support it – I provide an example.

Example

from enum import Enum

class StrEnum(str, Enum):
    def __repr__(self) -> str:
        return str.__repr__(self.value)

class A(str, Enum):
    FOO = "foo"

class B(StrEnum):
    BAR= "bar"

class C(BaseModel):
    a: A = Field(...)
    b: B = Field(...)

print(C(a="foo", b="bar").dict())

import json

print(json.dumps(C(a="foo", b="bar").dict()))

Outputs:

{'a': <A.FOO: 'foo'>, 'b': 'bar'}
{"a": "foo", "b": "bar"}

Explanation

Class A and B are of types (str, Enum) and StrEnum, respectively.
Both are JSON serializable; StrEnum also prints as a primitive string.

Answered By: mr_mo