Layered configuration loader merging env vars, files, and defaults.
Project description
philiprehberger-config-kit
Layered configuration loader merging env vars, files, and defaults.
Installation
pip install philiprehberger-config-kit
Usage
from philiprehberger_config_kit import Config
config = Config(
sources=[
Config.defaults({"port": 3000, "debug": False, "log_level": "info"}),
Config.json_file("config.json", optional=True),
Config.env_file(".env", optional=True),
Config.env(prefix="APP_"),
]
)
# Typed access
port = config.get_int("port")
debug = config.get_bool("debug")
db_url = config.get_str("database_url")
timeout = config.get_float("timeout", default=5.0)
hosts = config.get_list("allowed_hosts")
Dot-Notation Access
Retrieve nested values using dot-separated keys:
from philiprehberger_config_kit import Config
config = Config(
sources=[
Config.defaults({
"database": {"host": "localhost", "port": 5432},
"cache": {"redis": {"url": "redis://localhost"}},
}),
]
)
host = config.get("database.host") # "localhost"
port = config.get_int("database.port") # 5432
url = config.get_str("cache.redis.url") # "redis://localhost"
Source Priority
Sources are applied in order -- later sources override earlier ones:
from philiprehberger_config_kit import Config
config = Config(sources=[
Config.defaults({...}), # lowest priority
Config.json_file("..."), # overrides defaults
Config.env_file(".env"), # overrides JSON
Config.env(prefix="APP_"), # highest priority
])
Schema Validation
Define expected keys, types, and allowed values, then validate:
from philiprehberger_config_kit import Config, ConfigSchema, SchemaError
config = Config(sources=[
Config.defaults({"host": "localhost", "port": 5432, "mode": "dev"}),
])
schema = ConfigSchema()
schema.required("host", str)
schema.required("port", int)
schema.optional("debug", bool)
schema.required("mode", str, choices=["dev", "prod", "test"])
config.validate(schema) # raises SchemaError with all failures listed
Reload
Refresh configuration from all sources at runtime:
from philiprehberger_config_kit import Config
config = Config(sources=[Config.env(prefix="APP_")])
port = config.get("port")
# After environment changes...
config.reload()
port = config.get("port") # picks up the new value
Change Listeners
Get notified when a value changes after reload():
from philiprehberger_config_kit import Config
config = Config(sources=[Config.json_file("config.json")])
def log_change(key, old, new):
print(f"{key}: {old!r} -> {new!r}")
unsubscribe = config.on_change(log_change)
# Later, after the source file changes on disk:
config.reload()
# log_change is called once per dotted key whose value changed
unsubscribe() # stop listening
Export Methods
from philiprehberger_config_kit import Config
config = Config(sources=[
Config.defaults({"db": {"host": "localhost", "port": 5432}, "debug": True}),
])
# Deep copy as nested dict
data = config.to_dict()
# {"db": {"host": "localhost", "port": 5432}, "debug": True}
# Flat dict with dot-notation keys (string values)
flat = config.flatten()
# {"db.host": "localhost", "db.port": "5432", "debug": "True"}
# Environment variable format (UPPER_SNAKE_CASE, string values)
env = config.to_env(prefix="APP")
# {"APP_DB_HOST": "localhost", "APP_DB_PORT": "5432", "APP_DEBUG": "True"}
Config Snapshot Diffing
Capture config state and compare snapshots to see what changed:
from philiprehberger_config_kit import Config
config = Config(sources=[
Config.defaults({"host": "localhost", "port": 3000}),
Config.env(prefix="APP_"),
])
before = config.snapshot()
# ... environment changes, then reload ...
config.reload()
after = config.snapshot()
diff = before.diff(after)
# {"added": {...}, "removed": {...}, "changed": {"port": {"old": "3000", "new": "8080"}}}
Typed List Getters
Parse comma-separated values into typed lists:
from philiprehberger_config_kit import Config
config = Config(sources=[
Config.defaults({"ports": "8080,8081,8082", "rates": "1.5,2.0,3.7"}),
])
ports = config.get_int_list("ports") # [8080, 8081, 8082]
rates = config.get_float_list("rates") # [1.5, 2.0, 3.7]
# Custom separator
config2 = Config(sources=[Config.defaults({"ids": "1|2|3"})])
config2.get_int_list("ids", sep="|") # [1, 2, 3]
Environment Variables
With prefix="APP_", env vars are mapped:
APP_PORT->portAPP_DATABASE__HOST->database.host(double underscore = nested)
Bool Coercion
get_bool() accepts: true/false, 1/0, yes/no, on/off
In-Memory Dict Source
Layer programmatic overrides on top of file/env sources without writing to disk. Both flat and nested forms work:
from philiprehberger_config_kit import Config
config = Config([
Config.defaults({"port": 8080}),
Config.dict_source({"db": {"host": "x", "port": 5432}}), # nested
Config.json_file("config.json", optional=True), # overrides above
])
Runtime Mutations with set()
Config.set(key, value) updates a value at runtime and fires on_change listeners — only when the value actually changes.
config.on_change(lambda key, old, new: print(f"{key}: {old} -> {new}"))
config.set("db.host", "new-host")
# db.host: localhost -> new-host
config.set("db.host", "new-host") # same value, listener does NOT fire
API
| Function / Class | Description |
|---|---|
Config(sources) |
Layered configuration with typed access |
Config.dict_source(values) |
Create an in-memory dict source (flat or nested) |
Config.get(key, default) |
Get a value by key with dot-notation support |
Config.get_str(key, default) |
Get a string value |
Config.get_int(key, default) |
Get an integer value |
Config.get_float(key, default) |
Get a float value |
Config.get_bool(key, default) |
Get a boolean value with coercion |
Config.get_list(key, separator, default) |
Get a list by splitting a string value |
Config.get_int_list(key, sep) |
Split a string value and convert each element to int |
Config.get_float_list(key, sep) |
Split a string value and convert each element to float |
Config.require(*keys) |
Raise ConfigError if any keys are missing |
Config.has(key) |
Check if a key exists |
Config.set(key, value) |
Set a value at runtime; fires on_change listeners on real change |
Config.validate(schema) |
Validate config against a ConfigSchema |
Config.reload() |
Reload configuration from all sources |
Config.on_change(callback) |
Register (key, old, new) listener; returns unsubscribe |
Config.to_dict() |
Return a deep copy as a nested dictionary |
Config.to_env(prefix) |
Export as UPPER_SNAKE_CASE environment variable pairs |
Config.flatten(prefix) |
Export as flat dict with dot-notation keys |
Config.snapshot() |
Capture current state as a ConfigSnapshot |
Config.freeze() |
Freeze the config to prevent mutation |
ConfigSchema |
Define expected keys, types, required/optional, and choices |
ConfigSchema.required(key, type, choices) |
Add a required field to the schema |
ConfigSchema.optional(key, type, choices) |
Add an optional field to the schema |
ConfigSnapshot |
Immutable snapshot of config state |
ConfigSnapshot.diff(other) |
Compare two snapshots and return added/removed/changed keys |
ConfigError(missing) |
Raised when required config keys are missing |
SchemaError(errors) |
Raised when config values fail schema validation |
Development
pip install -e .
python -m pytest tests/ -v
Support
If you find this project useful:
License
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file philiprehberger_config_kit-0.5.0.tar.gz.
File metadata
- Download URL: philiprehberger_config_kit-0.5.0.tar.gz
- Upload date:
- Size: 15.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
764c19a45cf523e463d4c857be2b6b45705613f257d3347f2c405201fb3bdea5
|
|
| MD5 |
9ade5e99dfc1842fa2a421156092d743
|
|
| BLAKE2b-256 |
9a4b34ff55622f2b0bff98941dcd2bd0a9cb46d676b25a91ea60e3e5cc2c2b91
|
File details
Details for the file philiprehberger_config_kit-0.5.0-py3-none-any.whl.
File metadata
- Download URL: philiprehberger_config_kit-0.5.0-py3-none-any.whl
- Upload date:
- Size: 10.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6dce51964c018d7c7923062397743cbb05e352681a4ff52e2a23a3f85ce2a4dd
|
|
| MD5 |
9b97219f644a961ff748360a491d6c03
|
|
| BLAKE2b-256 |
dfe0eebb9273f597927fa80b0054cc3d1d914108da03ea8d7d216f315541c772
|