Package: inquirer-executor
python-inquirer-executorThis is a wrapper aroundpython-inquirer. From that project's README:So,Inquirershould ease the process of asking end userquestions,parsing,validatinganswers, managinghierarchical promptsand providingerror feedback.This package extends this thought by building classes on top of it to create prompts that will automatically call one or more functions corresponding to the user's choice, while keeping your code nice, tidy and readable. This is achieved by facilitating the docstring of your functions as user-facing representaion of these functions.How to useInstallationpip install inquirer-executorAs the whole code is contained in a single file and has only one dependecy (the built-uponinquirerpackage), you can also manually copy/paste this (or parts of it) into your project, if that is how you roll.Creating a single-choice question (List)frominquirer_executorimportInquirerExecutorListquestion=InquirerExecutorList("Question you want to ask the user?",list_of_functions)Thelist_of_functionscan be any iterable that is exlusively composed of function types. The class will generate the question from the string you provided as the first argument and a list of functions that will be presented to the user as selectable options. These options will be represented by the given function's correspondingdocstring.Examplefrominquirer_executorimportInquirerExecutorListdefprint_one():"""One."""print("one")defprint_two():"""Two."""print("two")defprint_three():"""Three."""print("three")question=InquirerExecutorList("Of the given choices, how many puppies is best?",[print_one,print_two,print_three])This will create the instance of the question. You now haveprompt_user()andprompt_and_execute()methods at your disposal. Once you have used theprompt_user()method, and the user has provided an answer, you can also:use thefind_function()method to return the corresponding function to the user's answeraccess the instancesanswervalue to read the user's answer (the docstring they have selectedasstring)use theexecute()method to execute the users choice at a later point (the function returns the return value of the function called)For now though, we are just going to useprompt_and_execute()to see the results right away:question.prompt_and_execute()Which gives us this output:[?] Of the given choices, how many puppies is best?: Three.
   One.
   Two.
 > Three.

threeThe user has chosen from the docstrings representing the functions and the function got executed, printing 'three'. Neat.Creating a multiple-choice question (Checkbox)frominquirer_executorimportInquirerExecutorCheckboxquestion=InquirerExecutorCheckbox("Question you want to ask the user?",list_of_functions)Initializing this works exactly like it does for theInquirerExecutorListclass. The difference is the existence of theexecution_stackvalue, which is a list that contains all the options the user has checked. So this class will never return a single function, always a list of functions.Examplefrominquirer_executorimportInquirerExecutorCheckboxdefprint_puppies():"""Puppies."""print("puppies")defprint_rocks():"""Rocks."""print("rocks")defprint_kittens():"""Kittens."""print("kittens")question2=InquirerExecutorCheckbox("Of the given choices, which ones are furry and cuddly?",[print_puppies,print_rocks,print_kittens])This will create the instance of the question. Again, you now haveprompt_user()andprompt_and_execute()methods at your disposal. Once you have generated an answer with theprompt_user()method, you can:use thefind_functions()(mind the plural 's')method to return the corresponding list of functions to the users answeraccess the instancesanswervalue to read the user's answers (a list of the docstrings they have selected)use theexecute()method to execute the users choices at a later point (the function itself returns a list of the functions return values)For now though, we are again just going to useprompt_and_execute()to get this result:[?] Of the given choices, which one's are furry and cuddly?: 
   X Puppies.
   o Rocks.
 > X Kittens.

