Cross-Source References#
Sources can reference values from other sources using the ${@tag.key} syntax. This lets you pass a Vault token from an env variable, resolve a config file path from a CLI argument, or build connection strings that combine several sources — without imperative glue code.
Quick start#
The env in ${@env.config_path} is the source tag. By default the tag equals the source type's format_name — "env" for EnvSource, "json" for JsonSource, and so on. Set tag= explicitly when you have two sources of the same type.
Sources can be passed in any order: dature builds a dependency graph from ${@tag.key} patterns and loads them in topological order automatically. In the example above JsonSource is listed first but loaded second because it depends on EnvSource.
Syntax#
| Pattern | Result |
|---|---|
${@tag.key} | Value of key in the source tagged tag |
${@tag.section.key} | Nested key path (dot-separated) |
${@tag.key:-default} | Use default if key is absent |
$${@tag.key} | Literal ${@tag.key} (escape with $$) |
Escaping#
Prefix $$ to produce a literal $. This is useful when a config-file path should contain ${@...} literally rather than be treated as a cross-ref:
T-string syntax (Python 3.14+)#
Requires Python 3.14+
T-strings (PEP 750) are a Python 3.14 language feature. On earlier versions use the ${@tag.key} string syntax instead.
from dature import ref gives you a proxy object. ref.tag.key inside a t-string is exactly equivalent to "${@tag.key}" as a plain string:
from dataclasses import dataclass
import dature
from dature import ref
@dataclass
class AppConfig:
host: str = "localhost"
port: int = 8080
# t"{ref.env.config_path}" ≡ "${@env.config_path}"
# t"{ref.env.log_level:INFO}" ≡ "${@env.log_level:-INFO}"
cfg = dature.load(
dature.JsonSource(file=t"{ref.env.config_path}"),
dature.EnvSource(prefix="APP_"),
schema=AppConfig,
)
assert cfg.host == "db.internal"
assert cfg.port == 5432
The format spec becomes the default value — t"{ref.env.log_level:INFO}" is the same as "${@env.log_level:-INFO}".
Error messages#
Unknown tag#
Cycle#
dature.errors.exceptions.DatureError: Cross-source reference cycle detected:
EnvSource(tag='env') → references ${@json.prefix_key}
JsonSource(tag='json') → references ${@env.config_path}
closes back to EnvSource(tag='env')
Sources cannot reference each other's data in a cycle. Break the cycle by hardcoding one side or parsing one source imperatively.
Tag collision#
Each source resolves to a tag that uniquely identifies it within a dature.load() call. If two sources resolve to the same tag, dature raises an error. EnvSource defaults to tag='env'. Loading two EnvSource instances without explicitly setting a tag on at least one of them will cause a collision:
dature.errors.exceptions.DatureError: Tag collision: multiple sources share resolved_tag='env':
EnvSource(prefix='APP_', expand_env_vars='default', nested_resolve_strategy='flat')
EnvSource(prefix='DB_', expand_env_vars='default', nested_resolve_strategy='flat')
Set an explicit tag= on at least one of them.