Skip to main content

dynamic-config-py-remote

All eight Rust remote stores — Consul, etcd, Firestore, git, NATS, Redis, S3 and HashiCorp Vault — for dynamic-config-py.

pip install dynamic-config-py[remote]
from dataclasses import dataclass

from dynamic_config import DynamicConfig
from dynamic_config.remote import Auth, Etcd, Vault


@dataclass
class Database:
    host: str = "localhost"
    port: int = 5432


config = DynamicConfig(Database, key="db").remote(
    Etcd(["http://etcd.internal:2379"], "myapp/db.json")
)
config.refresh_remote()      # reads the store, keeps the document
config.init()                # merges it, validates, installs

db = config.current()

Configuration in git, which is where a great many teams already keep it — one commit, one tree, so a set of files is read as of one instant:

from dynamic_config.remote import Git, GitAuth, GitKeys

config = DynamicConfig(Database, key="db").remote(
    Git(
        "https://github.com/acme/config.git",
        GitKeys.several(["services/api/base.yaml", "services/api/local.yaml"]),
        branch="main",
        # An installation token lives an hour; a watcher lives for the life
        # of the process. So the credential is a callable, and a rotated one
        # rebuilds nothing — the object database survives it.
        auth=GitAuth.token(mint_an_installation_token),
    )
)

Vault, with a credential that outlives the process that started:

from pathlib import Path

config = DynamicConfig(Database, key="db").remote(
    Vault(
        "https://vault.internal:8200",
        "secret",
        "myapp/db",
        auth=Auth.token(lambda: Path("/var/run/vault/token").read_text()),
    )
)

Why this is a second wheel

A wheel is built per platform, so a dependency in the ordinary wheel is in every install of it — including the ones reading a single TOML file. etcd speaks gRPC, the AWS SDK brings its own runtime and signing stack, NATS brings a protocol, git brings gix and three more bring HTTP over rustls: eight clients is most of an async ecosystem. They stay out until somebody asks for them.

A pip extra installs distributions, not Cargo features: a wheel compiled weeks ago on a release runner cannot have a feature turned on at install time. So dynamic-config-py[remote] resolves to this distribution, which contains the same engine built with the stores in it.

What it is not

It is not a second binding. These stores are ordinary dynamic_config.RemoteSource implementations — they answer fetch() with a (document, format) pair, and the base wheel merges it through the path it already had for a store written in Python. Nothing Rust crosses between the two extension modules, which is why the base wheel needed no change to accept these.

Credentials

Every credential argument accepts a callable, and that is the feature rather than a convenience: a configuration watcher outlives its credentials. A Vault token expires, an AppRole secret id is rewritten by a sidecar, an etcd password is rotated. A callable is invoked on every fetch, and a value that has changed rebuilds the client with it.

Etcd(["http://etcd:2379"], "myapp/db.json",
     user="myapp", password=lambda: os.environ["ETCD_PASSWORD"])

Auth.app_role(role_id, secret_id=lambda: read_secret_id())

Redis("redis://redis:6379", "myapp/db.json", password=lambda: read_password())

S3("myapp-config", "prod/db.json", access_key_id=lambda: current_key_id(),
   secret_access_key=lambda: current_secret())

S3 is the one whose credential is not a string. The AWS SDK takes a ProvideCredentials implementation and asks it per request, so a callable becomes a shim over a slot the fetch path writes — which means a rotated key rebuilds nothing, and which is also why passing no credentials at all is a first-class mode: the SDK's own chain (environment, profile, instance role, IRSA) is what most deployments should use.

Credentials never appear in a diagnostic — not in an exception message, not in a repr, not in describe(). A store URL that embeds user:password@host loses the password by the same rule the Rust store crates use, and every credential resolved for a call is scrubbed by value from anything that call reports.

TLS

A private certificate authority and a client certificate, spelled the same way for all eight stores:

Vault("https://vault.internal:8200", "secret", "myapp/db",
      auth=Auth.kubernetes("myapp"),
      tls=TlsConfig()
          .with_ca_certificate_file("/etc/ssl/private-ca.pem")
          .with_client_certificate_files("/etc/ssl/app.crt", "/etc/ssl/app.key"))

Each setting has a file spelling and a PEM-bytes one, because a Kubernetes secret mount produces files and a secrets manager produces bytes — and writing bytes to a temporary file so a client could read them back would put a private key on a disk that never asked for one. An empty TlsConfig is the platform's own trust store; a named authority replaces it, which is what pinning means.

