Skip to content

Getting started

Installation

Install the library with pip:

pip install confit

A simple example

Confit only abstracts the boilerplate code related to configuration and leaves the rest of your code unchanged.

Here is an example:

script.py
import datetime
+ from confit import Cli, Registry, RegistryCollection

+ app = Cli(pretty_exceptions_show_locals=False)

+ class RegistryCollection(:
+     factory = Registry(("test_cli", "factory"), entry_points=True)

+ @registry.factory.register("submodel")
class SubModel:
    # Type hinting is optional but recommended to benefit for argument casting !
    def __init__(self, value: float, desc: str = ""):
        self.value = value
        self.desc = desc


+ @registry.factory.register("bigmodel")
class BigModel:
    def __init__(self, date: datetime.date, submodel: SubModel):
        self.date = date
        self.submodel = submodel


+ @app.command(name="script", registry=registry)
def func(modelA: BigModel, modelB: BigModel, other: int, seed: int):
    """
    Run the configured models.

    Parameters
    ----------
    modelA : BigModel
        The first model.
    modelB : BigModel
        The second model.
    other : int
        Value printed by the command.
    seed : int
        Random seed.
    """
    assert modelA.submodel is modelB.submodel
    assert modelA.date == datetime.date(2010, 10, 10)
    print("Other:", other)

+ if __name__ == "__main__":
+     app()

Create a new config file

config.cfg
# CLI sections
[script]
modelA = ${modelA}
modelB = ${modelB}

# CLI common parameters
[modelA]
@factory = "bigmodel"
date = "2010-10-10"

[modelA.submodel]
@factory = "submodel"
value = 12

[modelB]
date = "2003-04-05"
submodel = ${modelA.submodel}

and run the following command from the terminal

python script.py --config config.cfg --seed 42
config.yaml
script:
  modelA: ${modelA}
  modelB: ${modelB}

modelA:
  "@factory": "bigmodel"
  date: "2010-10-10"

  submodel:
    "@factory": "submodel"
    value: 12

modelB:
  date: "2003-04-05"
  submodel: ${modelA.submodel}

and run the following command from the terminal

python script.py --config config.yaml --seed 42

Naming

To use the name of your config path (e.g. config-expe-2 if the configuration file is named config-expe-2.cfg in the configuration (after resolution), simply mention name = None under the section which title was provided at @app.command(name=<section-title>)

Multiple configurations

You can pass multiple configuration files by repeating the --config option. Configuration will be merged in order.

The same command also exposes a readable help message, including --config, typed parameters and nested field overrides:

python script.py --help
Run the configured models.

Parameters
----------
  --config <Path>
    Load a config file to fill in the following params. Can be repeated.

  --modelA <BigModel>
    The first model.

    --modelA.<field> VALUE

  --modelB <BigModel>
    The second model.

    --modelB.<field> VALUE

  --other <int>
    Value printed by the command.

  --seed <int>
    Random seed.

You can still call the function method from your code, but now also benefit from argument validation !

from script import func, BigModel, SubModel

# To seed before creating the models
from confit.utils.random import set_seed

seed = 42
set_seed(seed)

submodel = SubModel(value=12)
# BigModel will cast date strings as datetime.date objects
modelA = BigModel(date="2003-02-01", submodel=submodel)
modelB = BigModel(date="2003-04-05", submodel=submodel)
func(
    modelA=modelA,
    modelB=modelA,
    seed=seed,
)

Subcommands

Compose Confit applications with add_subcommands:

from confit import Cli

app = Cli()
training = Cli()


@training.command(name="run")
def run(epochs: int = 10):
    print(f"Training for {epochs} epochs")


app.add_subcommands(training, name="training", help="Training commands")

The command accepts the same configuration and override arguments as a top-level Confit command:

python script.py training run --config config.yml --epochs 20

Omit name to expose the child commands directly on the parent. Configuration sections continue to use the leaf command name, such as run in this example.

Validation errors

Confit adds configuration and component paths to validation errors. Use ConfitValidationError to preserve that context when validating nested objects.

from confit.errors import ConfitValidationError
from pydantic import TypeAdapter, ValidationError

try:
    TypeAdapter(int).validate_python("invalid")
except ValidationError as exc:
    error = ConfitValidationError.from_exception(exc, name="Encoder")
    error = error.with_path(("components", "encoder", "width"))
    print(error)

Catch ConfitValidationError for validation failures. Use with_path to add context without changing the original error, combine to collect failures, and errors() to access structured details.