Skip to content

bswck/configzen

configzen
skeleton Supported Python versions Package version

Tests Coverage Lifted?

Manage configuration with pydantic.

Warning

configzen is currently under huge refactoring to work with pydantic v2. The API is subject to change.

While being built on top of pydantic, configzen inherits most of its features, including data validation, schema generation, custom data types, good integration with Rich, and more.

Learn more below.

Features

Managing Content

Having a YAML configuration file like this:

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

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

# model.py
from ipaddress import IPv4Address, IPv6Address

from configzen import BaseConfig, Field, ModelConfig


class DBConfig(BaseConfig):
    host: IPv4Address | IPv6Address
    port: int
    user: str
    password: str = Field(exclude=True)

    model_config = ModelConfig(
        config_source="database.yml",
        env_prefix="DB_",
    )


db_config = DBConfig.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 for more information.

pydantic 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:

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

modify them, if the pydantic model validation allows it (<Your model>.Config.validate_assignment will be True by default):

>>> 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:

>>> db_config.at(DBConfig.port).reload()
5432
# `DBConfig.port` is a LinkedRoute object that ensures `port` of `DBConfig` exists!
>>> db_config
DatabaseConfig(host=IPv4Address('0.0.0.0'), port=5432, user='postgres', password='password')
>>> db_config.at(DBConfig.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:

>>> 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:

>>> 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(DBConfig.host).save()
40
>>> db_config.reload()
DatabaseConfig(host=IPv4Address('0.0.0.0'), port=5432, user='postgres', password='password')

or save the whole configuration:

>>> db_config.save()
39

Modular Configuration

Wrapping Modules In-Place

You can wrap modules in-place with configuration models:

  1. Without writing a model class:
# config.py
from configzen import ConfigModule

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

ConfigModule.wrap_this_module()
  1. With a model class:
# 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:

>>> 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:

# setup.py
from configzen import ConfigModel

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

config_model = AppConfig.wrap_module("config")
# config.py
HOST: str = "0.0.0.0"
PORT: int = 443
>>> 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

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 - json json (standard library)
TOML - toml, ini, cfg, conf tomlkit
YAML - yaml, yml ruamel.yaml
Plist - plist plistlib (standard library)

For Enterprise

Tidelift Available as part of the Tidelift Subscription.
This project and the maintainers of thousands of other packages are working with Tidelift to deliver one enterprise subscription that covers all of the open source you use. Learn more here.

To report a security vulnerability, please use the Tidelift security contact.
Tidelift will coordinate the fix and disclosure.

Installation

You might simply install it with pip:

pip install configzen

If you use Poetry, then you might want to run:

poetry add configzen

For Contributors

Poetry Ruff Pre-commit

Note

If you use Windows, it is highly recommended to complete the installation in the way presented below through WSL2.

  1. Fork the configzen repository on GitHub.

  2. Install Poetry.
    Poetry is an amazing tool for managing dependencies & virtual environments, building packages and publishing them. You might use pipx to install it globally (recommended):

    pipx install poetry

    If you encounter any problems, refer to the official documentation for the most up-to-date installation instructions.

    Be sure to have Python 3.8 installed—if you use pyenv, simply run:

    pyenv install 3.8
  3. Clone your fork locally and install dependencies.

    git clone https://github.com/your-username/configzen path/to/configzen
    cd path/to/configzen
    poetry env use $(cat .python-version)
    poetry install

    Next up, simply activate the virtual environment and install pre-commit hooks:

    poetry shell
    pre-commit install

For more information on how to contribute, check out CONTRIBUTING.md.
Always happy to accept contributions! ❤️

Legal Info

© Copyright by Bartosz Sławecki (@bswck).
This software is licensed under the terms of GPL-3.0 License.