puppies
kittensThe user has checked options one and three and the corresponing functions got called.Keep in mind that in this caseprompt_and_execute()always returnsa list.Mutating the question after instantiationAddingThere are two ways to add functions to InquirerExecutor instances after they have been created. The first one is the+operator, that will append the added function to the end of the choices associated with the question.The second one is theinsert(index, value)method, that will insert avalue(which in this case has to be a function type) atindex. Use it like you are used to from thelisttype.SettingYou can also set new values as you are used to likeinstance[0]=new_valuewhere again,new_valueneeds to be a function type.ReorderingInquirerExecutor provides areorder(indices)method where indices is a list of numbers that represent the new order, so when given[2, 0, 1], the original index 0 would be moved to index 2, original index 1 moved to 0 and 2 to 1.You can also use thereverse()method, which also works like you are used to fromlisttypes.RemovingInquirerExecutor provides aremove(value)method, that exceptseitherafunction nameas stringor an indexas number as it'svalueargument. In both cases, the matching function is removed from the choices presented to the user.Passing argumentsYou can of course pass whatever arguments you like to your functions. Just keep in mind, that potentially any and every function in the list will be called, so all of your functionsmustaccept thesameparameters. To prevent possible errors down the road, InquirerExecuterenforces thisat creation time and will throw anAssertionErrorif the accepted parameters of your functions don't match.ThemingYou can usepython-inquirer's built-in theming optionswith the key difference that you have toinstantiatethe themebefore using it. You then pass theinstanceto theprompt_user()orprompt_and_execute()methods using thethemekeyword,notthe theme class.Dynamically setting docstringsThis package makes it sometimes necessary - or at least preferable - to generate docstrings dynamically. This could be achieved by defining the docstring after you define the function like so:name=input("What is your name?")defsome_function():"""Can't display the name variable here."""returnnamesome_function.__doc__="Returns your name:{}".format(name)This is possible and valid as long as you are dealing withnormalfunctions. As soon as you are trying to do this with methods inside a class, Python will raise an error telling you that the__doc__attribute of methods is not writable.For this reason InquirerExecutor provides a decorator nameddynamic_docstring_decoratorthat can be used to set dynamic docstrings. The above code rewritten with the decorator would look like this:frominquirer_executorimportdynamic_docstring_decoratorname=input("What is your name?")@dynamic_docstring_decorator("Returns your name:{}".format(name))defsome_function():"""Can't display the name variable here."""# This docstring gets overwrittenreturnnameMuch nicer and cleaner!Using this as part of a whole catalogue of questionsDepending on what you are trying to achieve you might want to organize the questions yourself in a manner that fits your use case best. For simple applications, InquirerExecutor provides aQuestionsCatalogueclass, that can be instantiated with a n iterable type that consists of eitherinquirerorinquirer_executorobjects.TheQuestionsCataloguehandles these objects so they feel just like a list of functions and equips you with it'sprompt_all()method. This method returns a tuple of two items: 1) A dictionairy of all the answers given to the Text, Path, etc. prompts that you may have used directly frominquirerand 2) a list of functions the user has chosen from single- and multiple-choice questions in theQuestionsCatalogue. In order to keep everything human-readable and easy to reason about, this class provides no way of directly calling all functions, you need to call them yourself however and whenever you see fit.ExamplefrominquirerimportTextfrominquirer_executorimport(InquirerExecutorListasInqExList,InquirerExecutorCheckboxasInqExCheckbox,QuestionsCatalogue,)defreturn_one():"""Return 1"""return1defreturn_two():"""Return 2"""return2defreturn_three():"""Return 3"""return3defreturn_four():"""Return 4"""return4defreturn_five():"""Return 5"""return5inqex_checkbox=InqExCheckbox.from_iterable("What do you want to return?",[return_one,return_two])inqex_list=InqExList.from_iterable("What do you want to return?",[return_three,return_four,return_five])text_question_first_name=Text("first_name",message="What's your first name")text_question_last_name=Text("last_name",message="What's your last name")questions_catalogue=QuestionsCatalogue([inqex_checkbox,inqex_list,text_question_first_name,text_question_last_name])print(questions_catalogue.prompt_all())Assuming the user checked both options at the checkbox and chose "Return 4" at the single choice question and he is a billionaire from Gotham City the above code would produce something like this:[?] What do you want to return?: 
   X Return 1
 > X Return 2

[?] What do you want to return?: Return 4
   Return 3
 > Return 4
   Return 5

[?] What's your first name: Bruce
[?] What's your last name: Wayne
({'first_name': 'Bruce', 'last_name': 'Wayne'}, [<function return_one at 0x7f516964de18>, <function return_two at 0x7f51663a4d90>, <function return_four at 0x7f516611bd08>])ExamplesIf you would like to see this package applied in a bit more complex examples, please do consult theexamples folderof the repository. These small projects are structured with human-readability in mind and are heavily commented to guide you through the code to get you working with this package in no time.Raison D'êtreI needed this myself.ContributingContributions and improvements are very welcome. Please write a test for your code contribution and use theBlack code formatterwhen editing the code in this project.If you have played around with the package and you think what you have created would make a good example project, I would absolutely love to merge it into the examples folder, please make sure to comment your code so others can understand what you are doing.LicenseCopyright (c) 2019Konstantin Kovar, based onpython-inquirer, by Miguel Ángel García (@magmax9).Licensed under theMIT license.