Skip to main content

Toml-combine

Deployed to PyPI Deployed to PyPI GitHub Repository Continuous Integration MIT License

toml-combine is a Python lib and CLI-tool that reads a TOML configuration file defining a default configuration alongside with overrides, and merges everything following rules you define to get final configurations. Let's say: you have multiple services, and environments, and you want to describe them all without repeating the parts that are common to everyone.

Concepts

The config file

The configuration file is (usually) a TOML file. Here's a small example:

[dimensions]
environment = ["production", "staging"]

[default]
name = "my-service"
registry = "gcr.io/my-project/"
container.image_name = "my-image"
container.port = 8080

[[override]]
when.environment = "production"
service_account = "my-production-service-account"

[[override]]
when.environment = "staging"
service_account = "my-staging-service-account"

Dimensions

Consider all the configurations you want to generate. Each one differs from the others. Dimensions lets you describe the main "thing" that makes the outputs differents, e.g.: environment might be staging or production, region might be eu or us, and service might be frontend or backend. Some combinations of dimensions might not exists, for example, maybe there's no staging in eu.

Default

The common configuration to start from, before we start overlaying overrides on top.

Overrides

Each override defines a set of condition where it applies (when.<dimension> = "<dimension_value>") and a set of overridden key/values.

[[override]]
# Keys starting with `when.` are "conditions"
when.environment = "staging"
when.region = "us"

# Other keys in an override are "overridden keys" / "overridden values"
service_account = "my-us-staging-service-account"

If you run toml-combine with a given mapping that selects multiple overrides, they will be checked for compatibility with one another, and an error will be raised if they're not compatible.

Compatibility rules:

  • If the two overrides don't share any overridden key, then they're always compatible.

    Example (click to expand)
    [dimensions]
    environment = ["staging"]
    region = ["eu"]
    
    [[override]]
    when.environment = "staging"
    service_account = "my-staging-service-account"
    
    [[override]]
    when.region = "eu"
    env.CURRENCY = "EUR"
    
  • If an override defines a set of conditions (say env=prod) and the other one defines strictly more conditions (say env=prod, region=eu, in other words, it defines all the conditions of the first override and then some more), then they're compatible. Also, in that case, the override with more conditions will have precedence.

    Example
    [dimensions]
    environment = ["staging"]
    region = ["eu"]
    
    [[override]]
    when.environment = "staging"
    service_account = "my-staging-service-account"
    
    [[override]]
    when.environment = "staging"
    when.region = "eu"
    service_account = "my-staging-eu-service-account"
    
  • If they both define a dimension that the other one doesn't, they're incompatible.

    Example (click to expand)

    Incompatible overrides: neither is a subset of the other one and they both define a value for service_account:

    [dimensions]
    environment = ["staging"]
    region = ["eu"]
    
    [default]
    service_account = "my-service-account"
    
    [[override]]
    when.environment = "staging"
    service_account = "my-staging-service-account"
    
    [[override]]
    when.region = "eu"
    service_account = "my-eu-service-account"
    
    $ toml-combine config.toml --environment=staging --region=eu
    Error: Incompatible overrides `{'region': ['eu']}` and `{'environment': ['staging']}`:
    When they're both applicable, overrides defining a common overridden key (foo) must be
    a subset of one another
    

The configuration itself

Under the layer of dimensions/default/override/mapping system, what you actually define in the configuration is completely up to you. That said, only nested "dictionnaries"/"objects"/"tables"/"mapping" (those are all the same things in Python/JS/Toml lingo) will be merged between the default and the applicable overrides, while arrays will just replace one another. See Arrays below.

Arrays

Let's look at an example:

[dimensions]
environment = ["production", "staging"]

[default]
fruits = [{name="apple", color="red"}]

[[override]]
when.environment = "staging"
fruits = [{name="orange", color="orange"}]

In this example, with {"environment": "staging"}, fruits is [{name="orange", color="orange"}] and not [{name="apple", color="red"}, {name="orange", color="orange"}]. The only way to get multiple values to be merged is if they are dicts: you'll need to chose an element to become the key:

[dimensions]
environment = ["production", "staging"]

[default]
fruits.apple.color = "red"

[[override]]
when.environment = "staging"
fruits.orange.color = "orange"

In this example, on staging, fruits is {apple={color="red"}, orange={color="orange"}}.

This example is simple because name is a natural choice for the key. In some cases, the choice is less natural, but you can always decide to name the elements of your list and use that name as a key. Also, yes, you'll loose ordering.

