Customizing Converters¶
When working with attrs or dataclasses,
you can choose between two converters:
the built-in TSConverter
and
a cattrs.Converter
.
The built-in converter allows you to use Typed Settings with fewer (or even no) dependencies but it cannot be customized easily.
However, customization is one of cattrs’ many strengths. This section provides only a few recipes, so you may want to read cattrs’ full Customizing (Un-)structuring docs.
Enums¶
Typed Settings structures enum.Enum
instances by name and enum.StrEnum
as well as enum.IntEnum
instances by value.
If you don’t like this behavior,
you can reconfigure the converter with the help of typed_settings.converters.to_enum_by_name()
and typed_settings.converters.to_enum_by_value()
:
import enum
import functools
import typed_settings as ts
class LeEnum(enum.Enum):
spam = "Le spam"
eggs = "Le eggs"
@ts.settings
class Settings:
option: LeEnum
converter = ts.converters.get_default_cattrs_converter()
converter.register_structure_hook(LeEnum, ts.converters.to_enum_by_value)
settings = ts.load_settings(
Settings,
ts.default_loaders("myapp"),
converter=converter
)
print(settings)
$ MYAPP_OPTION="Le spam" python example.py
Settings(option=<LeEnum.spam: 'Le spam'>)
Why different behaviors?
Sqlalchemy (de)structures enums by name when used as column type.
Pydantic and Cattrs (de)structure enums by value – probably because it is more human readable?
The first versions of Typed Settings only supported
enum.Enum
.It used “by name” because I deemed it safer / less error prone, especially when used as command line options (e.g., via
click.Choice
).Support for
enum.StrEnum
andenum.IntEnum
was added in 25.0.I decided to follow the example of Cattrs/Pydantic and structure them by value. This also makes sense because they inherit
str
/int
and their value is what you get when you callstr
/int
on them.I didn’t change the behavior for
enum.Enum
for backwards compatibility.