Skip to main content

Spring-like deep merge configuration loader for Python

Project description

🌱 SprigConfig

Latest Version

SprigConfig is a lightweight, opinionated configuration system for Python applications. It provides layered YAML loading, profile overlays, environment variable expansion, recursive imports, safe secret handling, and detailed metadata tracking designed for clarity, reproducibility, and debuggability.

This updated README reflects the current, expanded architecture of SprigConfig — including its test infrastructure, .env handling model, and secret‑management APIs.


⭐ Key Features

✔️ Profile Injection (Runtime-Driven)

Profiles are never taken from files. The active profile comes from:

  1. load_config(profile=...)
  2. APP_PROFILE
  3. pytest"test"
  4. Otherwise → "dev"

Injected into final config as:

app:
  profile: <active>

If a YAML file contains app.profile, it is ignored with a warning.


✔️ Layered YAML Merging (Deep Merge)

SprigConfig merges:

  1. application.yml
  2. application-<profile>.yml
  3. imports: [file1.yml, file2.yml, …]

Features include:

  • Recursive dictionary merging
  • Override collision warnings
  • Partial merge clarity
  • Preservation of source metadata

✔️ Environment Variable Expansion

Patterns:

${VAR}
${VAR:default}

Expanded at load time. Missing variables fall back to defaults.


✔️ Secure Secret Handling

Values formatted as:

ENC(<ciphertext>)

are mapped to LazySecret objects.

  • Decryption is lazy (on .get())
  • Uses global Fernet key via APP_SECRET_KEY
  • Supports global key providers
  • Secrets redacted during dumps unless explicitly allowed

✔️ Import Chains

Inside any YAML file:

imports:
  - features.yml
  - security.yml

SprigConfig resolves imports relative to APP_CONFIG_DIR or the config root and detects circular imports.


✔️ Metadata Injection

Every loaded config includes:

sprigconfig._meta:
  profile: <active>
  sources: [list of resolved files]
  import_trace: <graph of import relationships>

This helps debugging and auditing.


✔️ BOM-Safe YAML Reads

UTF‑8 with BOM (utf-8-sig) is automatically sanitized so Windows-created files don’t introduce odd keys like server.


📦 Installation

pip install sprig-config
# or
poetry add sprig-config

📁 Project Structure

sprigconfig/
    config_loader.py
    config.py
    lazy_secret.py
    deepmerge.py
    exceptions.py
    ...

docs/
    README_AI_Info.md
    (future docs go here)

tests/
    conftest.py
    conftest.md
    test_*.py
    test_*.md
    config/

Documentation Strategy

  • docs/ → Project-wide documentation (AI disclosure, architecture notes)
  • tests/ → Each test module has matching .md explaining its purpose
  • conftest.md → Documentation for the test framework itself

This ensures the entire system is self-explaining.


📂 Configuration Layout Example

config/
  application.yml
  application-dev.yml
  application-test.yml
  application-prod.yml
  features.yml
  override.yml

application.yml

server:
  port: 8080
logging:
  level: INFO

application-dev.yml

server:
  port: 9090
imports:
  - features.yml
  - override.yml

override.yml

server:
  port: 9999
features:
  auth:
    methods: ["password", "oauth"]

⚙️ Runtime Selection & Profile Behavior

SprigConfig determines profile → merges → injects profile → processes imports.

from sprigconfig import load_config

cfg = load_config(profile="dev")
print(cfg["server"]["port"])  # 9999
print(cfg["app"]["profile"])  # dev

🔐 Secret Handling with LazySecret

secrets:
  db_user: ENC(gAAAAA...)
  db_pass: ENC(gAAAAA...)
val = cfg["secrets"]["db_pass"]
assert isinstance(val, LazySecret)
print(val.get())  # plaintext

LazySecrets are:

  • Safe by default
  • Not decrypted unless .get() is called
  • Redacted in dumps

📜 .env Resolution Model