Mapping

When you call the tool either with the CLI or the lib (see both below), you will have to provide a mapping of the desired dimentions. These values will be compared to overrides to apply overrides when relevant. It's ok to omit some dimensions, corresponding overrides won't be selected.

By default, the output is toml though you can switch to json with --format=json

CLI

Example with the config from the previous section:

$ toml-combine path/to/config.toml --environment=staging
[fruits]
apple.color = "red"
orange.color = "orange"

Lib

import toml_combine


result = toml_combine.combine(config_file=config_file, environment="staging")

print(result)
{
  "fruits": {"apple": {"color": "red"}, "orange": {"color": "orange"}}
}

You can pass either config (TOML string or dict) or config_file (pathlib.Path or string path) to combine(). All other kwargs specify the mapping you want.

A bigger example

[dimensions]
environment = ["production", "staging", "dev"]
service = ["frontend", "backend"]

[default]
registry = "gcr.io/my-project/"
service_account = "my-service-account"

[[override]]
when.service = "frontend"
name = "service-frontend"
container.image_name = "my-image-frontend"

[[override]]
when.service = "backend"
name = "service-backend"
container.image_name = "my-image-backend"
container.port = 8080

[[override]]
when.service = "backend"
when.environment = "dev"
name = "service-dev"
container.env.DEBUG = true

[[override]]
when.environment = ["staging", "dev"]
when.service = "backend"
container.env.ENABLE_EXPENSIVE_MONITORING = false

This produces the following configs:

$ toml-combine example.toml --environment=production --service=frontend
registry = "gcr.io/my-project/"
service_account = "my-service-account"
name = "service-frontend"

[container]
image_name = "my-image-frontend"
$ toml-combine example.toml --environment=production --service=backend
registry = "gcr.io/my-project/"
service_account = "my-service-account"
name = "service-backend"

[container]
image_name = "my-image-backend"
port = 8080
$ toml-combine example.toml --environment=staging --service=frontend
registry = "gcr.io/my-project/"
service_account = "my-service-account"
name = "service-frontend"

[container]
image_name = "my-image-frontend"
$ toml-combine example.toml --environment=staging --service=backend
registry = "gcr.io/my-project/"
service_account = "my-service-account"
name = "service-backend"

[container]
image_name = "my-image-backend"
port = 8080

[container.env]
ENABLE_EXPENSIVE_MONITORING = false
$ toml-combine example.toml --environment=dev --service=backend
registry = "gcr.io/my-project/"
service_account = "my-service-account"
name = "service-backend"

[container]
image_name = "my-image-backend"
port = 8080
[container.env]
DEBUG = true
ENABLE_EXPENSIVE_MONITORING = false

Metadata

Release files for toml-combine 1.0.3

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for toml-combine 1.0.3
File Size Uploaded
toml_combine-1.0.3.tar.gz 19.6 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for toml-combine 1.0.3
File Interpreter ABI Platform
toml_combine-1.0.3-py3-none-any.whl Python 3 none any Details

Total release size: 30.4 kB

Release files / toml_combine-1.0.3.tar.gz

Download URL toml_combine-1.0.3.tar.gz
Size 19.6 kB
Tags Source
SHA-256 checksum
How to use checksums
17dfe0b0b81ac56497fd3ffba52122aaa9c1857a708d163d01d74c952e6dd84d
BLAKE2b-256 checksum
How to use checksums
9c3c5fd48ef07070a26784d3b374cbc04bdbf02403c68899c6a263ac8e13b766
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.12.9

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on May 28, 2025.

Transparency log

Release files / toml_combine-1.0.3-py3-none-any.whl

Download URL toml_combine-1.0.3-py3-none-any.whl
Size 10.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
a787cd69e033b365cb38b720cde8e9a4454028fb667128511210ef1f00d962b7
BLAKE2b-256 checksum
How to use checksums
65ca4f023db9fe7427f0344dc42ba542de0da96a127ef30a8484e0736941af49
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.12.9

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on May 28, 2025.

Transparency log

Release history Release notifications | RSS feed

This release

1.0.3 This release

2 release files

1.0.2

2 release files

1.0.1

2 release files

1.0.0

2 release files

0.6.0

2 release files

0.5.0

2 release files

0.4.0

2 release files

0.3.0

2 release files

0.2.0

2 release files

0.1.9

2 release files

0.1.7

2 release files

0.1.6

2 release files

0.1.5

2 release files

0.1.4

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page