Getting Started
April 11, 2026 ยท View on GitHub
Installation
pip install molcrafts-molcfg
The PyPI distribution name is molcrafts-molcfg; the import name is molcfg.
For local development:
pip install -e ".[dev]"
pip install -e ".[docs]"
First Config
from molcfg import Config
cfg = Config({"app": {"name": "demo", "debug": False}})
# attribute access
assert cfg.app.name == "demo"
# dotted-path access
assert cfg["app.name"] == "demo"
# containment check
assert "app.debug" in cfg
Mutating a Config
cfg.app.name = "updated"
cfg["app.debug"] = True
Nested dicts are automatically wrapped into child Config objects.
Freezing and rollback
cfg.freeze()
# cfg.app.name = "x" # raises FrozenConfigError
cfg.unfreeze()
cfg.snapshot()
cfg.app.name = "temporary"
cfg.rollback()
assert cfg.app.name == "updated"
Layered loading
Later sources win using DEEP_MERGE by default:
from molcfg import CliSource, ConfigLoader, DictSource, EnvSource
cfg = ConfigLoader([
DictSource({"db": {"host": "localhost", "port": 5432}}, name="defaults"),
EnvSource(prefix="APP", name="env"),
CliSource(["--db.port=6432"], name="cli"),
]).load()
assert cfg["db.port"] == 6432
Source tracking
info = cfg.meta("db.port")
# {"source": "cli", "history": ("defaults", "cli")}
source is the last writer. history lists every source that touched the key, in order.
Serialization
d = cfg.to_dict()
s = cfg.to_json()
s = cfg.to_json(indent=2)
Change callbacks
def on_change(path: str, new_value, old_value) -> None:
print(f"{path}: {old_value!r} -> {new_value!r}")
cfg.on_change(on_change)
cfg.app.name = "watched"
# app.name: 'demo' -> 'watched'