Package: python-cli-generator
python-cli-generatorA Python framework that allows an automatic generation of a CLI given a class, a function or a list of classes.Report Bug·Request FeatureTable of ContentsAbout The ProjectGetting StartedPrerequisitesUsageImport the libraryCreate input classesGenerate CLICli resultsRoadmapLicenseContactAbout The ProjectThis library allows rapid creation of a CLI by automatically reading the attributes, methods and function parameters inside a class and generating its corresponding Command Line Interface through the built-in argparse library. The module contains an optional output processor able to print the result of the executed command in different formats.(back to top)Getting StartedThe necessary steps to get the library working on your environment.PrerequisitesBefore using the application you need to have installedpython. You can get instructions on how to install it by following the link shown before.Install the libraryGet the latest version of the library from the github repositorypip3installgit+https://github.com/AlexSua/python-cli-generator.gitGet the stable version from the PyPI repositorypip3installpython-cli-generator(back to top)UsageImport the libraryImport the controller class "Cli" which contains the main functionality for initializing the generation process.frompython_cli_generatorimportCliInitialize HTTPSession and CacheStorage (Optional)Initialize classes HTTPSession and CacheStorage for fetching from a REST API and cache the result of a method into a file respectively. These classes contain a method that acts as a decorator for another method providing extra functionality. You can see the example that follows to see how it works.frompython_cli_generator.plugins.cacheimportCacheStorageFilefrompython_cli_generator.plugins.httpimportHTTPSession# Introduce as arguments here all parameters who wish to be passed as attributes to session of the requests library. Every request through the method decorator called fetch from HTTPSession will use this parameters on each request.jikanmoe=HTTPSession(url_base="https://api.jikan.moe/v4/",headers={'sec-ch-ua':'"Google Chrome";v="107", "Chromium";v="107", "Not=A?Brand";v="24"','sec-ch-ua-mobile':'?0','sec-ch-ua-platform':'"Linux"','Upgrade-Insecure-Requests':'1','User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36','Accept':'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',})# Initialize the file where the result of cached methods will be stored.cache_storage=CacheStorageFile(file_name=".cache.example_filename")Create input classesCreate the classes the generator will use to generate the Command line interface.Notice that comments are as well parsed and automatically added to the CLI.fromdatetimeimportdatetimefromenumimportEnumfromtypingimportListclassParameterTest:"""Parameter test classparameter_test_required (str): optional parameter parameter_test_attr1parameter_test_optional (str): optional parameter parameter_test_attr2."""#If it doesn't have default value is not generated.parameter_test_attr1:strparameter_test_attr2:str=""classAnimeType(Enum):tv="tv"movie="movie"ova="ova"special="special"ona="ona"music="music"classTest:"""Test classtest_attr_1 (str): optional parameter test_attr_1test_attr_2 (str): optional parameter test_attr_2."""test_attr_1:strtest_attr_2:strdef__init__(self):# self.test_attr_1 = "test1"# self.test_attr_2 = "test2"pass# Store cache for a maximum of 60 seconds.@cache_storage.cache(expiration=60)# Fetch anime from the path /anime of jikanmoe. Query params are automatically introduced given the optional parameters of the method.# _response gives you the response of the request. If you use the POST method positional parameters are introduced as body parameters.@jikanmoe.fetch("anime",method="GET")defanime_search(self,q:str=None,min_score:int=None,type:AnimeType=None,sort:str="desc",_response:dict=None):"""Get anime list from malArgs:q (str, optional): Query anime. Defaults to None.min_score (int, optional): Minimum score. Defaults to None.type (AnimeType, optional): Type of anime. Defaults to None.sort (str, optional): Sort anime. Defaults to None."""returnlist(map(lambdax:{"mal_id":x["mal_id"],"title":x["titles"][0]["title"],"genres":",".join(list(map(lambday:y["name"],x["genres"]))),"score":x["score"]},_response["data"]))deft_method2(self,test3,test4="test4",**test5:ParameterTest):"""A method1 exampleArgs:test3 (str): required parameter test3test4 (str, optional): optional parameter test4. Defaults to "test4"."""return[{"parameter_name":"test_1","parameter_value":self.test_attr_1},{"parameter_name":"test_2","parameter_value":self.test_attr_2},{"parameter_name":"test3","parameter_value":test3},{"parameter_name":"test4","parameter_value":test4},{"parameter_name":"test5","parameter_value":test5},]classTest1:"""test1 descriptiont2_attr_1 (str): optional parameter test1t2_attr_2 (int): optional parameter test2.t2_attr_3 (datatime): optional parameter test2.t2_attr_4 (list): optional parameter test2."""t1_attr_1:strt1_attr_2:intt1_attr_3:datetimet1_attr4:list[str]=[]def_default(self,param1:str):print(param1)classTest2:"""test2 descriptiont2_attr_1 (str): optional parameter test1t2_attr_2 (int): optional parameter test2.t2_attr_3 (datatime): optional parameter test2.t2_attr_4 (list): optional parameter test2."""t2_attr_1:strt2_attr_2:intt2_attr_3:datetimet2_attr_4:List[str]=[]deft2_method1(self,**test1:Test1):returntest1deft2_method2(self,**test1:Test1):returntest1classTest5:def__init__(self,attr_construct_t5:str)->None:"""Args:attr_construct_t5 (str): This attribute is introduced in the constructor of Test5"""self.attr_construct_t5=attr_construct_t5classTest4:def__init__(self,attr_construct_t4:str,attr_t5:Test5)->None:"""Args:attr_construct_t4 (str): This attribute is introduced in the constructor of Test4"""self.attr_construct_t4=attr_construct_t4self.attr_t5=attr_t5classTest3:"""test3 descriptiont3_attr_1 (str): optional parameter test1t3_attr_2 (int): optional parameter test2.t3_attr_3 (datatime): optional parameter test2.t3_attr_4 (list): optional parameter test2."""t3_attr_1:strt3_attr_2:intt3_attr_3:datetimet3_attr_4:List[str]=[]deft3_method1(self,test1:Test4):"""Method 1 for subcommand3. This method contains an object as parameter.Args:test1 (Test4): Parameter as a class."""return{"test1":test1.attr_t5.attr_construct_t5}deft3_method2(self,test1:datetime):"""Method 2 for subcommand3.Args:test1 (datetime): A datetime"""print(test1)deft3_method3(self,test1):"""Method 3 for subcommand3Args:test1 (test1): attr1"""print(test1)deftest(x:str):"""Args:x (str): is an x parameter"""print(x)(back to top)Generate CLIThe following code shows how to generate the CLI given the classes created above.options={# Enable/disable the output processing. The automatically format of the executed method."enable_output_processing":True,# Enable/disable the argument that specify the format with which the user can specify a print format to the output processor."enable_format_argument":True,# Default format for the output processor"format":"json",# Enable/disable the argument that tells the program to output the result inside a file."enable_file_argument":True,# Enable/disable the argument that allows to search for elements inside a result that is a list of elements."enable_search_argument":True,# Enable/disable the argument that allows to hide the full list of optional arguments."enable_full_help_argument":False,# Enable/disable the argument that allows to set the log level to debug."enable_verbose_argument":True,# Configuration file where configuration of classes (attributes) will be stored between executions."configuration_file":"./configuration_file.json"}# Options per subcommandgenerate_arguments_options={"enable_format_argument":True,"format":"json","enable_file_argument":True,"enable_search_argument":True,"enable_full_help_argument":True,"enable_verbose_argument":True,# Enable/disable the generation of arguments from attributes of a class."enable_class_attributes_generator":True,# Enable/disable the generation of arguments from functions of a class."enable_class_functions_generator":False}# Create CLI class with the selected configuration.cli=Cli(**options)# Generate CLI arguments for Test classcli.generate_arguments(Test())# Geberate CLI arguments for the following dictionary.cli.generate_arguments({"subcommand1":(Test1()),"subcommand2":[(Test2(),generate_arguments_options)],"subcommand3":(Test3()),})# Obtain the arguments that are introduced in the cli as a dictionary.args=cli.parse()# print(args)# Execute the selected command in the cli.# If no arguments are introduced the function# you select in the CLI will be executed with# the arguments you have introduced in the CLI.cli.execute_command()(back to top)CLI resultsThe following logs show how the CLI was generated from the classes declared above.# python3 examples/example.pyusage:examples/example.py[-h][-ta1test_attr_1][-ta2test_attr_2]{t_method,subcommand1,subcommand2,subcommand3}...