SprigConfig supports configuration directory override via:

  1. load_config(config_dir=...)
  2. APP_CONFIG_DIR
  3. .env in the project root
  4. Test overrides (--env-path)
  5. Default: ./config

.env example:

APP_CONFIG_DIR=/opt/myapp/config
APP_SECRET_KEY=AbCdEf123...

🧪 Test Suite Overview

SprigConfig has a documented, extensible test architecture.

Test categories:

  • Config mechanics
  • Metadata & import tracing
  • Deep merge
  • Profile overlay behavior
  • LazySecret & crypto handling
  • CLI serialization tests
  • Integration tests with full directory copies

Documentation-per-test:

Every test module includes a paired .md file explaining its purpose and architecture.


🧰 Test CLI Flags (from conftest.py)

Flag Purpose
--env-path Use a custom .env file during tests
--dump-config Print merged config for debugging
`--dump-config-format yaml json`
--dump-config-secrets Resolve LazySecrets
--dump-config-no-redact Show plaintext secrets
--debug-dump=file.yml Write merged config snapshot
RUN_CRYPTO=true Enable crypto-heavy tests

These make the test suite extremely reproducible and transparent.


🛡️ Production Guardrails

When profile = prod:

  • Missing logging.level → default to INFO
  • logging.level: DEBUG blocked unless
    allow_debug_in_prod: true
    
  • Missing application-prod.yml → error
  • Missing application-test.yml (when test) → error

🔗 Programmatic Access

from pathlib import Path
from sprigconfig import ConfigLoader

loader = ConfigLoader(config_dir=Path("config"), profile="dev")
cfg = loader.load()

print(cfg.get("server.port"))
print(cfg.to_dict())

🧭 Migration Notes

  • Remove app.profile from YAML files; runtime decides profile
  • Use imports for modularizing config trees
  • Secrets should always be stored as encrypted ENC(...) values

Versioning

SprigConfig follows Semantic Versioning:

  • MAJOR versions introduce breaking changes
  • MINOR versions add backward-compatible functionality
  • PATCH versions contain backward-compatible bug fixes

Pre-release versions (e.g. -rc1) indicate a release candidate. They are feature-complete but may receive final fixes before a stable release and are not recommended for production use unless explicitly intended for testing.

📚 Additional Documentation

Developer-focused documentation is available under the docs/ directory:

These documents cover contributor workflows, test mechanics, Git usage, CI/release processes, and internal design notes.

📄 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

sprig_config-1.2.3.tar.gz (31.6 kB view details)

Uploaded Source

Built Distribution

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

sprig_config-1.2.3-py3-none-any.whl (38.2 kB view details)

Uploaded Python 3

File details

Details for the file sprig_config-1.2.3.tar.gz.

File metadata

  • Download URL: sprig_config-1.2.3.tar.gz
  • Upload date:
  • Size: 31.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.6

File hashes

Hashes for sprig_config-1.2.3.tar.gz
Algorithm Hash digest
SHA256 4b083f2304da9287a761202782f60e9dba5e1f35a7eaecb16975a82b7c8fd8e2
MD5 dc83b5ef5a7cde4e2aab587eb664b660
BLAKE2b-256 48a56aef2669cb176960cebdb3f85cc01310a7fb1bc5a2c29139eb9e59ec1471

See more details on using hashes here.

File details

Details for the file sprig_config-1.2.3-py3-none-any.whl.

File metadata

  • Download URL: sprig_config-1.2.3-py3-none-any.whl
  • Upload date:
  • Size: 38.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.6

File hashes

Hashes for sprig_config-1.2.3-py3-none-any.whl
Algorithm Hash digest
SHA256 c2a533e1863a515c1537665d5914ae6d45c1c32b431d046e58a7e0ac52c254a7
MD5 e0280414552f0a69e2d51b3b973ab3c5
BLAKE2b-256 07028cb2a66211a3744b94dfe4083801a0a32b65b7be204921a89b1eaee4de67

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