Skip to content

Config management

The ConfigDataclass mixin provides a mechanism for storing a global configuration object that can be used anywhere within your program.

It can also load configurations from a file. The file types currently supported are JSON and TOML.

Usage Example

Define a ConfigDataclass representing a website configuration. This will include several nested dataclasses for distinct sections of the configuration.

from dataclasses import dataclass

from fancy_dataclass import ConfigDataclass


@dataclass
class ServerConfig:
    hostname: str
    port: int

@dataclass
class DatabaseConfig:
    username: str
    password: str

@dataclass
class WebsiteConfig(ConfigDataclass):
    title: str
    author: str
    description: str
    server: ServerConfig
    database: DatabaseConfig

Now suppose you have a configuration file you want to load from, website_config.toml, whose schema matches the WebsiteConfig class:

# Website Configuration

title = "My Awesome Website"
author = "Webby McWebface"
description = "A simple example of a TOML configuration file for a website."

[server]
hostname = "localhost"
port = 8080

[database]
username = "admin"
password = "password123"

You can load the config file to initialize the configurations as a globally accessible object:

# load from file (only need to do this once)
WebsiteConfig.load_config('website_config.toml')

Then, at any point in your program, you can fetch the configs like so:

>>> cfg = WebsiteConfig.get_config()

# then do stuff with the configs...
>>> print(cfg.title)
My Awesome Website

The advantage of this is that you don't have to pass the configuration object around as a parameter or store it as a global variable.

You can also update the configurations:

def print_current_username():
    """Helper function to print out current database username."""
    global_cfg = WebsiteConfig.get_config()
    print(global_cfg.database.username)
>>> print_current_username()
admin

# update the config by mutating a local reference
>>> cfg.database.username = 'test1'
>>> print_current_username()
test1

# update the global config with another object
>>> from copy import deepcopy
>>> cfg2 = deepcopy(cfg)
>>> cfg2.database.username = 'test2'
>>> cfg2.update_config()
>>> print_current_username()
test2

Sometimes it is useful to modify the configs temporarily:

>>> print_current_username()
test2
>>> cfg.database.username = 'temporary'

# temporarily update global config with the local version
>>> with cfg.as_config():
        print_current_username()
temporary

# global config reverts back to its value before 'as_config' was called
>>> print_current_username()
test2

Details

For configurations with a specified schema, create a subclass of ConfigDataclass instantiating your schema.

The following methods can then be used:

  • load_config: load configs from a JSON or TOML file
  • get_config: get the global config object
  • clear_config: set the global config to None
  • update_config: set the global config to a particular object
  • as_config: context manager to temporarily change the global config to a particular object

For configurations without a specified schema, you can use DictConfig instead. This has the same interface as ConfigDataclass, except you do not need to subclass it or specify a dataclass schema. Instead, it can load the contents of a JSON or TOML file into a regular Python dict, which you can access with get_config.

By default, ConfigDataclass and DictConfig cannot write config files, only read them. To write, you can subclass JSONDataclass or TOMLDataclass.