positionalarguments:{t_method,subcommand1,subcommand2,subcommand3}Testclasst_methodAmethod1examplesubcommand1test1descriptionsubcommand2subcommand3test3description

options:-h,--helpshowthishelpmessageandexit-ta1test_attr_1,--ta1test_attr_1,--test_attr_1test_attr_1(str):optionalparametertest_attr_1-ta2test_attr_2,--ta2test_attr_2,--test_attr_2test_attr_2(str):optionalparametertest_attr_2.# python3 examples/example.py subcommand3 -husage:examples/example.pysubcommand3[-h][-ta4t3_attr_4[t3_attr_4...]][-ta1t3_attr_1][-ta2t3_attr_2][-ta3t3_attr_3]{t3_method1,t3_method2,t3_method3}...

positionalarguments:{t3_method1,t3_method2,t3_method3}t3_method1Method1forsubcommand3.Thismethodcontainsanobjectasparameter.t3_method2Method2forsubcommand3.t3_method3Method3forsubcommand3

options:-h,--helpshowthishelpmessageandexit-ta4t3_attr_4[t3_attr_4...],--ta4t3_attr_4[t3_attr_4...],--t3_attr_4t3_attr_4[t3_attr_4...](list):optionalparametertest2.-ta1t3_attr_1,--ta1t3_attr_1,--t3_attr_1t3_attr_1(str):optionalparametertest1-ta2t3_attr_2,--ta2t3_attr_2,--t3_attr_2t3_attr_2(int):optionalparametertest2.-ta3t3_attr_3,--ta3t3_attr_3,--t3_attr_3t3_attr_3(datatime):optionalparametertest2.# python3 examples/example.py subcommand3 t3_method1 -husage:examples/example.pysubcommand3t3_method1[-h][-f{json,table,raw}][-v][-ssearch][-aattribute[attribute...]]attr_construct_t4attr_construct_t5

