Skip to main content

saneconfig

CI Docs PyPI

Dead-simple typed config loader for dataclasses:

  • defaults
  • TOML file(s)
  • environment variables

with great errors and provenance ("where did this value come from?").

Python 3.11+.

Core package has zero runtime dependencies; optional extras:

  • saneconfig[dotenv] for .env file support.

Install

pip install saneconfig
# optional .env support
pip install "saneconfig[dotenv]"

Quick start

from dataclasses import dataclass
from saneconfig import load, REQUIRED


@dataclass
class AppConfig:
    debug: bool = False
    port: int = 8080
    database_url: str = REQUIRED


cfg = load(
    AppConfig,
    env_prefix="APP",
    files=["config.toml", "config.local.toml"],
)

print(cfg.port)

Precedence (highest wins)

  1. CLI args (argv=True or argv=[...])
  2. Environment variables
  3. .env file values (when dotenv is enabled)
  4. TOML files (later overrides earlier)
  5. Dataclass defaults

TOML example

debug = true
port = 9000
database_url = "postgresql://user:pass@localhost:5432/mydb"

Nested dataclasses map to TOML tables:

[db]
host = "localhost"
port = 5432

Env var mapping

With env_prefix="APP":

  • APP_PORT=9000 -> port
  • APP_DEBUG=true -> debug
  • nested via __: APP_DB__HOST=localhost -> db.host

Booleans accept: true/false, yes/no, on/off, 1/0 (case-insensitive).

Lists in env vars use JSON:

APP_ALLOWED='["a","b"]'

CLI overrides

Enable CLI parsing by passing argv=True (uses sys.argv[1:]) or provide a list explicitly:

cfg = load(
    AppConfig,
    env_prefix="APP",
    argv=["--port=9001", "--db.host=db.internal"],
)

Supported form: --key=value with dotted nesting (--db.host=x).

Provenance / debugging

cfg, report = load(
    AppConfig,
    env_prefix="APP",
    files=["config.toml", "config.local.toml"],
    return_report=True,
)

print(report)

Example output:

database_url='postgresql://...' (env:APP_DATABASE_URL)
debug=False (default)
port=9000 (file:config.toml)

Schema docs

You can include richer docs using dataclass metadata:

from dataclasses import dataclass, field

@dataclass
class AppConfig:
    port: int = field(default=8080, metadata={"help": "HTTP listen port"})
from saneconfig import dump_schema
print(dump_schema(AppConfig, env_prefix="APP"))

dump_schema(...) includes a Help column using field(metadata={"help": ...}).

Errors that help

If a value cannot be converted:

ConfigError: port expected int but got "eighty"
  source: env:APP_PORT
  hint: Use a valid int value.

If required values are missing:

ConfigError: missing required configuration values:
  - database_url

Supported types (v0.1)

  • str, int, float, bool
  • Optional[T]
  • list[T] (TOML arrays or JSON arrays in env)
  • Literal[...]
  • nested dataclasses
  • pathlib.Path
  • dict[str, T] (TOML table or JSON object in env)

Non-goals (by design)

  • profiles/composition systems
  • interpolation DSLs
  • frameworks and global state

MIT Licensed.


A tiny example you can run

from dataclasses import dataclass
from typing import Literal, Optional

from saneconfig import REQUIRED, load


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


@dataclass
class App:
    mode: Literal["dev", "prod"] = "dev"
    debug: bool = False
    port: int = 8080
    api_key: str = REQUIRED
    db: DB = DB()
    notes: Optional[str] = None


cfg, report = load(App, env_prefix="APP", files=["config.toml"], return_report=True)
print(cfg)
print(report)

Download files

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

Source Distribution

saneconfig-0.1.0.tar.gz (14.3 kB view details)

Uploaded Source

Built Distribution

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

saneconfig-0.1.0-py3-none-any.whl (10.9 kB view details)

Uploaded Python 3

File details

Details for the file saneconfig-0.1.0.tar.gz.

File metadata

  • Download URL: saneconfig-0.1.0.tar.gz
  • Upload date:
  • Size: 14.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.3

File hashes

Hashes for saneconfig-0.1.0.tar.gz
Algorithm Hash digest
SHA256 7ef26073be5317f419e9f865a08a55ff610bc6b2df1118ff1322c31bd77d4bcf
MD5 ee874db798465e770c37a8cd88747e07
BLAKE2b-256 d60f8c11ce6099d45eeccc93d98f6945197436008f4ca93279e0b93b128cee8a

See more details on using hashes here.

File details

Details for the file saneconfig-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: saneconfig-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 10.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.3

File hashes

Hashes for saneconfig-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 d7a00796a800c1c94fd91116e10044ce68a057701ec2d5361ad6474fcdbc56a6
MD5 1d4404b394ec6ef4e0b997b3a0b54d76
BLAKE2b-256 44eef23d0c0f75375f9e10fb9fc60b78170349f90705ea225235c992b6fc70ca

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 files

Supported by

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