Package: thatway
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.QuickstartCreate a package with settings.examples/mypkg/moduleA/file.pyfromthatwayimportSettingclassFirstClass:my_attribute=Setting(True,desc="Whether 'my_attribute' is an attribute")max_instances=Setting(3,desc="Maximum number of instances")examples/mypkg/moduleB/file.pyfromthatwayimportconfig,Settingconfig.moduleB.msg=Setting("This is my message")View settings:importexamples.mypkgfromthatwayimportconfigprint(config.dumps_yaml())FirstClass:my_attribute:true# Whether 'my_attribute' is an antribuemax_instances:3# Maximum number of instancesmoduleB:msg:ThisismymessageLoad different settings:examples/mypkg/new_settings.yamlFirstClass:my_attribute:falsemax_instances:2with python:frompathlibimportPathimportexamples.mypkgfromthatwayimportconfigconfig.load_yaml(str(Path("examples")/"mypkg"/"new_settings.yaml"))print(config.dumps_yaml())FirstClass:my_attribute:false# Whether 'my_attribute' is an antribuemax_instances:2# Maximum number of instancesmoduleB:msg:ThisismymessageRulesThe following are design decisions on the behavior of thatway’s configuration
manager.1. Configure directlySettings can be set directly on the config object.>>>fromthatwayimportconfig,Setting>>>config.a=Setting(3)>>>config.a3>>>config.nested.b=Setting("nested")>>>config.nested.b'nested'Trying to set an entry in the config without a setting raises an exception.>>>fromthatwayimportconfig>>>config.new_value=3Traceback(mostrecentcalllast):...thatway.base.ConfigException:OnlySettingscanbeinsertedintheConfig2. Configure object attributesSettings can be set as object attributes.>>>fromthatwayimportSetting>>>classObj:...attribute=Setting("my value")>>>obj=Obj()>>>obj.attribute'my value'3. Configuration lockingSettings cannot be accidentally modified. Once they’re set, they’re set until
the config’supdateorloadmethods are used.>>>fromthatwayimportSetting>>>config.b=Setting(3)>>>config.b3>>>config.b=Setting(5)# oops!Traceback(mostrecentcalllast):...thatway.base.ConfigException:Entry'b'alreadyintheConfig--useaConfig.updateorloadmethodtochangeitsvalue.>>>config.b=5# oops!Traceback(mostrecentcalllast):...thatway.base.ConfigException:OnlySettingscanbeinsertedintheConfig>>>config.update({'b':5})>>>config.b5The 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.4. Type EnforcementSetting types are checked and maintained with either the setting’s value type,
or theallowed_typesoptional argument.>>>fromthatwayimportSetting>>>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(mostrecentcalllast):...ValueError:Couldnotconvert'my new d value'intoanyofthefollowingtypes:[<class'int'>]6. Missing SettingsTrying 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.>>>fromthatwayimportSetting>>>config.update({'e':'unassigned'})# 'f' doesn't exist in configTraceback(mostrecentcalllast):...KeyError:"Tried assigning setting with name 'e' which does not exist in the Config"7. Immutable Settings ValuesSetting 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 immutableFeatures1. Setting descriptionsSettings can include descriptions.>>>fromthatwayimportSetting>>>config.e=Setting(4,desc="The 'e' attribute")2. Yaml processingSettings can be dumped inyaml.config.dumps_yaml()Obj:a:1b:name# The 'b' settingnested:c:trueAndyamlstrings or files can be loaded withconfig.loads_yaml(string)andconfig.load_yaml(filepath), respectively.3. Toml processingSettings can be dumped intoml.config.dumps_toml()[Obj]a=1b="name"# The 'b' setting[nested]c=trueAndtomlstrings or files can be loaded withconfig.loads_toml(string)andconfig.load_toml(filepath), respectively.