Custom Remote Source#
RemoteSource is the abstract base for sources that fetch configuration from remote services — secret managers, key-value stores, HTTP APIs. Subclass it to plug in any backend: AWS Secrets Manager, Azure Key Vault, Consul KV, or your own.
For the built-in HashiCorp Vault integration, see VaultSource.
Implementing a custom RemoteSource#
Subclass RemoteSource and implement two methods:
remote_address() -> str— human-readable identifier shown in error messages and debug reports (e.g. an ARN, a URL, a Consul path)._fetch() -> JSONValue— perform the actual fetch and return a dict (mapping field names to values). The base class handles caching, prefix stripping, env-var expansion, and error-location rendering for free.
from dataclasses import dataclass
from typing import ClassVar
import dature
from dature.sources.base import RemoteSource
from dature.type_aliases import JSONValue
@dataclass(kw_only=True, repr=False)
class InMemorySource(RemoteSource):
backend: dict[str, dict[str, JSONValue]]
key: str
format_name = "in-memory"
location_label: ClassVar[str] = "MEMORY"
def remote_address(self) -> str:
return f"memory://{self.key}"
def _fetch(self) -> JSONValue:
return self.backend[self.key]
@dataclass
class Config:
db_password: str
port: int
backend = {"myapp/config": {"db_password": "s3cret", "port": 5432}}
config = dature.load(
InMemorySource(backend=backend, key="myapp/config"),
schema=Config,
)
assert config == Config(db_password="s3cret", port=5432) # noqa: S106
Optional hooks#
validate()— runs after credential merge; override to enforce invariants (e.g. "eithertokenorrole_id+secret_idis set", asVaultSourcedoes).__repr__()— defaults tof"{self.format_name} '{self.remote_address()}'".
The config_group ClassVar that ties VaultSource to dature.configure(vault=...) is wired into dature.config.DatureConfig and is not extensible from outside the package. For a custom subclass, expose connection params via constructor arguments.
Not part of dature's API surface
The InMemorySource above is a teaching example. It is not shipped, not tested by dature's CI, and not bound by dature's backward-compatibility guarantees. Treat it as a starting point for your own implementation.