Skip to content

Merge

merge()

merge(base, override, strategy) merges two plain dicts and returns a new one. Neither input is mutated.

from molcfg import MergeStrategy, merge

base = {"db": {"host": "localhost", "port": 5432}, "debug": False}
override = {"db": {"port": 6432}}

result = merge(base, override, MergeStrategy.DEEP_MERGE)
assert result == {"db": {"host": "localhost", "port": 6432}, "debug": False}

Strategies

DEEP_MERGE (default)

Recursively merges nested dicts. Scalar values in override replace those in base.

base     = {"db": {"host": "a", "port": 5432}}
override = {"db": {"port": 6432}}
# result  = {"db": {"host": "a", "port": 6432}}

OVERRIDE

Discards base entirely and returns a deep copy of override.

base     = {"db": {"host": "a", "port": 5432}, "debug": True}
override = {"db": {"port": 6432}}
# result  = {"db": {"port": 6432}}

APPEND

Like DEEP_MERGE for dicts, but concatenates lists instead of replacing them.

base     = {"tags": ["web", "api"]}
override = {"tags": ["internal"]}
# result  = {"tags": ["web", "api", "internal"]}

ConfigLoader

ConfigLoader applies merge incrementally across an ordered list of sources. Later sources override earlier ones.

from molcfg import CliSource, ConfigLoader, DictSource, EnvSource, MergeStrategy

cfg = ConfigLoader(
    [
        DictSource({"db": {"host": "localhost", "port": 5432}}, name="defaults"),
        EnvSource(prefix="APP", name="env"),
        CliSource(["--db.port=6432"], name="cli"),
    ],
    strategy=MergeStrategy.DEEP_MERGE,
).load()

The resulting Config object carries full source metadata. cfg.meta("db.port") returns the last writer and the complete history.

ProfileLoader

ProfileLoader adds named profile overlays on top of a base set of sources.

from molcfg import DictSource, ProfileLoader, TomlFileSource

loader = ProfileLoader(
    base_sources=[
        DictSource({"db": {"host": "localhost", "port": 5432}}, name="defaults"),
        TomlFileSource("config.toml", name="file"),
    ],
    profiles={
        "prod": DictSource({"db": {"host": "prod-db.internal"}}, name="profile:prod"),
        "staging": DictSource({"db": {"host": "staging-db.internal"}}, name="profile:staging"),
    },
)

cfg = loader.load(profile="prod")
assert cfg["db.host"] == "prod-db.internal"
assert cfg["db.port"] == 5432  # from defaults

Call loader.load() without a profile to get the base config only.