Defining parameters
This package lets you define parameters for configuration and settings. The difference
between configuration and settings is as follows. Config
is for parameters that do not
change during runtime and are read from file. Settings
are parameters that can change
programmatically during runtime and are read from and saved to file for persistancy over
sessions. During definition, they differ only in terms of the base classes that are used.
The intended structure is that parameters are defined in section classes. Sections can be nested. There should be one special root section for the application, referred to as the container, that handles file storage. Config sections and Settings sections should never be mixed (i.e., do not nest a Settings section in a Config section and vice versa).
Defining non-container section(s)
A section is defined by subclassing the relevant base class (ConfigSectionBase
for
config, SettingsSectionBase
for settings) and decorating it with
@dataclass(frozen=True)
. Parameters are defined as fields of the dataclass. For a
dataclass, it is mandatory to add a type hint for each field. These type hints are used
also to validate the data that is read from the parameter file. If you
specify a default value as well, then you prevent the occurance of an exception if the
value for the parameter of concern is not found in the parameter file.
The dataclass
decorator provided by application_settings
is actually an exported
pydantic.dataclasses.dataclass
, which
is a drop-in replacement for a dataclass
from the standard python library, enhanced
with data validation. If you need additional dataclass functionality such as fields
etc., you can import those from the standard library.
Nested sections are obtained by defining fields in a section that are type hinted with the appropriate contained section class(es) and instantiated (possible only when all parameters of the nested section have default values).
Defining the container
The container is a special section that is to be the root for parametrisation of an
application. It is defined likewise: by subclassing the relevant base class (ConfigBase
for config, SettingsBase
for settings), decorating it with @dataclass(frozen=True)
,
defining fields for parameters and nested non-root sections.
Note that albeit settings can be changed programmatically, we still set frozen=True
for
the settings container and -sections (see also the example section below).
Example
from application_settings import ConfigBase, ConfigSectionBase, attributes_doc, dataclass
@attributes_doc
@dataclass(frozen=True)
class MyExampleConfigSection(ConfigSectionBase):
"""Config section for an example"""
field1: float = 0.5
"""Docstring for the first field; defaults to 0.5"""
field2: int = 2
"""Docstring for the second field; defaults to 2"""
@attributes_doc
@dataclass(frozen=True)
class MyExampleConfig(ConfigBase):
"""Config for an example"""
name: str = "nice example"
"""With this parameter you can configure the name; defaults to 'nice example'"""
section1: MyExampleConfigSection = MyExampleConfigSection()
"""Holds the configuration parameters for the first section"""
from application_settings import SettingsBase, SettingsSectionBase, attributes_doc, dataclass
@attributes_doc
@dataclass(frozen=True)
class BasicSettingsSection(SettingsSectionBase):
"""Settings section for the basics"""
totals: int = 2
"""The totals value; defaults to 2"""
@attributes_doc
@dataclass(frozen=True)
class MyExampleSettings(SettingsBase):
"""Settings for an example"""
name: str = "nice name"
"""This parameter holds the name setting; defaults to 'nice name'"""
basics: BasicSettingsSection = BasicSettingsSection()
"""Holds the setting parameters for the basic section"""