Skip to content

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. "either token or role_id+secret_id is set", as VaultSource does).
  • __repr__() — defaults to f"{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.