Skip to main content

Minimal schema-agnostic configuration loader library

Project description

justconf

Minimal schema-agnostic configuration library for Python.

Provides simple, composable building blocks for configuration management:

  • Loaders — fetch config from various sources (environment variables, .env files, TOML)
  • Merge — combine multiple configs with deep merge and priority control
  • Processors — resolve placeholders from external sources (HashiCorp Vault)

Schema-agnostic: use your preferred validation library (Pydantic, msgspec, dataclasses) or none at all.

Table of Contents

Installation

pip install justconf

For .env file support:

pip install justconf[dotenv]

Quick Start

from justconf import env_loader, dotenv_loader, toml_loader, merge

# Load from multiple sources and merge (later sources have higher priority)
config = merge(
    toml_loader("config.toml"),      # base config
    dotenv_loader(".env"),           # override with .env
    env_loader(prefix="APP"),        # highest priority: environment variables
)

# Use with your preferred validation library
from pydantic import BaseModel

class DatabaseConfig(BaseModel):
    host: str
    port: int = 5432

class AppConfig(BaseModel):
    debug: bool = False
    database: DatabaseConfig

app_config = AppConfig(**config)

With Secret Resolution

from justconf import merge, toml_loader, process
from justconf.processor import VaultProcessor, TokenAuth

# Load and merge config
config = merge(
    toml_loader("config.toml"),
    {"db_password": "${vault:secret/db#password}"},  # placeholder for secret
)

# Resolve secrets from Vault
processor = VaultProcessor(
    url="http://vault:8200",
    auth=TokenAuth(token="hvs.xxx"),
)
config = process(config, [processor])
# {"db_password": "actual_password_from_vault", ...}

Loaders

Loaders fetch configuration from various sources and return a dictionary.

  • env_loader(prefix=None, case_sensitive=False) — loads from environment variables. If prefix is set, filters variables by prefix and strips it from keys.

    config = env_loader(prefix="APP")
    # APP_DEBUG=true, APP_PORT=8080 -> {"debug": "true", "port": "8080"}
    
  • dotenv_loader(path=".env", prefix=None, case_sensitive=False, encoding="utf-8") — loads from .env file. Requires pip install justconf[dotenv]. Supports variable interpolation (${VAR}).

    config = dotenv_loader(".env", prefix="APP")
    
  • toml_loader(path="config.toml", encoding="utf-8") — loads from TOML file using Python's built-in tomllib. Native TOML types are preserved (int, float, bool, list, dict, datetime).

    config = toml_loader("config.toml")
    

Nested Configuration

Use double underscores (__) to create nested structures from flat environment variables:

export DATABASE__HOST=localhost
export DATABASE__PORT=5432
config = env_loader()
# {"database": {"host": "localhost", "port": "5432"}}

Merge

The merge function combines multiple dictionaries with deep merge. Later arguments have higher priority.

from justconf import merge

config = merge(
    {"db": {"host": "localhost", "port": 5432}, "tags": ["a", "b"]},
    {"db": {"port": 3306}, "tags": ["c"]},
)
# {"db": {"host": "localhost", "port": 3306}, "tags": ["c"]}

Merge strategy:

  • dict + dict → recursive deep merge
  • Everything else (list, str, int, etc.) → overwrite

Processors

Processors resolve placeholders in your configuration, fetching values from external sources.

Placeholder Syntax

