mirror of
https://github.com/jbranchaud/til
synced 2026-09-01 01:01:46 +00:00
Add Combine StrEnum With Pydantic For Union Type as a Python TIL
This commit is contained in:
@@ -10,7 +10,7 @@ working across different projects via [VisualMode](https://www.visualmode.dev/).
|
||||
|
||||
For a steady stream of TILs, [sign up for my newsletter](https://visualmode.kit.com/newsletter).
|
||||
|
||||
_1857 TILs and counting..._
|
||||
_1858 TILs and counting..._
|
||||
|
||||
See some of the other learning resources I work on:
|
||||
|
||||
@@ -1087,6 +1087,7 @@ If you've learned something here, support my efforts writing daily TILs by
|
||||
- [Break Debugger On First Line Of Program](python/break-debugger-on-first-line-of-program.md)
|
||||
- [Check If Package Is Installed With Pip](python/check-if-package-is-installed-with-pip.md)
|
||||
- [Check Precondition Before Click Arg Parsing](python/check-precondition-before-click-arg-parsing.md)
|
||||
- [Combine StrEnum With Pydantic For Union Type](python/combine-strenum-with-pydantic-for-union-type.md)
|
||||
- [Commit Writes From Executed SQLite Statements](python/commit-writes-from-executed-sqlite-statements.md)
|
||||
- [Configure Other Attributes Of Dataclass Field](python/configure-other-attributes-of-dataclass-field.md)
|
||||
- [Control Passing Of Time In Tests](python/control-passing-of-time-in-tests.md)
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
# Combine StrEnum With Pydantic For Union Type
|
||||
|
||||
I want a [Pydantic](https://pydantic.dev/docs/validation/latest/get-started/)
|
||||
model that I can use to verify the shape and values of user-provided config
|
||||
file. Let's say, for now, the only config value supported by the file is
|
||||
`storage_format` and it can be one of three values (`json`, `sqlite`,
|
||||
`inmemory`).
|
||||
|
||||
I can start with a
|
||||
[`StrEnum`](https://docs.python.org/3/library/enum.html#enum.StrEnum) class to
|
||||
represent the set of valid values for the storage format field.
|
||||
|
||||
```python
|
||||
from enum import StrEnum
|
||||
from typing import Literal
|
||||
|
||||
class StorageFormat(StrEnum):
|
||||
SQLITE = "sqlite"
|
||||
JSON = "json"
|
||||
INMEMORY = "inmemory"
|
||||
|
||||
@classmethod
|
||||
def default(cls) -> Literal[StorageFormat.SQLITE]:
|
||||
return cls.SQLITE
|
||||
```
|
||||
|
||||
Notice I've also provided a class method called `default` for serving up a
|
||||
fallback default value.
|
||||
|
||||
Here is the corresponding Pydantic `CliConfig` model which uses the
|
||||
`StorageFormat` string enum class as the type signature for its `storage_format`
|
||||
field.
|
||||
|
||||
```python
|
||||
from pydantic import BaseModel
|
||||
|
||||
class CliConfig(BaseModel):
|
||||
storage_format: StorageFormat = StorageFormat.default()
|
||||
```
|
||||
|
||||
For `storage_format` to be valid in the context of `CliConfig`, it must be one
|
||||
of the values defined by that `StrEnum`. I get auto-complete, I get type
|
||||
checking, and I can validate a config file I've just read into memory (in this
|
||||
case, using
|
||||
[`model_validate_json`](https://pydantic.dev/docs/validation/dev/api/pydantic/base_model/#pydantic.BaseModel.model_validate_json)).
|
||||
|
||||
```python
|
||||
def _read_config(self) -> CliConfig:
|
||||
if self.exists():
|
||||
raw_json = self.config_file.read_text()
|
||||
return CliConfig.model_validate_json(raw_json)
|
||||
|
||||
return CliConfig()
|
||||
```
|
||||
Reference in New Issue
Block a user