# AlphaConf
[![PyPI version](https://badge.fury.io/py/alphaconf.svg)](https://pypi.org/project/alphaconf/)
A small library to ease writing parameterized scripts.
The goal is to execute a single script and be able to overwrite the parameters
easily.
The configuration is based on [OmegaConf].
Optionally, loading from toml or using [pydantic] is possible.
To run multiple related tasks, there is an integration with
[invoke](https://www.pyinvoke.org).
If you need something more complex, like running multiple instances of the
script, take a look at [hydra-core](https://hydra.cc) or use another script
to launch multiple instances.
## Demo and application
To run an application, you need...
```python
# myapp.py
import alphaconf
import logging
# define the default values and helpers
alphaconf.setup_configuration({
"server.url": "http://default",
}, {
"server.url": "The URL to show here",
})
def main():
log = logging.getLogger()
log.info('server.url:', alphaconf.get('server.url'))
log.info('has server.user:', alphaconf.get('server.user', bool, default=False))
if __name__ == '__main__':
alphaconf.cli.run(main)
```
Invoking:
```bash
python myapp.py server.url=http://github.com
```
During an *interactive session*, you can set the application in the current
context.
```python
# import other modules
import alphaconf.interactive
alphaconf.interactive.mount()
alphaconf.interactive.load_configuration_file('path')
```
Check the [DEMO](./demo.ipynb) for more examples.
## How the configuration is loaded
When running a program, first dotenv is used to load environment variables
from a `.env` file - this is optional.
Then configuration is built from:
- default configurations defined using (`alphaconf.setup_configuration`)
- `application` key is generated
- `PYTHON_ALPHACONF` environment variable may contain a path to load
- configuration files from configuration directories (using application name)
- environment variables based on key prefixes,
except "BASE" and "PYTHON"; \
if you have a configuration key "abc", all environment variables starting
with "ABC_" will be loaded, for example "ABC_HELLO=a" would set "abc.hello=a"
- key-values from the program arguments
Finally, the configuration is fully resolved and logging is configured.
## Configuration templates and resolvers
Configuration values are resolved by [OmegaConf].
Some of the resolvers (standard and custom):
- `${oc.env:USER,me}`: resolve the environment variable USER
with a default value "me"
- `${oc.select:config_path}`: resolve to another configuration value
- `${read_text:file_path}`: read text contents of a file as `str`
- `${read_bytes:file_path}`: read contents of a file as `bytes`
- `${read_strip:file_path}`: read text contents of a file as strip spaces
The *oc.select* is used to build multiple templates for configurations
by providing base configurations.
An argument `--select key=template` is a shortcut for
`key=${oc.select:base.key.template}`.
So, `logging: ${oc.select:base.logging.default}` resolves to the configuration
dict defined in base.logging.default and you can select it using
`--select logging=default`.
## Configuration values and integrations
### Typed-configuration
You can use [OmegaConf] with [pydantic] to *get* typed values.
```python
class MyConf(pydantic.BaseModel):
value: int = 0
def build(self):
# use as a factory pattern to create more complex objects
# for example, a connection to the database
return self.value * 2
# setup the configuration
alphaconf.setup_configuration(MyConf, prefix='a')
# read the value
alphaconf.get('a', MyConf)
v = alphaconf.get(MyConf) # because it's registered as a type
```
### Secrets
When showing the configuration, by default configuration keys which are
secrets, keys or passwords will be masked.
You can read values or passwords from files, by using the template
`${read_strip:/path_to_file}`
or, more securely, read the file in the code
`alphaconf.get('secret_file', Path).read_text().strip()`.
### Inject parameters
We can inject default values to functions from the configuration.
Either one by one, where we can map a factory function or a configuration key.
Or inject all automatically base on the parameter name.
```python
from alphaconf.inject import inject, inject_auto
@inject('name', 'application.name')
@inject_auto(ignore={'name'})
def main(name: str, example=None):
pass
# similar to
def main(name: str=None, example=None):
if name is None:
name = alphaconf.get('application.name', str)
if example is None:
example = alphaconf.get('example', default=example)
...
```
### Invoke integration
Just add the lines below to parameterize invoke.
Note that the argument parsing to overwrite configuration will work only
when the script is directly called.
```python
import alphaconf.invoke
ns = alphaconf.invoke.collection(globals())
alphaconf.setup_configuration({'backup': 'all'})
alphaconf.invoke.run(__name__, ns)
```
## Way to 1.0
- Run a specific function `alphaconf my.module.main`:
find functions and inject args
- Install completions for bash `alphaconf --install-autocompletion`
[OmegaConf]: https://omegaconf.readthedocs.io/
[pydantic]: https://docs.pydantic.dev/latest/
Raw data
{
"_id": null,
"home_page": "",
"name": "alphaconf",
"maintainer": "",
"docs_url": null,
"requires_python": ">=3.9",
"maintainer_email": "",
"keywords": "configuration,omegaconf,pydantic,script",
"author": "",
"author_email": "Krzysztof Magusiak <chrmag@poczta.onet.pl>",
"download_url": "https://files.pythonhosted.org/packages/65/63/4d4244599ef94fb1f7bf35f55d2304067f3b742315ec8ebd9d1a9ce577b8/alphaconf-0.5.0.tar.gz",
"platform": null,
"description": "# AlphaConf\n\n[![PyPI version](https://badge.fury.io/py/alphaconf.svg)](https://pypi.org/project/alphaconf/)\n\nA small library to ease writing parameterized scripts.\nThe goal is to execute a single script and be able to overwrite the parameters\neasily.\nThe configuration is based on [OmegaConf].\nOptionally, loading from toml or using [pydantic] is possible.\n\nTo run multiple related tasks, there is an integration with\n[invoke](https://www.pyinvoke.org).\nIf you need something more complex, like running multiple instances of the\nscript, take a look at [hydra-core](https://hydra.cc) or use another script\nto launch multiple instances.\n\n## Demo and application\n\nTo run an application, you need...\n\n```python\n# myapp.py\nimport alphaconf\nimport logging\n# define the default values and helpers\nalphaconf.setup_configuration({\n \"server.url\": \"http://default\",\n}, {\n \"server.url\": \"The URL to show here\",\n})\n\ndef main():\n log = logging.getLogger()\n log.info('server.url:', alphaconf.get('server.url'))\n log.info('has server.user:', alphaconf.get('server.user', bool, default=False))\n\nif __name__ == '__main__':\n alphaconf.cli.run(main)\n```\n\nInvoking:\n```bash\npython myapp.py server.url=http://github.com\n```\n\nDuring an *interactive session*, you can set the application in the current\ncontext.\n```python\n# import other modules\nimport alphaconf.interactive\nalphaconf.interactive.mount()\nalphaconf.interactive.load_configuration_file('path')\n```\n\nCheck the [DEMO](./demo.ipynb) for more examples.\n\n## How the configuration is loaded\n\nWhen running a program, first dotenv is used to load environment variables\nfrom a `.env` file - this is optional.\n\nThen configuration is built from:\n\n- default configurations defined using (`alphaconf.setup_configuration`)\n- `application` key is generated\n- `PYTHON_ALPHACONF` environment variable may contain a path to load\n- configuration files from configuration directories (using application name)\n- environment variables based on key prefixes,\n except \"BASE\" and \"PYTHON\"; \\\n if you have a configuration key \"abc\", all environment variables starting\n with \"ABC_\" will be loaded, for example \"ABC_HELLO=a\" would set \"abc.hello=a\"\n- key-values from the program arguments\n\nFinally, the configuration is fully resolved and logging is configured.\n\n## Configuration templates and resolvers\n\nConfiguration values are resolved by [OmegaConf].\nSome of the resolvers (standard and custom):\n- `${oc.env:USER,me}`: resolve the environment variable USER\n with a default value \"me\"\n- `${oc.select:config_path}`: resolve to another configuration value\n- `${read_text:file_path}`: read text contents of a file as `str`\n- `${read_bytes:file_path}`: read contents of a file as `bytes`\n- `${read_strip:file_path}`: read text contents of a file as strip spaces\n\nThe *oc.select* is used to build multiple templates for configurations\nby providing base configurations.\nAn argument `--select key=template` is a shortcut for\n`key=${oc.select:base.key.template}`.\nSo, `logging: ${oc.select:base.logging.default}` resolves to the configuration\ndict defined in base.logging.default and you can select it using\n`--select logging=default`.\n\n## Configuration values and integrations\n\n### Typed-configuration\n\nYou can use [OmegaConf] with [pydantic] to *get* typed values.\n```python\nclass MyConf(pydantic.BaseModel):\n value: int = 0\n\n def build(self):\n # use as a factory pattern to create more complex objects\n # for example, a connection to the database\n return self.value * 2\n\n# setup the configuration\nalphaconf.setup_configuration(MyConf, prefix='a')\n# read the value\nalphaconf.get('a', MyConf)\nv = alphaconf.get(MyConf) # because it's registered as a type\n```\n\n### Secrets\n\nWhen showing the configuration, by default configuration keys which are\nsecrets, keys or passwords will be masked.\nYou can read values or passwords from files, by using the template\n`${read_strip:/path_to_file}`\nor, more securely, read the file in the code\n`alphaconf.get('secret_file', Path).read_text().strip()`.\n\n### Inject parameters\n\nWe can inject default values to functions from the configuration.\nEither one by one, where we can map a factory function or a configuration key.\nOr inject all automatically base on the parameter name.\n\n```python\nfrom alphaconf.inject import inject, inject_auto\n\n@inject('name', 'application.name')\n@inject_auto(ignore={'name'})\ndef main(name: str, example=None):\n pass\n\n# similar to\ndef main(name: str=None, example=None):\n if name is None:\n name = alphaconf.get('application.name', str)\n if example is None:\n example = alphaconf.get('example', default=example)\n ...\n```\n\n### Invoke integration\n\nJust add the lines below to parameterize invoke.\nNote that the argument parsing to overwrite configuration will work only\nwhen the script is directly called.\n\n```python\nimport alphaconf.invoke\nns = alphaconf.invoke.collection(globals())\nalphaconf.setup_configuration({'backup': 'all'})\nalphaconf.invoke.run(__name__, ns)\n```\n\n## Way to 1.0\n- Run a specific function `alphaconf my.module.main`:\n find functions and inject args\n- Install completions for bash `alphaconf --install-autocompletion`\n\n[OmegaConf]: https://omegaconf.readthedocs.io/\n[pydantic]: https://docs.pydantic.dev/latest/\n",
"bugtrack_url": null,
"license": "BSD License",
"summary": "Write simple scripts leveraging omegaconf",
"version": "0.5.0",
"project_urls": {
"Homepage": "https://github.com/kmagusiak/alphaconf"
},
"split_keywords": [
"configuration",
"omegaconf",
"pydantic",
"script"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "ed56568a060f7a8da17a4cdbac3e291396ee13d422dd16e8de77a0cf1cbad1f1",
"md5": "5ee560f98648690fbe2517009f4d7938",
"sha256": "b61cc075ccfe07a7aaf22090d13cca5d546dfb571b47406d9e8809f0e45719b2"
},
"downloads": -1,
"filename": "alphaconf-0.5.0-py3-none-any.whl",
"has_sig": false,
"md5_digest": "5ee560f98648690fbe2517009f4d7938",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.9",
"size": 25047,
"upload_time": "2023-12-04T22:23:59",
"upload_time_iso_8601": "2023-12-04T22:23:59.377359Z",
"url": "https://files.pythonhosted.org/packages/ed/56/568a060f7a8da17a4cdbac3e291396ee13d422dd16e8de77a0cf1cbad1f1/alphaconf-0.5.0-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "65634d4244599ef94fb1f7bf35f55d2304067f3b742315ec8ebd9d1a9ce577b8",
"md5": "ffa8226ceb7db770eb405636f5e5e55c",
"sha256": "153b57289355601d34eb5569ed5031b711204524c5598cf071ed49e0c20e8ce9"
},
"downloads": -1,
"filename": "alphaconf-0.5.0.tar.gz",
"has_sig": false,
"md5_digest": "ffa8226ceb7db770eb405636f5e5e55c",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.9",
"size": 31552,
"upload_time": "2023-12-04T22:24:01",
"upload_time_iso_8601": "2023-12-04T22:24:01.380131Z",
"url": "https://files.pythonhosted.org/packages/65/63/4d4244599ef94fb1f7bf35f55d2304067f3b742315ec8ebd9d1a9ce577b8/alphaconf-0.5.0.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2023-12-04 22:24:01",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "kmagusiak",
"github_project": "alphaconf",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"requirements": [],
"lcname": "alphaconf"
}