Field Groups#
Ensure related fields are always overridden together:
"""Field groups — ensure related fields change together."""
from dataclasses import dataclass
from pathlib import Path
import dature
SHARED_DIR = Path(__file__).parents[2] / "shared"
@dataclass
class Config:
host: str
port: int
debug: bool
user: str
password: str
config = dature.load(
dature.Yaml12Source(file=SHARED_DIR / "common_field_groups_defaults.yaml"),
dature.Yaml12Source(file=SHARED_DIR / "common_field_groups_overrides.yaml"),
schema=Config,
field_groups=((dature.F[Config].host, dature.F[Config].port),),
)
assert config.host == "production.example.com"
assert config.port == 8080
assert config.user == "admin"
assert config.password == "secret"
If overrides.yaml changes host and port together, the group constraint is satisfied. If a source partially overrides a group, FieldGroupError is raised:
"""Field groups — error on partial override (basic)."""
from dataclasses import dataclass
from pathlib import Path
import dature
SOURCES_DIR = Path(__file__).parent / "sources"
SHARED_DIR = Path(__file__).parents[2] / "shared"
@dataclass
class Config:
host: str
port: int
debug: bool
user: str
password: str
dature.load(
dature.Yaml12Source(file=SHARED_DIR / "common_field_groups_defaults.yaml"),
dature.Yaml12Source(
file=SOURCES_DIR / "field_groups_partial_overrides.yaml",
),
schema=Config,
field_groups=(
(dature.F[Config].host, dature.F[Config].port),
(dature.F[Config].user, dature.F[Config].password),
),
)
| dature.errors.exceptions.FieldGroupError: Config field group errors (1)
+-+---------------- 1 ----------------
| dature.errors.exceptions.FieldGroupViolationError: Field group (host, port) partially overridden in source 1
| changed: host (from source yaml1.2 '{SOURCES_DIR}field_groups_partial_overrides.yaml')
| unchanged: port (from source yaml1.2 '{SHARED_DIR}common_field_groups_defaults.yaml')
+------------------------------------
Nested Dataclass Expansion#
Passing a dataclass field expands it into all its leaf fields:
"""Field groups — error on partial override with nested dataclass expansion."""
from dataclasses import dataclass
from pathlib import Path
import dature
SOURCES_DIR = Path(__file__).parent / "sources"
@dataclass
class Database:
host: str
port: int
@dataclass
class Config:
host: str
port: int
database: Database
# (dature.F[Config].database, dature.F[Config].port)
# expands to (database.host, database.port, port)
dature.load(
dature.Yaml12Source(file=SOURCES_DIR / "field_groups_nested_defaults.yaml"),
dature.Yaml12Source(
file=SOURCES_DIR
/ "advanced_field_groups_expansion_error_overrides.yaml",
),
schema=Config,
field_groups=((dature.F[Config].database, dature.F[Config].port),),
)
| dature.errors.exceptions.FieldGroupError: Config field group errors (1)
+-+---------------- 1 ----------------
| dature.errors.exceptions.FieldGroupViolationError: Field group (database.host, database.port, port) partially overridden in source 1
| changed: database.host (from source yaml1.2 '{SOURCES_DIR}advanced_field_groups_expansion_error_overrides.yaml'), port (from source yaml1.2 '{SOURCES_DIR}advanced_field_groups_expansion_error_overrides.yaml')
| unchanged: database.port (from source yaml1.2 '{SOURCES_DIR}field_groups_nested_defaults.yaml')
+------------------------------------
Multiple Groups#
If a source partially overrides multiple groups, all violations are reported:
"""Multiple field groups — error when both groups partially overridden."""
from dataclasses import dataclass
from pathlib import Path
import dature
SOURCES_DIR = Path(__file__).parent / "sources"
SHARED_DIR = Path(__file__).parents[2] / "shared"
@dataclass
class Config:
host: str
port: int
debug: bool
user: str
password: str
OVERRIDES_FILE = (
SOURCES_DIR / "advanced_field_groups_multiple_error_overrides.yaml"
)
dature.load(
dature.Yaml12Source(file=SHARED_DIR / "common_field_groups_defaults.yaml"),
dature.Yaml12Source(file=OVERRIDES_FILE),
schema=Config,
field_groups=(
(dature.F[Config].host, dature.F[Config].port),
(dature.F[Config].user, dature.F[Config].password),
),
)
| dature.errors.exceptions.FieldGroupError: Config field group errors (2)
+-+---------------- 1 ----------------
| dature.errors.exceptions.FieldGroupViolationError: Field group (host, port) partially overridden in source 1
| changed: host (from source yaml1.2 '{SOURCES_DIR}advanced_field_groups_multiple_error_overrides.yaml')
| unchanged: port (from source yaml1.2 '{SHARED_DIR}common_field_groups_defaults.yaml')
+---------------- 2 ----------------
| dature.errors.exceptions.FieldGroupViolationError: Field group (user, password) partially overridden in source 1
| changed: user (from source yaml1.2 '{SOURCES_DIR}advanced_field_groups_multiple_error_overrides.yaml')
| unchanged: password (from source yaml1.2 '{SHARED_DIR}common_field_groups_defaults.yaml')
+------------------------------------
Field groups work with all merge strategies and can be combined with field_merges.