${processor:path#key|modifier:value}
  • processor — name of the processor (e.g., vault)
  • path — path to the secret
  • key — (optional) specific key within the secret
  • modifiers — (optional) post-processing modifiers

Placeholders can be embedded within strings:

config = {"dsn": "postgres://user:${vault:secret/db#password}@localhost/db"}

VaultProcessor

Fetches secrets from HashiCorp Vault (KV v2).

from justconf import process
from justconf.processor import VaultProcessor, TokenAuth

processor = VaultProcessor(
    url="http://vault:8200",
    auth=TokenAuth(token="hvs.xxx"),
    mount_path="secret",  # KV v2 mount path (default: "secret")
    timeout=30,           # request timeout in seconds
    verify=True,          # SSL verification (default: True)
)

config = {"api_key": "${vault:secret/api#key}"}
result = process(config, [processor])
# {"api_key": "actual_key"}

SSL Verification

The verify parameter controls SSL certificate verification:

  • verify=True (default) — use system CA certificates
  • verify=False — disable SSL verification (not recommended for production)
  • verify="/path/to/ca-bundle.crt" — use custom CA bundle
# For internal Vault with self-signed certificate
processor = VaultProcessor(
    url="https://vault.internal:8200",
    auth=TokenAuth(token="hvs.xxx"),
    verify="/etc/ssl/certs/internal-ca.crt",
)

Authentication Methods

VaultProcessor supports multiple Vault auth methods:

  • TokenAuth(token) — direct token authentication
  • AppRoleAuth(role_id, secret_id, mount_path="approle") — for AppRole automated workflows
  • JwtAuth(role, jwt, mount_path="jwt") — for JWT/OIDC (GitLab CI/CD, etc.)
  • KubernetesAuth(role, jwt=None, jwt_path="...", mount_path="kubernetes") — for Kubernetes pods; JWT is read from /var/run/secrets/kubernetes.io/serviceaccount/token by default
  • UserpassAuth(username, password, mount_path="userpass")username/password authentication

Auth Fallback Chain

Pass a list of auth methods to try them in order until one succeeds:

import os

processor = VaultProcessor(
    url="http://vault:8200",
    auth=[
        TokenAuth(token=os.environ.get("VAULT_TOKEN", "")),
        KubernetesAuth(role="myapp"),
        AppRoleAuth(role_id="xxx", secret_id="yyy"),
    ],
)

File Modifier

Write secrets to files instead of keeping them in memory. Useful for certificates and keys:

config = {
    "tls_cert": "${vault:secret/tls#cert|file:/etc/ssl/cert.pem}",
    "tls_key": "${vault:secret/tls#key|file:/etc/ssl/key.pem|encoding:utf-8}",
}

result = process(config, [processor])
# {"tls_cert": "/etc/ssl/cert.pem", "tls_key": "/etc/ssl/key.pem"}
# Files are created with the secret content

If the value is a dict or list, it's serialized as JSON.

Development

Debugging with a real Vault server

You can use a real Vault server to debug this project. To make this process easier, this project includes a docker-compose.yml file that can run a ready-to-use Vault server.

To run the server and set it up, run the following commands:

docker compose up
make vault

After that, you will have a Vault server running at http://localhost:8200, where you can authorize in three ways:

  • using the root token (which is token)
  • using the JWT method (role=jwt_role, token=link)
  • using the AppRole method (the values of role_id and secret_id can be found in the logs of the make vault command).

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

justconf-0.2.0a1.tar.gz (54.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

justconf-0.2.0a1-py3-none-any.whl (13.7 kB view details)

Uploaded Python 3

File details

Details for the file justconf-0.2.0a1.tar.gz.

File metadata

  • Download URL: justconf-0.2.0a1.tar.gz
  • Upload date:
  • Size: 54.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.26 {"installer":{"name":"uv","version":"0.9.26","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for justconf-0.2.0a1.tar.gz
Algorithm Hash digest
SHA256 f244d44b0950f0ff6bd3a33eab4229d92fbdd0c45f11938c5e368302a5c2f106
MD5 3f46f86973e5e448d132fe6f2930952d
BLAKE2b-256 b6080def9e3b7100d39fa5d270541945c5f254d9b11ceb8435403949d1e5e06b

See more details on using hashes here.

File details

Details for the file justconf-0.2.0a1-py3-none-any.whl.

File metadata

  • Download URL: justconf-0.2.0a1-py3-none-any.whl
  • Upload date:
  • Size: 13.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.26 {"installer":{"name":"uv","version":"0.9.26","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for justconf-0.2.0a1-py3-none-any.whl
Algorithm Hash digest
SHA256 51600b010cd8781c8397fba04f287c721fc045fc81fabe1b1d11751825cea0ad
MD5 f9a23c8c1d67121c3d2132aaa9e9474c
BLAKE2b-256 5729d5af2ed680f16e73ec25d517976e8e627831b2cebc13e4a84563f60dbce4

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page