Python | Linux | Windows | MacOS |
---|---|---|---|
3.10 | |||
3.11 |
Initially positioned as a convenient bridge between dataclass
and ConfigParser
,
but later was split into optional modules and added extra functionality:
- Profiles module (cfg.profiles) - a lot of functions for config profiles manipulation:
- Profiles: get, set, clear, rename and switch
- Groups: get and del, set at init only ('group' keyword)
- I/O module (cfg.io) - export/import functions, if needed custom save/load
- File module (cfg.file) - save/load functions for ini config files (use I/O)
- Config groups - simultaneous switch/rename of several configs profiles (use profiles)
- On set handlers (cfg.*_on_set) - calling a user-defined function for changed field(s)
- Options (cfg.options) - change defaults in several functions (waits rewrite in future)
- Data validation (implemented in utils module, but maybe
pydantic
should be used) - Batch fields get (cfg.get_*) - data, defaults, types, changed states, params, on_set handlers
- Batch fields set (cfg.set_*) - data and defaults only
- Besides ConfigBase, there is also LanguageBase - use fixed 'language' group, and 'str' type
- Add docs..
- Add optional autosave (time interval, at exit)
- Add optional get_value_func and pooling_sec to Field (for environment variables, etc.)
- Add optional history of fields/profiles changes (for undo/redo)
- Add config versions (import from older configs by dev-provided functions)
- Add multiple configs in single file (if profiles disabled)
- Add modules support, for example __init__(modules={'db': DataBaseBridge}) (cfg.db)
- Add several active profiles support (with different active fields, override by last one)
- Add logging..
- Do something with utils module - make a separate library or simplify it
- Rebuilt Options to set default methods params at init and change it during execution
Recommended way (without '--user' - elevated privileges needed, if a system interpreter is used)
pip install --user configlayer
from configlayer import ConfigBase
class Config(ConfigBase):
param: str = 'Some str'
data = Config('cfg.ini') # Load from file if exists, else check save file possibility
data.param = 'Another str'
data.cfg.file.save()
from ast import literal_eval # Needed only for custom fields import from str
from configlayer import ConfigBase, Field # Field is needed only for custom fields I/O
# Configuration fields with types and factory defaults
class Config(ConfigBase):
"""Main""" # optional verbose config name at first __doc__ line
auto: bool = False
tab: int = 0
param: str = 'factory default'
items: list = []
items_custom_io: list = Field([], lambda x: f'{x}custom', lambda x: literal_eval(x[:-6]))
# Init config from file, if it exists
data = Config('config simple.ini')
# Set fields ways
data.param = 'field'
data.cfg.set_fields({'auto': True, 'items': ['some']})
# Set user defaults
data.cfg.set_defaults({'tab': 1, 'items_custom_io': ['default']})
# Save changes to file (no autosave yet, planned)
data.cfg.file.save()
# Init config with profiles support (file has additional internal section)
data = Config('config profiles.ini', profiles=True)
profiles = data.cfg.profiles
# Set defaults ways (at this stage - default profile selected, set fields ways change defaults)
data.param = 'default'
data.cfg.set_fields({'auto': True, 'tab': 2})
data.cfg.set_defaults({'items': ['default'], 'items_custom_io': ['default']})
# Add new profiles and switch to it ways
profiles.set('Profile 1', {'auto': False, 'tab': 0})
## 'auto' and 'tab' at factory defaults, 'items' and 'items_custom_io' at user defaults
profiles.switch('Profile 1')
## the same as 'Profile 1', due to copy from currently selected profile
profiles.switch('Profile 2', add=True, add_current=True)
## all fields copied from user defaults
profiles.switch('Profile 3', add=True)
# Rename current profile
profiles.rename('New profile')
# Rename selected profile
profiles.rename('New profile 2', 'Profile 2')
# Save changes to file (no autosave yet, planned)
data.cfg.file.save()
# Init config only in RAM with export/import functions access
data1 = Config(io=True)
data1.param = 'field'
exported = data1.cfg.io.export_config()
data2 = Config(io=True)
data2.cfg.io.import_config(exported)
assert data1 == data2