Quick Start
Install
Install with pip:
pip install batconf
Project Setup
BatConf is designed to be minimally invasive. Most projects only need a single file which imports from batconf. Config classes are stdlib dataclasses which can be used with or without BatConf.
Add a GlobalConfig and Config classes dataclass to your module’s root
__init__.pyThe Config dataclasses provide basic config objects for your classes and modules.
Config dataclasses can be nested to create a configuration tree structure.
Add the get_config function function to
{yourmodule}/conf.pyThis is where we create the list of config sources which we will use to lookup values.
Use get_config function to get the global, or partial config you need to run your code.
References
Example Configuration (tests/example/project/): the example python module “project” uses BatConf. Test cases are included which show specific uses with more context.
template project example: Is a project template with a basic batconf setup
GlobalConfig and Config classes
The GlobalConfig class is a python dataclass, used for namespacing
and providing a structured configuration tree.
Its attributes should be other Config dataclasses for sub-modules.
It can define config options, and they can be given default values.
# yourmodule/__init__.py
from dataclasses import dataclass
from .example import Config
@dataclass
class GlobalConfig:
# example module with configuration dataclass
example: Config
option: str = "default value"
# yourmodule/example/__init__.py
from dataclasses import dataclass
from .client import ClientConfig
@dataclass
class ExampleConfig:
client: ClientConfig
moduleoption: str = 'a module level option'
get_config function
Add a get_config function to your project, I recommend putting this in
{yourmodule}/config.py
Most projects can copy this example with minimal modification.
# {yourmodule}/conf.py
from . import GlobalConfig
from batconf.manager import Configuration, ConfigProtocol
from batconf.source import SourceList
from batconf.sources.args import CliArgsConfig, Namespace
from batconf.sources.env import EnvConfig
from batconf.sources.file import FileConfig
from batconf.sources.dataclass import DataclassConfig
def get_config(
# Known issue: https://github.com/python/mypy/issues/4536
config_class: ConfigProtocol = GlobalConfig, # type: ignore
cli_args: Namespace = None,
config_file: FileConfig = None,
config_file_name: str = None,
config_env: str = None,
) -> Configuration:
# Build a prioritized config source list
config_sources = [
CliArgsConfig(cli_args) if cli_args else None,
EnvConfig(),
config_file if config_file else FileConfig(
config_file_name, config_env=config_env
),
DataclassConfig(config_class),
]
source_list = SourceList(config_sources)
return Configuration(source_list, config_class)
Defaults
The default will construct a :class:batconf.manager.Configuration
object using your GlobalConfig and Config classes
# yourmodule/lib.py
from .conf import get_config
from .example.client import Client
def application_code():
cfg = get_config()
print(f'default option value: {cfg.option=}')
client = Client.from_config(cfg.example.client)
client.do_work()
Partial Configs
Given any valid config_class, get_config will return a Configuration with it
as the root.
from yourmodule.conf import get_config
from yourmodule.client import ClientConfig
cfg = get_config(ClientConfig)
print(cfg.username)
Gotcha: the DataclassConfig source is currently linked to the __module__
Namespace of the Config classes. For now, we recommend that Config class
structure mirrors your module names. We are working on a fix to make this
more flexible.
Usage
Access config option values using python’s attribute(.) notation.
In [1]: cfg = get_config()
WARNING:root:Config File not specified: create config.yaml, set environment variable BAT_CONFIG_FILE to config file path, or speicfy a config file.
In [2]: print(cfg)
Root <class 'bat.GlobalConfig'>:
|- server = <class 'bat.server.ServerConfiguration'>:
| |- host: "0.0.0.0"
| |- port: "5000"
SourceList=[
<batconf.sources.env.EnvConfig object at 0x7faf102ed4f0>,
<batconf.sources.file.FileConfig object at 0x7faf102e7440>,
<batconf.sources.dataclass.DataclassConfig object at 0x7faf102e7740>,
]
In [3]: cfg.server.host
Out[3]: '0.0.0.0'
CLI Args
When running commands from a CLI, use the parsed args(argparse.Namespace).
yourmodule/clilib.py
from argparse import Namespace
from .conf import get_config
from .example.client import Client
# execute > `yourmodulecli --flag client --address=0.0.0.0 connect`
def cli_client_connect(args: Namespace):
cfg = get_config(cli_args=args)
print(f'cli arg "flag": {cfg.flag=}')
print(f'Connect to server@{cfg.example.client.address}')
client = Client.from_config(cfg.example.client)
client.connect()
Warning: The builtin CliArgsConfig has some sharp edges.
Additional documentation and development are needed to make it easier to use.
Gotcha: argparse Namespace is a flat structure. In the current implementation this results in any arguments from the CLI overwriting all other config options with the same name. In most projects, this kind of namespace collision has not caused serious issues, but it is a known defect. It is possible to use nested Namespaces to solve this problem, but it adds complexity and needs to be documented.
Configuration File (YAML)
default: dev
dev:
yourproject:
example:
client:
username: devusr
password: changeme
address: 0.0.0.0
prod:
yourproject:
example:
client:
username: produser
password: lets-add-a-secure-source-for-this
address: 192.168.1.1
This example has 2 environments, dev and prod, the default environment is set
to dev.
In each environment we have a section for the root module yourproject, and
configuration options for the client found in yourproject.example.client.
setting the configuration file
Default: If no config file is specified, batconf will look for a file named
config.yamlin your working directory.Environment variable:
BAT_CONFIG_FILEis an environment variable that you can set to the path to your config file.CLI args: I recommend adding config file path and environment to your CLI for convenience. ex:
> yourcli --config_file=~/mycfg.yaml --env=staging ...