Package: configfy
ConfigfyDecorator library to expose keyword arguments through config filesConfigfy is a prototyping library that enables fast exposure of function parameters to the user in order modify program behavior without having to handle argument parsing or control the flow of config options through your program. It is implemented as a decorator library that makes use of the python configparser module.It can be used to quick and dirty add new arguments to an function,
or substitute the complete configuration management for an application.Hostet ongithubInstallationConfigfy is best installed using pippipinstallconfigfySimple exampleDefine a function that makes use of keyword arguments, and overwrites the default
keyword argument with a config file setting.importconfigfyfromconfigfyimportconfigfyascfy@cfydefhello(name,another_name='Pedro'):"""Be nice and say hello"""print(f'Hello{name}, I am{another_name}!')hello('Bob')With a config.ini containing[global]another_name='Suzan Flusan'producesHelloBob,IamSuzanFlusan!Note: Be aware that the library expects the presence of a config file (./configfy.ini) containing at least the empty section [global].Advanced ExampleShow how to specify sections to use in config files and how the config file can be changed during runtime, or specified in the decorator.From docs/example.pyimportconfigfyfromconfigfyimportconfigfyascfy@cfydefhello(name,another_name='Pedro'):"""Be nice and say hello"""print('Hello%s, I am%s!'%(name,another_name))@cfy(section='greetings_section')defgreetings(name,language='english'):"""Give a nice greeting ..."""iflanguage=='english':print('Hello%s! How are you doing?'%(name))eliflanguage=='spanish':print('Hola%s! Que tal?'%(name))eliflanguage=='german':print('Hallo%s! Wie gehts?'%(name))eliflanguage=='serbian':print('Zdravo%s! Kako si?'%(name))else:print('!nuqneH%s!'%(name))@cfy(config='yet_another_config.ini')defgoodby(msg='Goodby!'):print(msg)print('# Use default configfy.ini file (missing greetings section)...')print('# Current config:%s'%configfy.configfile.config)hello('Bob')greetings('Tom')goodby()print('\n# Changing config to "another_config.ini" ...')configfy.set_active_config_file('another_config.ini')print('After setting new config file, current config:%s'%configfy.configfile.config)hello('Bob')greetings('Tom')goodby()print('\n# Specifying kwargs, overwriting config settings...')hello('Bob',another_name='Alfredo')greetings('Tom',language='serbian')goodby(msg='That\'s all Folks!')Produces# Use default configfy.ini file (missing greetings section)...# Current config: OrderedDict([('global', {'another_name': 'Suzan Flusan', 'language': 'spanish'})])HelloBob,IamSuzanFlusan!# 2018-08-01 17:45:53,834 - configfy - WARNING - Config section greetings_section not found!HelloTom!Howareyoudoing?
Goodby!# Changing config to "another_config.ini" ...Aftersettingnewconfigfile,currentconfig:OrderedDict([('global',{'language':'spanish','msg':'A goodby message! Ignored'}),('greetings_section',{'language':'german'})])HelloBob,IamPedro!
HalloTom!Wiegehts?
Goodby!# Specifying kwargs, overwriting config settings...HelloBob,IamAlfredo!
ZdravoTom!Kakosi?
That'sallFolks!Complete config replacementThis is a complete example making use of configfy as a general tool to replace
the configuration file for an application. The source code can be found in ./docimportclickimportconfigfyfromconfigfyimportconfigfyascfy# Two user functions that get their kwargs from the current config file@cfydefuser_function1(kw1=23,name1=''):print('Calling user_function1(%s,%s) ...'%(kw1,name1))@cfydefuser_function2(kw2=None,name2=''):print('Calling user_function2(%s,%s) ...'%(kw2,name2))# Use the excellent click library to handle program arguments@click.group()@click.version_option(0.1)@click.option('-v','--verbose',count=True)@click.option('--config',default='configfy.ini',help='Specify the configfy file to use')defexample(verbose,config):"""Enabling sub commands"""# Load config fileconfigfy.set_active_config_file(config)globalconfig_fileconfig_file=config@example.command()defex1():user_function1()@example.command()defex2():user_function2()if__name__=='__main__':example()config file:[global]# Pass a number and a listkw1=1001name1=['l', 'i', 's', 't']# Pass a dict and a setkw2={'d': 42}# Note: passing set(1, 2, 3) wont work. It will be passed as a stringname2={1, 2, 3}Usage>pythoncomplete_example.py--configcomplete_example.iniex1
Callinguser_function1(1001,['l','i','s','t'])...

>pythoncomplete_example.py--configcomplete_example.iniex2
Callinguser_function2({'d':42},{1,2,3})...DebuggingDebugging functions augmented with configfy can be tricky because instead of stepping
directly into a user function modified by configfy, the debugger will enter the
configfy library code first.What one can do, is make the debugger "skip" the configfy library code.pdbimportpdbfromconfigfyimportconfigfyascfy@cfydeffuu(kw_me=42):print(kw_me)if__name__=='__main__':# load pdb, making use of the skip parameterpdb.Pdb(skip=['configfy.*']).set_trace()fuu()pudbimportpudbfromconfigfyimportconfigfyascfy# Prevent pudb from stepping into the decorator library codepudb._get_debugger(skip=['configfy.*'])@cfydeffuu(kw_me=42):print(kw_me)if__name__=='__main__':pudb.set_trace()fuu()OverheadTry it out yourself! Runcd docpython overhead.pyI gotComparingperformance...thiscantakeawhile.
native:11.863sec
configfy+config11.953sec
configfy12.160secAuthorI happy to receive any feedback or comments on github or privately tomanuel.pasieka@protonmail.chWhy I wrote this moduleI wrote this library because I often have to write prototypes in ascientificsettings, in which it is unclear upfront what goals to achieve.It often happened to me that I had to introduce additional parameters and options to functions deep down in the application flow, in order to make its behavior alterable by the user. One can do this by either some global config file, or parse program arguments and pass them through multiple layers to the desired functions.In order to make those steps easier and speed things up, I wrote this library which enables one to post-hoc add keyword arguments to any function in the codebase, and expose them to the user via a simple config file.LicenseMIT