Package: click-schema-config
click-schema-configclick-schema-config allows you to add settings from a config file. Those will be automatically pulled into your program description without having to repeat them. Comments will be used as helper text for click.Is this project necessary?After having built and used this, I am no longer convinced it is the best approach. I thinkyt-dlpandparallelway of doing it might be more pertinent: Having profile files that specifies what options to enable.That said, codegen-ini solves the problem of packaging click's parameters and well-tying them, which has been a constant pain point for me.I will continue developping and using this tool for now, but it might not be the best way to go about this problem.Installationpoetryaddclick-schema-configor, using pippip install click-schema-configUsageDecorate your function with@schema_from_inis(files=[...])This will automatically infer the structure of your ini files and its documentation and add it to click.Example of a config.default.ini:initialized_to_none=[test1]; Wow, multilines; Talk about eye candymultiline_commented="value1"typed:int = 2inferred=True[test2]inline_commented="value1"# This comment does not appear in the documentation; This is a commentafter_paragraph=NoneNote that you can type values directly. If a parameter appears without = succeding it, it becomes a required parameter.main.pyimportpprintimportclickfromclick_schema_configimportschema_from_inis@click.command()@schema_from_inis(files=["config.default.ini"])defmain(**kwargs):pprint.pprint(kwargs)if__name__=="__main__":main()This will result in:python__main__.py--help

Usage:__main__.py[OPTIONS]Options:--initialized_to_noneTEXT--test1.multiline_commentedTEXTWow,multilinesTalkabouteyecandy[default:value1]--test1.typedINTEGER[default:2]--test1.inferred/--no-test1.inferred[default:test1.inferred]--test2.inline_commentedTEXT[default:value1]--test2.after_paragraphTEXTThisisacomment--helpShowthismessageandexit.andpython__main__.py{'initialized_to_none':None,'required_parameter_overriden':'not required','test1__inferred':True,'test1__multiline_commented':'value1','test1__typed':2,'test2__after_paragraph':None,'test2__inline_commented':'value1'}You can of course override using the options:pythonmain.py--test2.inline_commented"HEY"{'initialized_to_none':None,'required_parameter_overriden':'not required','test1__inferred':True,'test1__multiline_commented':'value1','test1__typed':2,'test2__after_paragraph':None,'test2__inline_commented':'HEY'}RationaleHaving setting files allow for separation of concerns and for users to know what they are expected to tweak and modify. This library is here to provide schema specifications of settings.Codegen-iniThis library also comes with thecodegen-initool that allows you to have well-typed click dictionaries.
For instance, in the following code:@click.command()@schema_from_inis(files=["config.default.ini"])defmain(**kwargs):pprint.pprint(kwargs)It is unclear what keywords are present in kwargs, and what can be accessed. This makes for uncoupled code where changing the configuration leads to bugs and undefined variables.
To solve this, we can use codegen-ini to generate a pydantic class for uscodegen.yamlschemas:MyClass:"./config.default.ini"and run itcodegen-iniThe following code will be generated in ./generated/MyClass.py:frompydanticimportBaseModelclassMyClass(BaseModel):initialized_to_none:None=Nonerequired_parameter_overriden:strrequired_parameter:int"""Wow, multilinesTalk about eye candy"""test1__multiline_commented:str="value1"test1__typed:int=2test1__inferred:bool=Truetest2__inline_commented:str="value1""""This is a comment"""test2__after_paragraph:None=NoneclassMyClassPartial(BaseModel):initialized_to_none:None|None=Nonerequired_parameter_overriden:str|None=Nonerequired_parameter:int|None=None"""Wow, multilinesTalk about eye candy"""test1__multiline_commented:str|None=Nonetest1__typed:int|None=Nonetest1__inferred:bool|None=Nonetest2__inline_commented:str|None=None"""This is a comment"""test2__after_paragraph:None|None=NoneWhich you can use to type your passed config:fromgenerated.codegen_iniimportMyClassdefmain(**kwargs):config=MyClass(**kwargs)print(config.test1__multiline_commented)# Well typedTODOIntegration with click types, like click.choices and click.intrangeTest suitePreserve section structure in codegen-ini's generated classes?