Thatway is a simple, decentralized configuration manager.
Place your configuration settings throughout your application--not in a centralized file or submodule--and thatway collects them and allows you to modify them through configurations files. Decentralized configuration reduces the complexity of submodules and the coupling between submodules.
-
Create a package with settings.
examples/mypkg/moduleA/file.py
from thatway import Setting class FirstClass: my_attribute = Setting(True, desc="Whether 'my_attribute' is an attribute") max_instances = Setting(3, desc="Maximum number of instances")
examples/mypkg/moduleB/file.py
from thatway import config, Setting config.moduleB.msg = Setting("This is my message")
-
View settings:
import examples.mypkg from thatway import config print(config.dumps_yaml())
FirstClass: my_attribute: true # Whether 'my_attribute' is an antribue max_instances: 3 # Maximum number of instances moduleB: msg: This is my message
-
Load different settings:
examples/mypkg/new_settings.yaml
FirstClass: my_attribute: false max_instances: 2
with python:
from pathlib import Path import examples.mypkg from thatway import config config.load_yaml(str(Path("examples") / "mypkg" / "new_settings.yaml")) print(config.dumps_yaml())
FirstClass: my_attribute: false # Whether 'my_attribute' is an antribue max_instances: 2 # Maximum number of instances moduleB: msg: This is my message
The following are design decisions on the behavior of thatway's configuration manager.
-
Configure directly
Settings can be set directly on the config object.
>>> from thatway import config, Setting >>> config.a = Setting(3) >>> config.a 3 >>> config.nested.b = Setting("nested") >>> config.nested.b 'nested'
Trying to set an entry in the config without a setting raises an exception.
>>> from thatway import config >>> config.new_value = 3 Traceback (most recent call last): ... thatway.base.ConfigException: Only Settings can be inserted in the Config
-
Configure object attributes
Settings can be set as object attributes.
>>> from thatway import Setting >>> class Obj: ... attribute = Setting("my value") >>> obj = Obj() >>> obj.attribute 'my value'
-
Configuration locking
Settings cannot be accidentally modified. Once they're set, they're set until the config's
update
orload
methods are used.>>> from thatway import Setting >>> config.b = Setting(3) >>> config.b 3 >>> config.b = Setting(5) # oops! Traceback (most recent call last): ... thatway.base.ConfigException: Entry 'b' already in the Config--use a Config.update or load method to change its value. >>> config.b = 5 # oops! Traceback (most recent call last): ... thatway.base.ConfigException: Only Settings can be inserted in the Config >>> config.update({'b': 5}) >>> config.b 5
The one exception is that settings defined on a class can be replaced on the class itself--not a class instance. This is because settings act as descriptors for classes.
-
Type Enforcement
Setting types are checked and maintained with either the setting's value type, or the
allowed_types
optional argument.>>> from thatway import Setting >>> config.c = Setting(5, allowed_types=(int, str)) >>> config.update({'c': 'my new c value'}) >>> config.c 'my new c value' >>> config.d = Setting(6) >>> config.update({'d': 'my new d value'}) Traceback (most recent call last): ... ValueError: Could not convert 'my new d value' into any of the following types: [<class 'int'>]
-
Missing Settings
Trying to update a setting that doesn't exist is not possible. This behavior is designed to avoid trying to change a setting but using an incorrect setting name and location.
>>> from thatway import Setting >>> config.update({'e': 'unassigned'}) # 'f' doesn't exist in config Traceback (most recent call last): ... KeyError: "Tried assigning setting with name 'e' which does not exist in the Config"
-
Immutable Settings Values
Setting values can only be immutable objects.
>>> from thatway import Setting >>> config.cli.color = Setting(True) >>> config.cli.default_filenames = Setting(('a.html', 'b.html')) >>> config.cli.value_list = Setting([1, 2]) # lists are mutable Traceback (most recent call last): ... thatway.base.ConfigException: Setting value '[1, 2]' must be immutable
-
Setting descriptions
Settings can include descriptions.
>>> from thatway import Setting >>> config.e = Setting(4, desc="The 'e' attribute")
-
Yaml processing. Settings can be dumped in yaml with
config.dumps_yaml()
.Obj: a: 1 b: name # The 'b' setting nested: c: true
And yaml strings or files can be loaded with
config.loads_yaml(string)
andconfig.load_yaml(filepath)
, respectively. -
Toml processing
Settings can be dumped in toml with
config.dumps_toml()
.[Obj] a = 1 b = "name" # The 'b' setting [nested] c = true
And toml strings or files can be loaded with
config.loads_toml(string)
andconfig.load_toml(filepath)
, respectively.