Custom Types#
Use type_loaders to teach dature how to parse custom types from strings.
Pass type_loaders as a dict[type, Callable] mapping types to conversion functions:
from dataclasses import dataclass
import dature
@dataclass(frozen=True, slots=True)
class Rgb:
r: int
g: int
b: int
def rgb_from_string(value: str) -> Rgb:
parts = value.split(",")
return Rgb(r=int(parts[0]), g=int(parts[1]), b=int(parts[2]))
@dataclass
class AppConfig:
name: str
color: Rgb
config = dature.load(
dature.Yaml12Source(
file=SOURCES_DIR / "custom_type_common.yaml",
type_loaders={Rgb: rgb_from_string}, # applies only to this file source
),
schema=AppConfig,
)
assert config == AppConfig(name="my-app", color=Rgb(r=255, g=128, b=0))
Per-source vs Global#
type_loaders can be set per-source in Source, in dature.load() for merge mode, or globally via configure():
from dataclasses import dataclass
import dature
@dataclass(frozen=True, slots=True)
class Rgb:
r: int
g: int
b: int
def rgb_from_string(value: str) -> Rgb:
parts = value.split(",")
return Rgb(r=int(parts[0]), g=int(parts[1]), b=int(parts[2]))
@dataclass
class AppConfig:
name: str
color: Rgb
config = dature.load(
dature.Yaml12Source(
file=SOURCES_DIR / "custom_type_common.yaml",
type_loaders={Rgb: rgb_from_string}, # applies only to this file source
),
schema=AppConfig,
)
assert config == AppConfig(name="my-app", color=Rgb(r=255, g=128, b=0))
from dataclasses import dataclass
import dature
@dataclass(frozen=True, slots=True)
class Rgb:
r: int
g: int
b: int
def rgb_from_string(value: str) -> Rgb:
parts = value.split(",")
return Rgb(r=int(parts[0]), g=int(parts[1]), b=int(parts[2]))
@dataclass
class AppConfig:
name: str
color: Rgb
config = dature.load(
dature.Yaml12Source(file=SOURCES_DIR / "custom_type_common.yaml"),
dature.Yaml12Source(file=SOURCES_DIR / "custom_type_merge_override.yaml"),
schema=AppConfig,
# applies to all sources within a single load() call
type_loaders={Rgb: rgb_from_string},
)
assert config == AppConfig(name="my-app", color=Rgb(r=100, g=200, b=50))
from dataclasses import dataclass
import dature
@dataclass(frozen=True, slots=True)
class Rgb:
r: int
g: int
b: int
def rgb_from_string(value: str) -> Rgb:
parts = value.split(",")
return Rgb(r=int(parts[0]), g=int(parts[1]), b=int(parts[2]))
@dataclass
class AppConfig:
name: str
color: Rgb
# Register Rgb parser globally — no need to pass type_loaders
# to every load() call
dature.configure(type_loaders={Rgb: rgb_from_string})
config = dature.load(
dature.Yaml12Source(file=SOURCES_DIR / "custom_type_common.yaml"),
schema=AppConfig,
)
assert config == AppConfig(name="my-app", color=Rgb(r=255, g=128, b=0))
When both per-source and global type_loaders are set, they merge — per-source loaders take priority.