hydralette


Namehydralette JSON
Version 0.2.3 PyPI version JSON
download
home_pagehttps://github.com/ValeKnappich/hydralette
Summary
upload_time2024-02-08 15:26:18
maintainer
docs_urlNone
authorValeKnappich
requires_python>=3.10,<4.0
licenseMIT
keywords config cfg hydra
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            <div align="center" markdown="1">

# Hydralette

**Create complex configurations in a simple, pythonic way!**

[![python](https://img.shields.io/badge/-Python_3.8_%7C_3.9_%7C_3.10-blue?logo=python&logoColor=white)](https://github.com/pre-commit/pre-commit)
[![black](https://img.shields.io/badge/Code%20Style-Black-black.svg?labelColor=gray)](https://black.readthedocs.io/en/stable/)
[![isort](https://img.shields.io/badge/%20imports-isort-%231674b1?style=flat&labelColor=ef8336)](https://pycqa.github.io/isort/)
[![license](https://img.shields.io/badge/License-MIT-green.svg?labelColor=gray)](https://github.com/ashleve/lightning-hydra-template#license)

<a href="https://valeknappich.github.io/hydralette" style="font-size: 14pt">Documentation</a>

</div>

## Installation

```bash
pip install hydralette
# OR
poetry add hydralette
```

## Changelog

- v0.2.3
    - change version of `dill` dependency
- v0.2.2
    - support mixing _fields, _groups and _from_signature
    - support literal values as groups
    - add boolean flags as `--flag` or `--no-flag`
- v0.2.1
    - fix yaml representation
    - support setting value to None in automatic conversion
- v0.2.0
    - complete re-design --> breaking changes!
    - easier creation of hierarchical configs
- v0.1.5
    - Add yaml overrides
    - Add end-to-end tests with pytest
- v0.1.4
    - Add documentation at [https://valeknappich.github.io/hydralette](https://valeknappich.github.io/hydralette)
- v0.1.3
    - Add automatic generation of configs from signatures via `from_signature` and `config_from_signature`
- v0.1.2
    - Add support for `config groups`, `references`, `validation` and `type conversion`
    - Add CLI help pages


## Features

### Basics

Create a config using the `Config` class, passing the config fields as keyword arguments.

```python
from hydralette import Config
cfg = Config(a=1, b=2, c="abc")
```

`Config` objects can be create from and exported to `dict`s.

```python
from hydralette import Config
cfg = Config.from_dict({"a": 1, "b": 2, "c": "abc"})
print(cfg.to_dict())
```

Every hydralette `Config` be overriden via CLI:

```python
from hydralette import Config, Field
cfg = Config(
    a=Field(default=1, help="Lorem ipsum"),
    b=Config(
        c=Field(default=2, help="Lorem ipsum")
    )
)
cfg.apply(["--help"]) # or cfg.print_help()

# prints:

# Usage python script.py [OPTIONS]
# --a 1                   Lorem ipsum
# --b.c 1                 Lorem ipsum
```

After creation, you can override, resolve references, validate and check for missing required arguments.

```python
cfg.override(["--a", "1"]) # overrides defaults to sys.argv[1:]
cfg.resolve_references()
cfg.validate()
cfg.check_required_args()
# OR
cfg.apply(["--a", "1"]) # shorthand for the above
```


### Groups

Config groups can be very handy to make components interchangeable without requiring them to share a config.

```python
from hydralette import Config, Field
cfg = Config(
    model=Config(
        _groups={
            "_default": "rnn",
            "rnn": Config(
                n_layers=2,
                bidirectional=False
            ),
            "transformer": Config(
                n_layers=16,
                num_attention_heads=8
            )
        }
    )
)
cfg.apply(["--model", "transformer"])
```

### From signature / existing config

Often times, part of your configuration is already implemented somewhere else and duplicating this information creates a source of failure. Instead, you can automatically generate your hydralette `Config` based on an existing interface

```python

def calc(a: int, b=2):
    pass

from hydralette import Config, Field
cfg = Config(_from_signature=calc)
# equivalent to
cfg = Config(a=Field(type=int), b=Field(default=2, type=int))
```


### Fields

When you directly pass a value to `Config`s constructor, hydralette will create a `Field` under the hood. To use additional features, you can create it explicitly

`convert`: Specify how command-line overrides should be converted to the target type. If not explicitly specified, hydralette tries to use the field's `type` as conversion function (`type` is either explicitly specified or automatically derived from `default` / `default_factory`).

```python
import json
from hydralette import Config, Field
cfg = Config(my_dict=Field(default={"a": 1, "b": {"c": 2}}, convert=json.loads))
cfg.apply(['--my_dict', r'{"a": 2, "b": {"c": 3}}'])
```

`validate`: Constrain what values are valid for your field. If the validity of a value depends on the rest of the config, use `_validate` in the `Config` constructor instead.

```python
from hydralette import Config, Field
cfg = Config(n=Field(default=1, validate=lambda n: n > 0))
cfg.apply(['--n', '-1'])
# throws: ValidationError: Field validation failed for -1
cfg = Config(_validate=lambda cfg: cfg.a > cfg.b, a=1, b=2)
cfg.apply() # or cfg.validate()
# throws: ValidationError: Config validation failed for {'a': 1, 'b': 2}
```

`reference` / `reference_root`: Refer to any other value in the config

```python
from hydralette import Config, Field
from pathlib import Path
cfg = Config(
    dir=Path("outputs"),
    train=Config(
        checkpoint_dir=Field(reference_root=lambda cfg: cfg.dir / "checkpoints"), # relative to current config
        metrics_dir=Field(reference=lambda cfg: cfg.checkpoint_dir.parent / "metrics") # relative to root config
    )
)
cfg.resolve_references()
```





## Backlog

- [x] CLI
- [x] groups
- [x] from signatures
- [x] validation
- [x] conversion
- [x] references
- [x] yaml representation
- [x] pickle serialization
- [x] allow combining _groups, _fields and _from_signature
- [x] special support for boolean flags in CLI

## Dev Info

Steps on new release:

1. Run tests `pytest`
2. Edit docs
3. Increment version in `pyproject.toml`
4. Add changelog to `README.md`
5. Push increment to GitHub
6. Publish to PyPI `poetry publish --build`
7. Publish docs `mkdocs gh-deploy`
8. Create release and tag on GitHub
            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/ValeKnappich/hydralette",
    "name": "hydralette",
    "maintainer": "",
    "docs_url": null,
    "requires_python": ">=3.10,<4.0",
    "maintainer_email": "",
    "keywords": "config,cfg,hydra",
    "author": "ValeKnappich",
    "author_email": "",
    "download_url": "https://files.pythonhosted.org/packages/c4/b8/a9579ae185c4dc82952e92f27d33bbb9ad254421f7c21149fb257fb37c88/hydralette-0.2.3.tar.gz",
    "platform": null,
    "description": "<div align=\"center\" markdown=\"1\">\n\n# Hydralette\n\n**Create complex configurations in a simple, pythonic way!**\n\n[![python](https://img.shields.io/badge/-Python_3.8_%7C_3.9_%7C_3.10-blue?logo=python&logoColor=white)](https://github.com/pre-commit/pre-commit)\n[![black](https://img.shields.io/badge/Code%20Style-Black-black.svg?labelColor=gray)](https://black.readthedocs.io/en/stable/)\n[![isort](https://img.shields.io/badge/%20imports-isort-%231674b1?style=flat&labelColor=ef8336)](https://pycqa.github.io/isort/)\n[![license](https://img.shields.io/badge/License-MIT-green.svg?labelColor=gray)](https://github.com/ashleve/lightning-hydra-template#license)\n\n<a href=\"https://valeknappich.github.io/hydralette\" style=\"font-size: 14pt\">Documentation</a>\n\n</div>\n\n## Installation\n\n```bash\npip install hydralette\n# OR\npoetry add hydralette\n```\n\n## Changelog\n\n- v0.2.3\n    - change version of `dill` dependency\n- v0.2.2\n    - support mixing _fields, _groups and _from_signature\n    - support literal values as groups\n    - add boolean flags as `--flag` or `--no-flag`\n- v0.2.1\n    - fix yaml representation\n    - support setting value to None in automatic conversion\n- v0.2.0\n    - complete re-design --> breaking changes!\n    - easier creation of hierarchical configs\n- v0.1.5\n    - Add yaml overrides\n    - Add end-to-end tests with pytest\n- v0.1.4\n    - Add documentation at [https://valeknappich.github.io/hydralette](https://valeknappich.github.io/hydralette)\n- v0.1.3\n    - Add automatic generation of configs from signatures via `from_signature` and `config_from_signature`\n- v0.1.2\n    - Add support for `config groups`, `references`, `validation` and `type conversion`\n    - Add CLI help pages\n\n\n## Features\n\n### Basics\n\nCreate a config using the `Config` class, passing the config fields as keyword arguments.\n\n```python\nfrom hydralette import Config\ncfg = Config(a=1, b=2, c=\"abc\")\n```\n\n`Config` objects can be create from and exported to `dict`s.\n\n```python\nfrom hydralette import Config\ncfg = Config.from_dict({\"a\": 1, \"b\": 2, \"c\": \"abc\"})\nprint(cfg.to_dict())\n```\n\nEvery hydralette `Config` be overriden via CLI:\n\n```python\nfrom hydralette import Config, Field\ncfg = Config(\n    a=Field(default=1, help=\"Lorem ipsum\"),\n    b=Config(\n        c=Field(default=2, help=\"Lorem ipsum\")\n    )\n)\ncfg.apply([\"--help\"]) # or cfg.print_help()\n\n# prints:\n\n# Usage python script.py [OPTIONS]\n# --a 1                   Lorem ipsum\n# --b.c 1                 Lorem ipsum\n```\n\nAfter creation, you can override, resolve references, validate and check for missing required arguments.\n\n```python\ncfg.override([\"--a\", \"1\"]) # overrides defaults to sys.argv[1:]\ncfg.resolve_references()\ncfg.validate()\ncfg.check_required_args()\n# OR\ncfg.apply([\"--a\", \"1\"]) # shorthand for the above\n```\n\n\n### Groups\n\nConfig groups can be very handy to make components interchangeable without requiring them to share a config.\n\n```python\nfrom hydralette import Config, Field\ncfg = Config(\n    model=Config(\n        _groups={\n            \"_default\": \"rnn\",\n            \"rnn\": Config(\n                n_layers=2,\n                bidirectional=False\n            ),\n            \"transformer\": Config(\n                n_layers=16,\n                num_attention_heads=8\n            )\n        }\n    )\n)\ncfg.apply([\"--model\", \"transformer\"])\n```\n\n### From signature / existing config\n\nOften times, part of your configuration is already implemented somewhere else and duplicating this information creates a source of failure. Instead, you can automatically generate your hydralette `Config` based on an existing interface\n\n```python\n\ndef calc(a: int, b=2):\n    pass\n\nfrom hydralette import Config, Field\ncfg = Config(_from_signature=calc)\n# equivalent to\ncfg = Config(a=Field(type=int), b=Field(default=2, type=int))\n```\n\n\n### Fields\n\nWhen you directly pass a value to `Config`s constructor, hydralette will create a `Field` under the hood. To use additional features, you can create it explicitly\n\n`convert`: Specify how command-line overrides should be converted to the target type. If not explicitly specified, hydralette tries to use the field's `type` as conversion function (`type` is either explicitly specified or automatically derived from `default` / `default_factory`).\n\n```python\nimport json\nfrom hydralette import Config, Field\ncfg = Config(my_dict=Field(default={\"a\": 1, \"b\": {\"c\": 2}}, convert=json.loads))\ncfg.apply(['--my_dict', r'{\"a\": 2, \"b\": {\"c\": 3}}'])\n```\n\n`validate`: Constrain what values are valid for your field. If the validity of a value depends on the rest of the config, use `_validate` in the `Config` constructor instead.\n\n```python\nfrom hydralette import Config, Field\ncfg = Config(n=Field(default=1, validate=lambda n: n > 0))\ncfg.apply(['--n', '-1'])\n# throws: ValidationError: Field validation failed for -1\ncfg = Config(_validate=lambda cfg: cfg.a > cfg.b, a=1, b=2)\ncfg.apply() # or cfg.validate()\n# throws: ValidationError: Config validation failed for {'a': 1, 'b': 2}\n```\n\n`reference` / `reference_root`: Refer to any other value in the config\n\n```python\nfrom hydralette import Config, Field\nfrom pathlib import Path\ncfg = Config(\n    dir=Path(\"outputs\"),\n    train=Config(\n        checkpoint_dir=Field(reference_root=lambda cfg: cfg.dir / \"checkpoints\"), # relative to current config\n        metrics_dir=Field(reference=lambda cfg: cfg.checkpoint_dir.parent / \"metrics\") # relative to root config\n    )\n)\ncfg.resolve_references()\n```\n\n\n\n\n\n## Backlog\n\n- [x] CLI\n- [x] groups\n- [x] from signatures\n- [x] validation\n- [x] conversion\n- [x] references\n- [x] yaml representation\n- [x] pickle serialization\n- [x] allow combining _groups, _fields and _from_signature\n- [x] special support for boolean flags in CLI\n\n## Dev Info\n\nSteps on new release:\n\n1. Run tests `pytest`\n2. Edit docs\n3. Increment version in `pyproject.toml`\n4. Add changelog to `README.md`\n5. Push increment to GitHub\n6. Publish to PyPI `poetry publish --build`\n7. Publish docs `mkdocs gh-deploy`\n8. Create release and tag on GitHub",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "",
    "version": "0.2.3",
    "project_urls": {
        "Homepage": "https://github.com/ValeKnappich/hydralette",
        "Repository": "https://github.com/ValeKnappich/hydralette"
    },
    "split_keywords": [
        "config",
        "cfg",
        "hydra"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "c39d6b4a8965574b169d7a3d52cc8045924dc2e7d698836be2a3e5fbb157241d",
                "md5": "4b87edf884ee2c5d3ac738fdb3a1e6fb",
                "sha256": "4d708ea0c8bbbb5724d1ddd8b726479766ab2f6d5d459865b7d4d3c61beddc37"
            },
            "downloads": -1,
            "filename": "hydralette-0.2.3-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "4b87edf884ee2c5d3ac738fdb3a1e6fb",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.10,<4.0",
            "size": 9631,
            "upload_time": "2024-02-08T15:26:17",
            "upload_time_iso_8601": "2024-02-08T15:26:17.686765Z",
            "url": "https://files.pythonhosted.org/packages/c3/9d/6b4a8965574b169d7a3d52cc8045924dc2e7d698836be2a3e5fbb157241d/hydralette-0.2.3-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "c4b8a9579ae185c4dc82952e92f27d33bbb9ad254421f7c21149fb257fb37c88",
                "md5": "2b5ab3adcb42f9544d6607ab625b83b7",
                "sha256": "ec5b3eb87a1a8c5c71b055b2b8de016176f67f1cdd5d51e1381ad00010f1f02f"
            },
            "downloads": -1,
            "filename": "hydralette-0.2.3.tar.gz",
            "has_sig": false,
            "md5_digest": "2b5ab3adcb42f9544d6607ab625b83b7",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.10,<4.0",
            "size": 8407,
            "upload_time": "2024-02-08T15:26:18",
            "upload_time_iso_8601": "2024-02-08T15:26:18.905182Z",
            "url": "https://files.pythonhosted.org/packages/c4/b8/a9579ae185c4dc82952e92f27d33bbb9ad254421f7c21149fb257fb37c88/hydralette-0.2.3.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-02-08 15:26:18",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "ValeKnappich",
    "github_project": "hydralette",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": false,
    "lcname": "hydralette"
}
        
Elapsed time: 0.30699s