positionalarguments:attr_construct_t4(str):ThisattributeisintroducedintheconstructorofTest4attr_construct_t5(str):ThisattributeisintroducedintheconstructorofTest5

options:-h,--helpshowthishelpmessageandexit-f{json,table,raw},--f{json,table,raw},--format{json,table,raw}Specifytheformatthatisgoingtobeusedasoutput-v,--v,--verboseSetthelogleveltodebug-ssearch,--ssearch,--searchsearchSearchinsideallvaluesofalist-aattribute[attribute...],--aattribute[attribute...],--attributeattribute[attribute...]Onlyprinttheattributesyouselect# python3 examples/example.py subcommand3 t3_method1 t4construct t5construct{"test1":"t5construct"}# python3 examples/example.py  t_method -husage:examples/example.pyt_method[-h][-f{json,table,raw}][-v][-ssearch][-aattribute[attribute...]][-ttest4][-tptatest5.parameter_test_attr2]test3

positionalarguments:test3(str):requiredparametertest3

options:-h,--helpshowthishelpmessageandexit-f{json,table,raw},--f{json,table,raw},--format{json,table,raw}Specifytheformatthatisgoingtobeusedasoutput-v,--v,--verboseSetthelogleveltodebug-ssearch,--ssearch,--searchsearchSearchinsideallvaluesofalist-aattribute[attribute...],--aattribute[attribute...],--attributeattribute[attribute...]Onlyprinttheattributesyouselect-ttest4,--ttest4,--test4test4(str,optional):optionalparametertest4.Defaultsto"test4".-tptatest5.parameter_test_attr2,--tptatest5.parameter_test_attr2,--test5.parameter_test_attr2test5.parameter_test_attr2# python3 examples/example.py -ta1 tt1 -ta2 tt2 t_method tt3 --t tt4 -tpta tt5 -f table+--------------------------------------------------------------+|Parameter_name|Parameter_value|+----------------+---------------------------------------------+|test_1|tt1||test_2|tt2||test3|tt3||test4|tt4||test5|{'test5':{'parameter_test_attr2':'tt5'...|+----------------+---------------------------------------------+# python3 examples/example.py -ta1 tt1 -ta2 tt2 t_method tt3 --t tt4 -tpta tt5 -f table+--------------------------------------------------------------+|Parameter_name|Parameter_value|+----------------+---------------------------------------------+|test_1|tt1||test_2|tt2||test3|tt3||test4|tt4||test5|{'test5':{'parameter_test_attr2':'tt5'...|+----------------+---------------------------------------------+# python3 examples/example.py anime_search -q naruto -f table+-------------------------------------------------------------------------------------------------+|Mal_id|Title|Genres|Score|+--------+---------------------------------------------+----------------------------------+-------+|20|Naruto|Action,Adventure,Fantasy|7.98||1735|Naruto:Shippuuden|Action,Adventure,Fantasy|8.25||34566|Boruto:NarutoNextGenerations|Action,Adventure,Fantasy|5.75||16870|TheLast:NarutotheMovie|Action,Adventure,Fantasy,Romance|7.78||28755|Boruto:NarutotheMovie|Action,Adventure,Fantasy|7.41||13667|Naruto:ShippuudenMovie6-RoadtoNin...|Action,Adventure,Fantasy|7.67||2472|Naruto:ShippuudenMovie1|Action,Adventure,Fantasy|7.29||442|NarutoMovie1:DaiKatsugeki!!YukiHim...|Action,Adventure,Fantasy|7.11||4437|Naruto:ShippuudenMovie2-Kizuna|Action,Adventure,Fantasy|7.28||8246|Naruto:ShippuudenMovie4-TheLostTo...|Action,Adventure,Fantasy|7.42||10589|Naruto:ShippuudenMovie5-BloodPriso...|Action,Adventure,Fantasy|7.45||936|NarutoMovie2:DaiGekitotsu!Maboroshi...|Action,Adventure,Fantasy|6.87||2144|NarutoMovie3:DaiKoufun!MikazukiJim...|Action,Adventure,Fantasy|6.91||6325|Naruto:ShippuudenMovie3-HinoIshi...|Action,Adventure,Fantasy|7.33||32365|Boruto:NarutotheMovie-NarutogaHok...|Action,Adventure,Fantasy|7.35||12979|NarutoSD:RockLeenoSeishunFull-Powe...|Action,Comedy|7.16||594|Naruto:TakigakurenoShitou-OregaEi...|Action,Adventure,Fantasy|6.76||761|Naruto:AkakiYotsubanoCloverwoSagas...|Adventure,Comedy|6.55||1074|NarutoNarutimateHero3:TsuiniGekitot...|Action|6.78||2248|Naruto:DaiKatsugeki!!YukiHimeShinob...|Action,Comedy,Fantasy|6.86||10686|Naruto:HonoonoChuuninShiken!Naruto...|Action,Adventure|7.17||19511|Naruto:Shippuuden-SunnySideBattle|Comedy,Fantasy,Gourmet|7.55||4134|Naruto:Shippuuden-Shippuu!"Konoha Ga... |              Action              | 7.14  || 10659  | Naruto Soyokazeden Movie: Naruto to Mash... |          Action,Comedy           | 6.96  ||  7367  |           Naruto: The Cross Roads           |          Action,Fantasy          | 6.79  |+--------+---------------------------------------------+----------------------------------+-------+(back to top)RoadmapAdded options to disable/enable class attributes arguments generation.Support for class with non-empty constructors.Support for a list of classes in JSON format.Support for a list of classes with non-empty constructors.Support for DateTime with the following formats 2022-12-20/00:00:20 and 2022-12-20Support for enumeration type. It will be interpreted as argparse "choices"._default method inside a class will be treated as the method that is going to be executed in the specified subparser.Generate a log file with last commands executed.Improve performance with argument prediction. Only generate the arguments that the program know that are introduced.Improve documentationAdd testsAdd an argument that supports writing into a file instead of printing in the terminal.Possibility to add custom arguments.Add decorators to change the behavior of the arguments generated.Add configuration file. The CLI can fetch/store the configuration for classes introduced as arguments in 'generate_arguments'Add cache. A cache decorator can be used to save the result between executions of a function for a given set of arguments during a given time.Add REST API support. A REST API decorator can be used to use an API using the python method parameters as input for generating the request.Add multiple output support. CSV and YAML.See theopen issuesfor a full list of proposed features (and known issues).(back to top)LicenseDistributed under the MIT License. SeeLICENSE.mdfor more information.(back to top)ContactProject Link:https://github.com/AlexSua/python-cli-generator(back to top)