config.merge
Call config1.merge(config2) to combine configuration using Atmos's deep-merge engine. Nested objects merge recursively, and values from the right-hand configuration take precedence.
Usage
base = config.validate({
"database": {"host": "localhost", "port": 5432},
"tags": ["base"],
}, schema={
"database": {"host": str, "port": int},
"tags": schema.list(str),
})
overrides = config.validate({
"database": {"host": "prod-db"},
"tags": ["prod"],
}, schema={
"database": {"host": str},
"tags": schema.list(str),
})
cfg = base.merge(overrides)
print(cfg.database.host) # prod-db
print(cfg.database.port) # 5432
print(cfg.tags) # ["prod"]
Records returned by config.load and
config.validate expose this method, including nested records.
The right-hand value can also be a dictionary:
cfg = base.merge({"database": {"host": "prod-db"}})
Arguments
config1.merge(other, list_merge_strategy="replace")
| Argument | Description |
|---|---|
other | Required config record or string-keyed dictionary, positional or keyword. |
list_merge_strategy | Keyword-only: "replace" (default), "append", or "merge". Applies recursively to lists. |
The receiver is a config record, not the predeclared config module. To begin with a plain dictionary, first
validate it with config.validate.
Merge rules
- Objects merge recursively, preserving keys that occur only on the left.
- Other right-hand values replace left-hand values, including type changes,
None,False,0, and empty strings. - With
"replace", the right-hand list replaces the whole left-hand list, including when it is empty. - With
"append", list items are concatenated left then right; duplicates are retained. - With
"merge", lists merge by index using Atmos's existing list-merge behavior: object pairs merge recursively, overlapping scalar or mismatched elements keep the left-hand value, and unmatched tail elements from either side are retained. This is not a set union or a merge by an object's name/ID.
cfg = base.merge({"tags": ["prod"]}, list_merge_strategy="append")
print(cfg.tags) # ["base", "prod"]
Neither input is mutated or frozen by the merge. The result is a new, deeply frozen config record with dot and index access and JSON encoding. Integers retain arbitrary precision, and floats retain their type. Calls can be chained, used in loaded functions, or run concurrently in parallel tasks.
The merge attribute is reserved for this method. A data field named merge remains accessible with
cfg["merge"] and is preserved in JSON. dir(cfg) includes the method; key iteration, membership, len,
dict(cfg), and JSON output include only data fields.
Validate the combined result
Merging combines data, not schema definitions. It does not reapply either input's schema or rerun file/network loads. To enforce a schema on the combined configuration, validate the result explicitly:
cfg = config.validate(base.merge(overrides), schema={
"database": {"host": str, "port": int},
"tags": schema.list(str),
})
Defaults already inserted in the right-hand configuration participate like any other value. To merge partial overrides, give those overrides a schema that describes only their supplied fields, or pass a dictionary. Errors from validation of merged data report field paths; the merged record does not retain file source locations.
Related
config.loadloads YAML/JSON with inline, local-file, or HTTPS schemas.config.validatevalidates existing data without changing it.schemadefines inline types and field rules.