configzen


Nameconfigzen JSON
Version 0.10.0 PyPI version JSON
download
home_pagehttps://github.com/bswck/configzen
SummaryThe easiest way to manage configuration files in Python
upload_time2023-08-23 21:12:51
maintainer
docs_urlNone
authorbswck
requires_python>=3.8,<4.0
licenseMIT
keywords
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # configzen `v0.10.0`

_configzen_ – easily create and maintain complex, statically-typed configurations with validation in Python.

It's important to keep your configuration safe and consistent. Give a shot to _configzen_ 🚀

⭐ Supports **Python 3.8 or above**,<br>
⭐ Is **fully typed**,<br>
⭐ Supports **YAML, JSON, TOML, INI, XML, ConfigObj, BSON, CBOR, Amazon Ion, properties** and **shellvars**,<br>
⭐ Supports **reading and writing configuration files**, fully or partially, with the ability to preserve the original file structure (without comments[^1]),<br>
⭐ Supports **configuration preprocessing** (extending, including and copying configuration files without the need to change the code),<br>
⭐ Supports **variable interpolation** (runtime value substitution),<br>
⭐ Supports **modular configuration with type validation** (wrapping runtime Python modules in-place and outside them),<br>
⭐ Supports **synchronous and asynchronous file operations**,<br>
⭐ Supports loading configuration from **environment variables and secret files**.<br>

