Confit is a complete and easy-to-use configuration framework aimed at improving the reproducibility of experiments by relying on the Python typing system, minimal configuration files and command line interfaces.
Install the library with pip:
pip install confit
Confit only abstracts the boilerplate code related to configuration and leaves the rest of your code unchanged.
Here is an example:
+ from confit import Cli, Registry, RegistryCollection
+ class registry(RegistryCollection):
+ factory = Registry(("test_cli", "factory"), entry_points=True)
+ @registry.factory.register("submodel")
class SubModel:
# Type hinting is optional but recommended !
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 = Cli(pretty_exceptions_show_locals=False)
# you can use @confit.validate_arguments instead if you don't plan on using the CLI
+ @app.command(name="script", registry=registry)
def func(modelA: BigModel, modelB: BigModel, seed: int = 42):
assert modelA.submodel is modelB.submodel
print("modelA.date:", modelA.date.strftime("%B %-d, %Y"))
print("modelB.date:", modelB.date.strftime("%B %-d, %Y"))
+ if __name__ == "__main__":
+ app()
Create a new config file
The following also works with YAML files
# CLI sections
[script]
modelA = ${modelA}
modelB = ${modelB}
# CLI common parameters
[modelA]
@factory = "bigmodel"
date = "2003-02-01"
[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 43
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)
func(
# BigModel will cast date strings as datetime.date objects
modelA=BigModel(date="2003-02-01", submodel=submodel),
# Since the modelB argument was typed, the dict is cast as a BigModel instance
modelB=dict(date="2003-04-05", submodel=submodel),
seed=seed,
)
modelA.date: February 1, 2003
modelB.date: April 5, 2003
You can also serialize registered classes, while keeping references between instances:
from confit import Config
submodel = SubModel(value=12)
modelA = BigModel(date="2003-02-01", submodel=submodel)
modelB = BigModel(date="2003-02-01", submodel=submodel)
print(Config({"modelA": modelA, "modelB": modelB}).to_str())
[modelA]
@factory = "bigmodel"
date = "2003-02-01"
[modelA.submodel]
@factory = "submodel"
value = 12
[modelB]
@factory = "bigmodel"
date = "2003-02-01"
submodel = ${modelA.submodel}
You also benefit from informative validation errors:
func(
modelA=dict(date="hello", submodel=dict(value=3)),
modelB=dict(date="2010-10-05", submodel=dict(value="hi")),
)
ConfitValidationError: 2 validation errors for __main__.func()
-> modelA.date
invalid date format, got 'hello' (str)
-> modelB.submodel.value
value is not a valid float, got 'hi' (str)
Visit the documentation for more information!
We would like to thank Assistance Publique – Hôpitaux de Paris and AP-HP Foundation for funding this project.