Metadata-Version: 2.1
Name: confit
Version: 0.7.3
Summary: Smart configuration framework
Author-email: Perceval Wajsburt <perceval.wajsburt@aphp.fr>, Thomas Petit-Jean <thomas.petitjean@aphp.fr>, Adam Remaki <adam.remaki@aphp.fr>, Alice Calliger <alice.calliger@aphp.fr>
License: Copyright 2023 Assistance Publique - Hôpitaux de Paris
        
        Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
        
        1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
        
        2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
        
        3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
        
        THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
        
Requires-Python: <4.0,>=3.7.1
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: catalogue<3.0,>=2.0.7
Requires-Dist: lark<2.0,>=1.1.5
Requires-Dist: pydantic<3.0,>=1.2
Requires-Dist: typer<1.0,>=0.6.1
Requires-Dist: pydantic-core>=0.20
Requires-Dist: PyYAML
Provides-Extra: dev
Requires-Dist: coverage<8.0,>=7.0; extra == "dev"
Requires-Dist: mike<2.0,>=1.1.2; extra == "dev"
Requires-Dist: mkdocs<2.0,>=1.4; extra == "dev"
Requires-Dist: mkdocs-autorefs<1.0.0,>=0.4.1; extra == "dev"
Requires-Dist: mkdocs-bibtex<3.0,>=2.0.3; extra == "dev"
Requires-Dist: mkdocs-glightbox<1.0.0,>=0.1.6; extra == "dev"
Requires-Dist: mkdocs-material<9.0,>=8.2; extra == "dev"
Requires-Dist: mkdocs-material-extensions<2.0.0,>=1.1.1; extra == "dev"
Requires-Dist: mkdocs-static-i18n<1.0.0,>=0.53; extra == "dev"
Requires-Dist: mkdocstrings<1.0.0,>=0.18.1; extra == "dev"
Requires-Dist: mkdocstrings-python<2.0.0,>=0.6; extra == "dev"
Requires-Dist: pre-commit<3.0,>=2.18.1; extra == "dev"
Requires-Dist: pytest<8.0,>=7.1.1; extra == "dev"
Requires-Dist: pytest-cov<5.0,>=4.0.0; extra == "dev"
Requires-Dist: rich; extra == "dev"
Requires-Dist: torch; extra == "dev"
Requires-Dist: numpy; extra == "dev"

![Tests](https://img.shields.io/github/actions/workflow/status/aphp/confit/tests.yml?branch=main&label=tests&style=flat-square)
[![Documentation](https://img.shields.io/github/actions/workflow/status/aphp/confit/documentation.yml?branch=main&label=docs&style=flat-square)](https://aphp.github.io/confit/latest/)
[![PyPI](https://img.shields.io/pypi/v/confit?color=blue&style=flat-square)](https://pypi.org/project/confit/)
[![Coverage](https://raw.githubusercontent.com/aphp/confit/coverage/coverage.svg)](https://raw.githubusercontent.com/aphp/confit/coverage/coverage.txt)


# Confit

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.

## Getting started

Install the library with pip:

<div class="termy">

```bash
pip install confit
```

</div>

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

Here is an example:

<h5 a><strong><code>script.py</code></strong></h5>

```diff
+ 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

<h5 a><strong><code>config.cfg</code></strong></h5>

```ini
# 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

<div class="termy">

```bash
python script.py --config config.cfg --seed 43
```

</div>

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

```python
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
```

#### Serialization

You can also serialize registered classes, while keeping references between instances:

```python
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())
```

```ini
[modelA]
@factory = "bigmodel"
date = "2003-02-01"

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

[modelB]
@factory = "bigmodel"
date = "2003-02-01"
submodel = ${modelA.submodel}
```

#### Error handling

You also benefit from informative validation errors:

```python
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](https://aphp.github.io/confit/) for more information!

## Acknowledgement

We would like to thank [Assistance Publique – Hôpitaux de Paris](https://www.aphp.fr/)
and [AP-HP Foundation](https://fondationrechercheaphp.fr/) for funding this project.