While being built on top of [pydantic](https://docs.pydantic.dev/1.10/), _configzen_ inherits most of its features, including
[data validation](https://docs.pydantic.dev/1.10/usage/validators/), [schema generation](https://docs.pydantic.dev/1.10/usage/schema/),
[custom data types](https://docs.pydantic.dev/1.10/usage/types/#arbitrary-types-allowed), good integration with [Rich](https://docs.pydantic.dev/1.10/usage/rich/), and more.

Learn more below.

## Features

### Managing content

Having a YAML configuration file like this:

```yaml
# database.yml
host: 127.0.0.1
port: 5432
user: postgres
```

You can create a _configzen_ configuration model for it like this:

```python
# model.py
from ipaddress import IPv4Address, IPv6Address

from configzen import ConfigField, ConfigMeta, ConfigModel


class DatabaseConfig(ConfigModel):
    host: IPv4Address | IPv6Address
    port: int
    user: str
    password: str = ConfigField(exclude=True)

    class Config(ConfigMeta):
        resource = "database.yml"
        env_prefix = "DB_"


db_config = DatabaseConfig.load()
```

And you can load your configuration from a file as well as from the environment variables
`DB_HOST`, `DB_PORT`, `DB_USER` and `DB_PASSWORD`. Since `password` is a field created with
the option `exclude=True`, it will not be included in the configuration's exported data: that
guarantees that your password does never leak into `database.yml` on save – but you may still pass it
through an environment variable (here – the mentioned `DB_PASSWORD`). Secret files are also supported,
see [the pydantic documentation](https://docs.pydantic.dev/latest/usage/settings/#secret-support)
for more information.

[pydantic](https://docs.pydantic.dev/latest/) will naturally take care of parsing and validating the loaded data.
Configuration models inherit from the `pydantic.BaseSettings` class, so you can use all of its features:
schema generation, type conversion, validation, etc.

There are additional features brought to you by _configzen_ worth checking out, though.

You can use the `db_config` object defined above to access the configuration values:

```python
>>> db_config.host
IPv4Address('127.0.0.1')
```

modify them, if the pydantic model validation allows
it ([`<Your model>.Config.validate_assignment`](https://docs.pydantic.dev/latest/usage/model_config/#options) will
be `True` by default):

```python
>>> db_config.host = "0.0.0.0"
>>> db_config.host
IPv4Address('0.0.0.0')
```

as well as reload particular values, without touching the rest of the configuration:

```python
>>> db_config.at("port").reload()
5432
>>> db_config
DatabaseConfig(host=IPv4Address('0.0.0.0'), port=5432, user='postgres', password='password')
>>> db_config.at("host").reload()
IPv4Address('127.0.0.1')
>>> db_config
DatabaseConfig(host=IPv4Address('127.0.0.1'), port=5432, user='postgres', password='password')
```

or reload the whole configuration:

```python
>>> db_config.port = 1234
>>> db_config.reload()
DatabaseConfig(host=IPv4Address('127.0.0.1'), port=5432, user='postgres', password='password')
```

or save a particular value, without touching the rest of the configuration:

```python
>>> db_config.host = "0.0.0.0"
>>> db_config.port = 443
>>> db_config
DatabaseConfig(host=IPv4Address('0.0.0.0'), port=443, user='postgres', password='password')
>>> db_config.at("host").save()
40
>>> db_config.reload()
DatabaseConfig(host=IPv4Address('0.0.0.0'), port=5432, user='postgres', password='password')
```

or save the whole configuration:

```python
>>> db_config.save()
39
```

### Preprocessing

To see supported preprocessing directives,
see [Supported preprocessing directives](#supported-preprocessing-directives).

#### Basic usage

Having a base configuration file like this (`base.json`):

```json
{
  "i18n": {
    "language": "en",
    "timezone": "UTC"
  },
  "app": {
    "debug": true,
    "expose": 8000
  }
}
```

create another configuration file like this, overriding desired sections as needed:

```yaml
# production.yml
^extend: base.json

+app:
  debug: false
```

and load the `production.yml` configuration file. No explicit changes to the code indicating the use of the `base.json`
file are needed.

_Note: Using `+` in front of a key will update the section already defined at that key,
instead of overwriting it entirely._

Notice how configuration file formats do not matter in _configzen_: you can
extend JSON configurations with YAML, but that might be as well any other format
among the supported ones (see the [Supported file formats](#supported-file-formats) section).

The above example is equivalent to as if you used:

```yaml
# production.yml
i18n:
  language: en
  timezone: UTC
app:
  debug: false
  expose: 8000
```

but with a significant difference: when you save the above configuration, the `^extend` relation to the base
configuration file `base.json` is preserved.
This basically means that changes made in the base configuration file will apply to the configuration model instance
loaded from the `^extend`-ing configuration file.
Any changes made locally to the model will result in `+` sections being automatically added to the exported
configuration data.

#### Supported preprocessing directives

| Directive  | Is the referenced file preprocessed? | Is the directive preserved on export? |
| ---------- | ------------------------------------ | ------------------------------------- |
| `^extend`  | Yes                                  | Yes                                   |
| `^include` | Yes                                  | No                                    |
| `^copy`    | No                                   | No                                    |


### Interpolation

#### Basic interpolation

You can use interpolation in your configuration files:

```yaml
cpu:
  cores: 4
num_workers: ${cpu.cores}
```

```python
>>> from configzen import ConfigModel
...
>>> class CPUConfig(ConfigModel):
...     cores: int
...
>>> class AppConfig(ConfigModel):
...     cpu: CPUConfig
...     num_workers: int
...
>>> app_config = AppConfig.load("app.yml")
>>> app_config
AppConfig(cpu=CPUConfig(cores=4), num_workers=4)
```


#### Reusable configuration with namespaces

You can share independent configuration models as namespaces through inclusion:

```yaml
# database.yml
host: ${app_config::db_host}
port: ${app_config::expose}
```

```yaml
# app.yml
db_host: localhost
expose: 8000
```

```python
>>> from configzen import ConfigModel, include
>>> from ipaddress import IPv4Address
>>>
>>> @include("app_config")
... class DatabaseConfig(ConfigModel):
...     host: IPv4Address
...     port: int
...
>>> class AppConfig(ConfigModel):
...     db_host: str
...     expose: int
...
>>> app_config = AppConfig.load("app.yml")
>>> app_config
AppConfig(db_host='localhost', expose=8000)
>>> db_config = DatabaseConfig.load("database.yml")
>>> db_config
DatabaseConfig(host=IPv4Address('127.0.0.1'), port=8000)
>>> db_config.dict()
{'host': IPv4Address('127.0.0.1'), 'port': 8000}
>>> db_config.export()  # used when saving
{'host': '${app_config::db_host}', 'port': '${app_config::expose}'}
```

You do not have to pass a variable name to `@include`, though. `@include` lets you overwrite the main interpolation namespace
or one with a separate name (here: `app_config`) with configuration models, dictionaries and their factories.


### Modular configuration

#### Wrapping modules in-place

You can wrap modules in-place with configuration models:


1) Without writing a model class:

```python
# config.py
from configzen import ConfigModule

# Annotate config fields
HOST: str = "localhost"
PORT: int = 8000

ConfigModule.wrap_this_module()
```

2) With a model class:

```python
# config.py
from configzen import ConfigModel

# Annotations are optional
HOST = "localhost"
PORT = 8000

class AppConfig(ConfigModel):
    HOST: str
    PORT: int

AppConfig.wrap_this_module()
```

Now values `HOST` and `PORT` will be validated as `str` and `int` data types, respectively:

```python
>>> import config  # <configuration module 'config' from 'config.py'>
>>> config.HOST
'localhost'
>>> config.PORT
8000
>>> config.PORT = "8000"
>>> config.PORT
8000
>>> config.PORT = "abc"
Traceback (most recent call last):
  ...
```

#### Wrapping interchangeable modules

You can wrap modules outside them with configuration models:

```python
# setup.py
from configzen import ConfigModel

class AppConfig(ConfigModel):
    HOST: str = "localhost"
    PORT: int = 8000

config_model = AppConfig.wrap_module("config")
```

```py
# config.py
HOST: str = "0.0.0.0"
PORT: int = 443
```

```python
>>> from setup import config_model
>>> config_model.HOST
'0.0.0.0'
>>> config_model.PORT
443
>>> config_model.PORT = "8000"
>>> config_model.PORT
8000
>>> import config
>>> config.HOST
'0.0.0.0'
>>> config.PORT
8000
```

## Supported file formats

_configzen_ uses [anyconfig](https://pypi.org/project/anyconfig/) to serialize and deserialize data and does not operate on any protocol-specific entities.
As an example result, comments in your configuration files are lost on save[^1], but you can exchange file formats without any hassle.

The following table shows the supported file formats, their requirements, file extensions, and the backend libraries used to accomplish this goal.

| File Format                                                                         | To use, install:              | Recognized File Extension(s) | Backend Library                                                                                       |
| ----------------------------------------------------------------------------------- | ----------------------------- | ---------------------------- | ----------------------------------------------------------------------------------------------------- |
| [JSON](https://en.wikipedia.org/wiki/JSON)                                          | -                             | `json`                       | [json](https://docs.python.org/3/library/json.html) (standard library)                                |
| [INI](https://en.wikipedia.org/wiki/INI_file)                                       | -                             | `ini`, `cfg`, `conf`         | [configparser](https://docs.python.org/3/library/configparser.html) (standard library)                |
| [TOML](https://en.wikipedia.org/wiki/TOML)                                          | -                             | `toml`                       | [toml](https://pypi.python.org/pypi/toml)                                                             |
| [YAML](https://yaml.org)                                                            | -                             | `yaml`, `yml`                | [pyyaml](https://pypi.python.org/pypi/PyYAML) / [ruamel.yaml](https://pypi.python.org/pypi/ruamel.yaml) |
| [XML](https://en.wikipedia.org/wiki/XML)                                            | -                             | `xml`                        | [xml](https://docs.python.org/3/library/xml.html) (standard library)                                  |
| [ConfigObj](https://configobj.readthedocs.io/en/latest/configobj.html#introduction) | `anyconfig-configobj-backend` | `configobj`                  | [configobj](https://pypi.org/project/configobj/)                                              |
| [BSON](https://en.wikipedia.org/wiki/BSON)                                          | `anyconfig-bson-backend`      | `bson`                       | [bson](https://pypi.org/project/bson/)                                                                |
| [CBOR](https://cbor.io/) ([RFC 8949](https://www.rfc-editor.org/rfc/rfc8949))       | `anyconfig-cbor2-backend`     | `cbor`, `cbor2`              | [cbor2](https://pypi.org/project/cbor2/)                                                              |
| [Amazon Ion](https://en.wikipedia.org/wiki/Ion_(serialization_format))              | `anyconfig-ion-backend`       | `ion`                        | [ion](https://pypi.org/project/amazon.ion/)                                                           |
| CBOR (deprecated, [RFC 7049](https://www.rfc-editor.org/rfc/rfc7049))               | `anyconfig-cbor-backend`      | `cbor`                       | [cbor](https://pypi.org/project/cbor/)                                                                |
| properties                                                                          | -                             | `properties`                 | (native)                                                                                              |
| shellvars                                                                           | -                             | `shellvars`                  | (native)                                                                                              |
<!-- Add msgpack when it works -->
If your file extension is not recognized, you can register your own file extension by calling `ConfigAgent.register_file_extension(file_extension, parser_name)`.

If your favorite backend library is not supported, please let me know by reporting it as an issue.
Using custom backends is to be supported in the future.

[^1]: A suggested alternative for comments is to use the `description` parameter in your configuration models' fields: `ConfigField(description=...)`.
The provided field descriptions are included in JSON schemas generated by the default implementation of the `ConfigModel.schema()` method.

## Setup

In order to use _configzen_ in your project, install it with your package manager, for example `pip`:

```bash
pip install configzen
```

If you are willing to contribute to _configzen_, which is awesome, simply clone this repository and install its
dependencies with [poetry](https://python-poetry.org/):

```bash
poetry install --with dev --all-extras
```
After that, install the [pre-commit](https://pre-commit.com/) hooks:

```bash
pre-commit install --hook-type pre-commit --hook-type pre-push
```

You might also need to install required stubs. First, activate your virtual environment:

```bash
poetry shell
```

and run (on Linux or [PowerShell](https://learn.microsoft.com/en-us/powershell/scripting/overview?view=powershell-7.3) 7.0+):

```bash
mypy configzen/ || (echo yes | mypy --install-types)
```

or, if you are using an older version of PowerShell:

```powershell
mypy configzen/; if (-not $?) { echo yes | mypy --install-types }
```

_Note: Using [WSL2](https://learn.microsoft.com/en-us/windows/wsl/install) + [pyenv](https://github.com/pyenv/pyenv#readme) (with Python 3.8) for developing configzen is strongly recommended in case you use Windows._

And you are good to go. 🚀

Contributions are welcome! Feel free to [open an issue](https://github.com/bswck/configzen/issues/new/choose) whenever
you encounter a bug or have a feature request or [submit a pull request](https://github.com/bswck/configzen/compare) with your changes.

## License

[MIT License](https://choosealicense.com/licenses/mit/)


## Credits

* [@Lunarmagpie](https://github.com/Lunarmagpie) for _crucial_ design tips and ideas.

## Author

* [bswck](https://github.com/bswck) (contact: bswck.dev@gmail.com or via [Discord](https://discord.com/) `bswck`)


            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/bswck/configzen",
    "name": "configzen",
    "maintainer": "",
    "docs_url": null,
    "requires_python": ">=3.8,<4.0",
    "maintainer_email": "",
    "keywords": "",
    "author": "bswck",
    "author_email": "bswck.dev@gmail.com",
    "download_url": "https://files.pythonhosted.org/packages/71/85/08835a39768c2c60cdef84659b213394f6f7e91bd05ba4c9cf626365a001/configzen-0.10.0.tar.gz",
    "platform": null,
    "description": "# configzen `v0.10.0`\n\n_configzen_ \u2013 easily create and maintain complex, statically-typed configurations with validation in Python.\n\nIt's important to keep your configuration safe and consistent. Give a shot to _configzen_ \ud83d\ude80\n\n\u2b50 Supports **Python 3.8 or above**,<br>\n\u2b50 Is **fully typed**,<br>\n\u2b50 Supports **YAML, JSON, TOML, INI, XML, ConfigObj, BSON, CBOR, Amazon Ion, properties** and **shellvars**,<br>\n\u2b50 Supports **reading and writing configuration files**, fully or partially, with the ability to preserve the original file structure (without comments[^1]),<br>\n\u2b50 Supports **configuration preprocessing** (extending, including and copying configuration files without the need to change the code),<br>\n\u2b50 Supports **variable interpolation** (runtime value substitution),<br>\n\u2b50 Supports **modular configuration with type validation** (wrapping runtime Python modules in-place and outside them),<br>\n\u2b50 Supports **synchronous and asynchronous file operations**,<br>\n\u2b50 Supports loading configuration from **environment variables and secret files**.<br>\n\nWhile being built on top of [pydantic](https://docs.pydantic.dev/1.10/), _configzen_ inherits most of its features, including\n[data validation](https://docs.pydantic.dev/1.10/usage/validators/), [schema generation](https://docs.pydantic.dev/1.10/usage/schema/),\n[custom data types](https://docs.pydantic.dev/1.10/usage/types/#arbitrary-types-allowed), good integration with [Rich](https://docs.pydantic.dev/1.10/usage/rich/), and more.\n\nLearn more below.\n\n## Features\n\n### Managing content\n\nHaving a YAML configuration file like this:\n\n```yaml\n# database.yml\nhost: 127.0.0.1\nport: 5432\nuser: postgres\n```\n\nYou can create a _configzen_ configuration model for it like this:\n\n```python\n# model.py\nfrom ipaddress import IPv4Address, IPv6Address\n\nfrom configzen import ConfigField, ConfigMeta, ConfigModel\n\n\nclass DatabaseConfig(ConfigModel):\n    host: IPv4Address | IPv6Address\n    port: int\n    user: str\n    password: str = ConfigField(exclude=True)\n\n    class Config(ConfigMeta):\n        resource = \"database.yml\"\n        env_prefix = \"DB_\"\n\n\ndb_config = DatabaseConfig.load()\n```\n\nAnd you can load your configuration from a file as well as from the environment variables\n`DB_HOST`, `DB_PORT`, `DB_USER` and `DB_PASSWORD`. Since `password` is a field created with\nthe option `exclude=True`, it will not be included in the configuration's exported data: that\nguarantees that your password does never leak into `database.yml` on save \u2013 but you may still pass it\nthrough an environment variable (here \u2013 the mentioned `DB_PASSWORD`). Secret files are also supported,\nsee [the pydantic documentation](https://docs.pydantic.dev/latest/usage/settings/#secret-support)\nfor more information.\n\n[pydantic](https://docs.pydantic.dev/latest/) will naturally take care of parsing and validating the loaded data.\nConfiguration models inherit from the `pydantic.BaseSettings` class, so you can use all of its features:\nschema generation, type conversion, validation, etc.\n\nThere are additional features brought to you by _configzen_ worth checking out, though.\n\nYou can use the `db_config` object defined above to access the configuration values:\n\n```python\n>>> db_config.host\nIPv4Address('127.0.0.1')\n```\n\nmodify them, if the pydantic model validation allows\nit ([`<Your model>.Config.validate_assignment`](https://docs.pydantic.dev/latest/usage/model_config/#options) will\nbe `True` by default):\n\n```python\n>>> db_config.host = \"0.0.0.0\"\n>>> db_config.host\nIPv4Address('0.0.0.0')\n```\n\nas well as reload particular values, without touching the rest of the configuration:\n\n```python\n>>> db_config.at(\"port\").reload()\n5432\n>>> db_config\nDatabaseConfig(host=IPv4Address('0.0.0.0'), port=5432, user='postgres', password='password')\n>>> db_config.at(\"host\").reload()\nIPv4Address('127.0.0.1')\n>>> db_config\nDatabaseConfig(host=IPv4Address('127.0.0.1'), port=5432, user='postgres', password='password')\n```\n\nor reload the whole configuration:\n\n```python\n>>> db_config.port = 1234\n>>> db_config.reload()\nDatabaseConfig(host=IPv4Address('127.0.0.1'), port=5432, user='postgres', password='password')\n```\n\nor save a particular value, without touching the rest of the configuration:\n\n```python\n>>> db_config.host = \"0.0.0.0\"\n>>> db_config.port = 443\n>>> db_config\nDatabaseConfig(host=IPv4Address('0.0.0.0'), port=443, user='postgres', password='password')\n>>> db_config.at(\"host\").save()\n40\n>>> db_config.reload()\nDatabaseConfig(host=IPv4Address('0.0.0.0'), port=5432, user='postgres', password='password')\n```\n\nor save the whole configuration:\n\n```python\n>>> db_config.save()\n39\n```\n\n### Preprocessing\n\nTo see supported preprocessing directives,\nsee [Supported preprocessing directives](#supported-preprocessing-directives).\n\n#### Basic usage\n\nHaving a base configuration file like this (`base.json`):\n\n```json\n{\n  \"i18n\": {\n    \"language\": \"en\",\n    \"timezone\": \"UTC\"\n  },\n  \"app\": {\n    \"debug\": true,\n    \"expose\": 8000\n  }\n}\n```\n\ncreate another configuration file like this, overriding desired sections as needed:\n\n```yaml\n# production.yml\n^extend: base.json\n\n+app:\n  debug: false\n```\n\nand load the `production.yml` configuration file. No explicit changes to the code indicating the use of the `base.json`\nfile are needed.\n\n_Note: Using `+` in front of a key will update the section already defined at that key,\ninstead of overwriting it entirely._\n\nNotice how configuration file formats do not matter in _configzen_: you can\nextend JSON configurations with YAML, but that might be as well any other format\namong the supported ones (see the [Supported file formats](#supported-file-formats) section).\n\nThe above example is equivalent to as if you used:\n\n```yaml\n# production.yml\ni18n:\n  language: en\n  timezone: UTC\napp:\n  debug: false\n  expose: 8000\n```\n\nbut with a significant difference: when you save the above configuration, the `^extend` relation to the base\nconfiguration file `base.json` is preserved.\nThis basically means that changes made in the base configuration file will apply to the configuration model instance\nloaded from the `^extend`-ing configuration file.\nAny changes made locally to the model will result in `+` sections being automatically added to the exported\nconfiguration data.\n\n#### Supported preprocessing directives\n\n| Directive  | Is the referenced file preprocessed? | Is the directive preserved on export? |\n| ---------- | ------------------------------------ | ------------------------------------- |\n| `^extend`  | Yes                                  | Yes                                   |\n| `^include` | Yes                                  | No                                    |\n| `^copy`    | No                                   | No                                    |\n\n\n### Interpolation\n\n#### Basic interpolation\n\nYou can use interpolation in your configuration files:\n\n```yaml\ncpu:\n  cores: 4\nnum_workers: ${cpu.cores}\n```\n\n```python\n>>> from configzen import ConfigModel\n...\n>>> class CPUConfig(ConfigModel):\n...     cores: int\n...\n>>> class AppConfig(ConfigModel):\n...     cpu: CPUConfig\n...     num_workers: int\n...\n>>> app_config = AppConfig.load(\"app.yml\")\n>>> app_config\nAppConfig(cpu=CPUConfig(cores=4), num_workers=4)\n```\n\n\n#### Reusable configuration with namespaces\n\nYou can share independent configuration models as namespaces through inclusion:\n\n```yaml\n# database.yml\nhost: ${app_config::db_host}\nport: ${app_config::expose}\n```\n\n```yaml\n# app.yml\ndb_host: localhost\nexpose: 8000\n```\n\n```python\n>>> from configzen import ConfigModel, include\n>>> from ipaddress import IPv4Address\n>>>\n>>> @include(\"app_config\")\n... class DatabaseConfig(ConfigModel):\n...     host: IPv4Address\n...     port: int\n...\n>>> class AppConfig(ConfigModel):\n...     db_host: str\n...     expose: int\n...\n>>> app_config = AppConfig.load(\"app.yml\")\n>>> app_config\nAppConfig(db_host='localhost', expose=8000)\n>>> db_config = DatabaseConfig.load(\"database.yml\")\n>>> db_config\nDatabaseConfig(host=IPv4Address('127.0.0.1'), port=8000)\n>>> db_config.dict()\n{'host': IPv4Address('127.0.0.1'), 'port': 8000}\n>>> db_config.export()  # used when saving\n{'host': '${app_config::db_host}', 'port': '${app_config::expose}'}\n```\n\nYou do not have to pass a variable name to `@include`, though. `@include` lets you overwrite the main interpolation namespace\nor one with a separate name (here: `app_config`) with configuration models, dictionaries and their factories.\n\n\n### Modular configuration\n\n#### Wrapping modules in-place\n\nYou can wrap modules in-place with configuration models:\n\n\n1) Without writing a model class:\n\n```python\n# config.py\nfrom configzen import ConfigModule\n\n# Annotate config fields\nHOST: str = \"localhost\"\nPORT: int = 8000\n\nConfigModule.wrap_this_module()\n```\n\n2) With a model class:\n\n```python\n# config.py\nfrom configzen import ConfigModel\n\n# Annotations are optional\nHOST = \"localhost\"\nPORT = 8000\n\nclass AppConfig(ConfigModel):\n    HOST: str\n    PORT: int\n\nAppConfig.wrap_this_module()\n```\n\nNow values `HOST` and `PORT` will be validated as `str` and `int` data types, respectively:\n\n```python\n>>> import config  # <configuration module 'config' from 'config.py'>\n>>> config.HOST\n'localhost'\n>>> config.PORT\n8000\n>>> config.PORT = \"8000\"\n>>> config.PORT\n8000\n>>> config.PORT = \"abc\"\nTraceback (most recent call last):\n  ...\n```\n\n#### Wrapping interchangeable modules\n\nYou can wrap modules outside them with configuration models:\n\n```python\n# setup.py\nfrom configzen import ConfigModel\n\nclass AppConfig(ConfigModel):\n    HOST: str = \"localhost\"\n    PORT: int = 8000\n\nconfig_model = AppConfig.wrap_module(\"config\")\n```\n\n```py\n# config.py\nHOST: str = \"0.0.0.0\"\nPORT: int = 443\n```\n\n```python\n>>> from setup import config_model\n>>> config_model.HOST\n'0.0.0.0'\n>>> config_model.PORT\n443\n>>> config_model.PORT = \"8000\"\n>>> config_model.PORT\n8000\n>>> import config\n>>> config.HOST\n'0.0.0.0'\n>>> config.PORT\n8000\n```\n\n## Supported file formats\n\n_configzen_ uses [anyconfig](https://pypi.org/project/anyconfig/) to serialize and deserialize data and does not operate on any protocol-specific entities.\nAs an example result, comments in your configuration files are lost on save[^1], but you can exchange file formats without any hassle.\n\nThe following table shows the supported file formats, their requirements, file extensions, and the backend libraries used to accomplish this goal.\n\n| File Format                                                                         | To use, install:              | Recognized File Extension(s) | Backend Library                                                                                       |\n| ----------------------------------------------------------------------------------- | ----------------------------- | ---------------------------- | ----------------------------------------------------------------------------------------------------- |\n| [JSON](https://en.wikipedia.org/wiki/JSON)                                          | -                             | `json`                       | [json](https://docs.python.org/3/library/json.html) (standard library)                                |\n| [INI](https://en.wikipedia.org/wiki/INI_file)                                       | -                             | `ini`, `cfg`, `conf`         | [configparser](https://docs.python.org/3/library/configparser.html) (standard library)                |\n| [TOML](https://en.wikipedia.org/wiki/TOML)                                          | -                             | `toml`                       | [toml](https://pypi.python.org/pypi/toml)                                                             |\n| [YAML](https://yaml.org)                                                            | -                             | `yaml`, `yml`                | [pyyaml](https://pypi.python.org/pypi/PyYAML) / [ruamel.yaml](https://pypi.python.org/pypi/ruamel.yaml) |\n| [XML](https://en.wikipedia.org/wiki/XML)                                            | -                             | `xml`                        | [xml](https://docs.python.org/3/library/xml.html) (standard library)                                  |\n| [ConfigObj](https://configobj.readthedocs.io/en/latest/configobj.html#introduction) | `anyconfig-configobj-backend` | `configobj`                  | [configobj](https://pypi.org/project/configobj/)                                              |\n| [BSON](https://en.wikipedia.org/wiki/BSON)                                          | `anyconfig-bson-backend`      | `bson`                       | [bson](https://pypi.org/project/bson/)                                                                |\n| [CBOR](https://cbor.io/) ([RFC 8949](https://www.rfc-editor.org/rfc/rfc8949))       | `anyconfig-cbor2-backend`     | `cbor`, `cbor2`              | [cbor2](https://pypi.org/project/cbor2/)                                                              |\n| [Amazon Ion](https://en.wikipedia.org/wiki/Ion_(serialization_format))              | `anyconfig-ion-backend`       | `ion`                        | [ion](https://pypi.org/project/amazon.ion/)                                                           |\n| CBOR (deprecated, [RFC 7049](https://www.rfc-editor.org/rfc/rfc7049))               | `anyconfig-cbor-backend`      | `cbor`                       | [cbor](https://pypi.org/project/cbor/)                                                                |\n| properties                                                                          | -                             | `properties`                 | (native)                                                                                              |\n| shellvars                                                                           | -                             | `shellvars`                  | (native)                                                                                              |\n<!-- Add msgpack when it works -->\nIf your file extension is not recognized, you can register your own file extension by calling `ConfigAgent.register_file_extension(file_extension, parser_name)`.\n\nIf your favorite backend library is not supported, please let me know by reporting it as an issue.\nUsing custom backends is to be supported in the future.\n\n[^1]: A suggested alternative for comments is to use the `description` parameter in your configuration models' fields: `ConfigField(description=...)`.\nThe provided field descriptions are included in JSON schemas generated by the default implementation of the `ConfigModel.schema()` method.\n\n## Setup\n\nIn order to use _configzen_ in your project, install it with your package manager, for example `pip`:\n\n```bash\npip install configzen\n```\n\nIf you are willing to contribute to _configzen_, which is awesome, simply clone this repository and install its\ndependencies with [poetry](https://python-poetry.org/):\n\n```bash\npoetry install --with dev --all-extras\n```\nAfter that, install the [pre-commit](https://pre-commit.com/) hooks:\n\n```bash\npre-commit install --hook-type pre-commit --hook-type pre-push\n```\n\nYou might also need to install required stubs. First, activate your virtual environment:\n\n```bash\npoetry shell\n```\n\nand run (on Linux or [PowerShell](https://learn.microsoft.com/en-us/powershell/scripting/overview?view=powershell-7.3) 7.0+):\n\n```bash\nmypy configzen/ || (echo yes | mypy --install-types)\n```\n\nor, if you are using an older version of PowerShell:\n\n```powershell\nmypy configzen/; if (-not $?) { echo yes | mypy --install-types }\n```\n\n_Note: Using [WSL2](https://learn.microsoft.com/en-us/windows/wsl/install) + [pyenv](https://github.com/pyenv/pyenv#readme) (with Python 3.8) for developing configzen is strongly recommended in case you use Windows._\n\nAnd you are good to go. \ud83d\ude80\n\nContributions are welcome! Feel free to [open an issue](https://github.com/bswck/configzen/issues/new/choose) whenever\nyou encounter a bug or have a feature request or [submit a pull request](https://github.com/bswck/configzen/compare) with your changes.\n\n## License\n\n[MIT License](https://choosealicense.com/licenses/mit/)\n\n\n## Credits\n\n* [@Lunarmagpie](https://github.com/Lunarmagpie) for _crucial_ design tips and ideas.\n\n## Author\n\n* [bswck](https://github.com/bswck) (contact: bswck.dev@gmail.com or via [Discord](https://discord.com/) `bswck`)\n\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "The easiest way to manage configuration files in Python",
    "version": "0.10.0",
    "project_urls": {
        "Homepage": "https://github.com/bswck/configzen"
    },
    "split_keywords": [],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "50587541b6ecb4c961459e9e4a970d7a1f368e930c2dd6f0e6caf0403f6368f8",
                "md5": "76afba7012cff8661992bff13c4f66f1",
                "sha256": "bb9b11d21462f50a4400b029b8fe87838907dcb654415cb954a68653ffbbf907"
            },
            "downloads": -1,
            "filename": "configzen-0.10.0-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "76afba7012cff8661992bff13c4f66f1",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.8,<4.0",
            "size": 41289,
            "upload_time": "2023-08-23T21:12:50",
            "upload_time_iso_8601": "2023-08-23T21:12:50.146658Z",
            "url": "https://files.pythonhosted.org/packages/50/58/7541b6ecb4c961459e9e4a970d7a1f368e930c2dd6f0e6caf0403f6368f8/configzen-0.10.0-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "718508835a39768c2c60cdef84659b213394f6f7e91bd05ba4c9cf626365a001",
                "md5": "98ce7010b592f1f74cec344ebc25d83e",
                "sha256": "6bde4b949d21a8fc86ce6c6cd07e5614c299209c1830d13e970830982e74109a"
            },
            "downloads": -1,
            "filename": "configzen-0.10.0.tar.gz",
            "has_sig": false,
            "md5_digest": "98ce7010b592f1f74cec344ebc25d83e",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.8,<4.0",
            "size": 42190,
            "upload_time": "2023-08-23T21:12:51",
            "upload_time_iso_8601": "2023-08-23T21:12:51.568539Z",
            "url": "https://files.pythonhosted.org/packages/71/85/08835a39768c2c60cdef84659b213394f6f7e91bd05ba4c9cf626365a001/configzen-0.10.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2023-08-23 21:12:51",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "bswck",
    "github_project": "configzen",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "lcname": "configzen"
}
        
Elapsed time: 0.23200s