Two stores cannot express all of it and refuse the part they cannot, at construction, naming the call and the way out. Nats takes certificate paths and not bytes (async-nats opens the files itself) and S3 takes no client certificate (the AWS SDK's TLS context has no slot for one). Ignoring either would leave a program believing it had pinned an authority when it had not. Git expresses all four settings and refuses them on a url that is not https://, because an ssh remote's trust lives in known_hosts; it is also the one store that adds a named authority to the platform's trust store rather than replacing it.

The private key is never rendered: repr() delegates to the Rust type's Debug, which prints a path where there is one and <redacted> where the key is bytes.

The tokio runtime

One, lazily, owned by the module. It starts when the first store that needs one is constructed — Etcd, Nats and S3 do; Consul, Firestore, Git, Redis and Vault are blocking and do not — and never shuts down; dynamic_config_remote.runtime_started() is how that promise is tested. Nothing running on it touches Python, which is what makes an immortal runtime safe here. See the book's Remote stores in Rust, from Python.

Which stores

All eight, one Python class each: Consul, Etcd, Firestore, Git, Nats, Redis, S3 and Vault, with ConsulAuth, FirestoreAuth, GitAuth, NatsAuth and Auth (Vault's) for the ones that log in, GitKeys for the one that reads a set, and TlsConfig for all of them. What is deliberately not here — each client's own configuration type, and with it a custom proxy; the multi-key forms for the seven that are not git; watch() — is listed in the book, with the reason in each case.

License

MIT

Metadata

Release files for dynamic-config-py-remote 0.3.3

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Built distributions (wheels)

Table of built distributions (wheels) for dynamic-config-py-remote 0.3.3
File
dynamic_config_py_remote-0.3.3-cp39-abi3-win_amd64.whl CPython 3.9 abi3 Windows x86-64 Details
dynamic_config_py_remote-0.3.3-cp39-abi3-manylinux_2_28_x86_64.whl CPython 3.9 abi3 Linux glibc 2.28+ x86-64 Details
dynamic_config_py_remote-0.3.3-cp39-abi3-manylinux_2_28_aarch64.whl CPython 3.9 abi3 Linux glibc 2.28+ ARM64 Details
dynamic_config_py_remote-0.3.3-cp39-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl CPython 3.9 abi3 macOS 10.12+ x86-64, macOS 11.0+ ARM64, macOS 10.12+ universal2 (ARM64, x86-64) Details

Total release size: 47.2 MB

Release files / dynamic_config_py_remote-0.3.3-cp39-abi3-win_amd64.whl

Download URL dynamic_config_py_remote-0.3.3-cp39-abi3-win_amd64.whl
Size 9.8 MB
Tags CPython 3.9 Windows x86-64 abi3
SHA-256 checksum
How to use checksums
05629771f2dbd46180cf009ad616c2bbcaeb170904c8c374b8b4875b17111fde
BLAKE2b-256 checksum
How to use checksums
54ba4c2673af7d2311aaa9fd10194569aad92293b72bf8327be4f78d1b4e2d4d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 23, 2026.

Transparency log

Release files / dynamic_config_py_remote-0.3.3-cp39-abi3-manylinux_2_28_x86_64.whl

Download URL dynamic_config_py_remote-0.3.3-cp39-abi3-manylinux_2_28_x86_64.whl
Size 9.9 MB
Tags CPython 3.9 Linux glibc 2.28+ x86-64 abi3
SHA-256 checksum
How to use checksums
2f9e4027f1e3c3cb2631f905b79674cc036917a8a69398e0065b42abef57bee4
BLAKE2b-256 checksum
How to use checksums
5047e275f89fe5f1eb6ad8da413913f842dcb902018a25b128130a1757364203
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 23, 2026.

Transparency log

Release files / dynamic_config_py_remote-0.3.3-cp39-abi3-manylinux_2_28_aarch64.whl

Download URL dynamic_config_py_remote-0.3.3-cp39-abi3-manylinux_2_28_aarch64.whl
Size 9.5 MB
Tags CPython 3.9 Linux glibc 2.28+ ARM64 abi3
SHA-256 checksum
How to use checksums
0b6d04d4d9cdf10aa45650e3035e108001ca1f5dc5993af6c81ba51576bca2c7
BLAKE2b-256 checksum
How to use checksums
5d45dcaebbc91c4bf7689e09fe3e32cc7c588680292c3c0b45c34da248edd220
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 23, 2026.

Transparency log

Release files / dynamic_config_py_remote-0.3.3-cp39-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl

Download URL dynamic_config_py_remote-0.3.3-cp39-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl
Size 18.0 MB
Tags CPython 3.9 abi3 macOS 10.12+ universal2 (ARM64, x86-64) macOS 10.12+ x86-64 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
0bfb8cf7482d04582c3b205dbb0864782097901819a535be238de61803126e67
BLAKE2b-256 checksum
How to use checksums
80cf942b7af9144fc7f16f3c53a16e3ffc817125c28e4c0497f651fbacf18f44
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 23, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.3.3 This release

4 release files

0.3.2

4 release files

0.3.1

4 release files

0.3.0

4 release files

0.2.0

4 release files

0.1.3

4 release files

0.1.2

4 release files

0.1.1

4 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page