Package: configlayer
Configlayer: an attempt to simplify working with configurationsPythonLinuxWindowsMacOS3.103.11FeaturesInitially positioned as a convenient bridge betweendataclassandConfigParser,but later was split into optional modules and added extra functionality:Profilesmodule (cfg.profiles) - a lot of functions for config profiles manipulation:Profiles: get, set, clear, rename and switchGroups: get and del, set at init only ('group' keyword)I/Omodule (cfg.io) - export/import functions, if needed custom save/loadFilemodule (cfg.file) - save/load functions for ini config files (useI/O)Config groups - simultaneous switch/rename of several configs profiles (useprofiles)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 inutilsmodule, but maybepydanticshould be used)Batch fields get (cfg.get_*) - data, defaults, types, changed states, params, on_set handlersBatch fields set (cfg.set_*) - data and defaults onlyBesides ConfigBase, there is also LanguageBase - use fixed 'language' group, and 'str' typeTodo listAdd 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 itRebuilt Options to set default methods params at init and change it during executionInstallingRecommended way (without '--user' - elevated privileges needed, if a system interpreter is used)pipinstall--userconfiglayerMinimal usage examplefromconfiglayerimportConfigBaseclassConfig(ConfigBase):param:str='Some str'data=Config('cfg.ini')# Load from file if exists, else check save file possibilitydata.param='Another str'data.cfg.file.save()Other examplesCommon partfromastimportliteral_eval# Needed only for custom fields import from strfromconfiglayerimportConfigBase,Field# Field is needed only for custom fields I/O# Configuration fields with types and factory defaultsclassConfig(ConfigBase):"""Main"""# optional verbose config name at first __doc__ lineauto:bool=Falsetab:int=0param:str='factory default'items:list=[]items_custom_io:list=Field([],lambdax:f'{x}custom',lambdax:literal_eval(x[:-6]))Simple config file# Init config from file, if it existsdata=Config('config simple.ini')# Set fields waysdata.param='field'data.cfg.set_fields({'auto':True,'items':['some']})# Set user defaultsdata.cfg.set_defaults({'tab':1,'items_custom_io':['default']})# Save changes to file (no autosave yet, planned)data.cfg.file.save()Profiles config file# 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 waysprofiles.set('Profile 1',{'auto':False,'tab':0})## 'auto' and 'tab' at factory defaults, 'items' and 'items_custom_io' at user defaultsprofiles.switch('Profile 1')## the same as 'Profile 1', due to copy from currently selected profileprofiles.switch('Profile 2',add=True,add_current=True)## all fields copied from user defaultsprofiles.switch('Profile 3',add=True)# Rename current profileprofiles.rename('New profile')# Rename selected profileprofiles.rename('New profile 2','Profile 2')# Save changes to file (no autosave yet, planned)data.cfg.file.save()Simple RAM-only config, with I/O operations# Init config only in RAM with export/import functions accessdata1=Config(io=True)data1.param='field'exported=data1.cfg.io.export_config()data2=Config(io=True)data2.cfg.io.import_config(exported)assertdata1==data2