Skip to main content

Dead-simple typed config loader for dataclasses (defaults + TOML + env) with great errors.

Project description

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)

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

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.

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