PyInquirer icon indicating copy to clipboard operation
PyInquirer copied to clipboard

Feature Request: Callback for choices and input questions

Open craigh92 opened this issue 5 years ago • 5 comments

I often want to perform an action as a result of a prompt choice/input:

For example:

q = {
    'type' : 'list,
    'name' : 'action',
    'message' : 'choose an option',
    'choices' : [
        {
            'name' : 'foo',
            'disabled' : False
        },
        {
            'name' : 'bar',
            'disabled' : False
        }
   ]
}

def foo() : print("you chose foo!")
def bar() : print("you chose bar!")

a = prompt(q)
if a['action'] == 'foo':
    foo()
elif a['action'] == 'bar':
   bar()

As the number of options grows, and the prompts become more complex this can become messy, as you have to update the logic that handles the choice every time you change/add a choice.

It would be good if you could do something like:

q = {
    'type' : 'list,
    'name' : 'action',
    'message' : 'choose an option',
    'choices' : [
        {
            'name' : 'foo',
            'disabled' : False,
            'callback' : lambda : print("you chose foo!")
        },
        {
            'name' : 'bar',
            'disabled' : False
            'callback' : lambda : print("you chose bar!")
        }
   ]
}

a = prompt(q)

#The callback could be called automatically as a result of the choice, or an alternative design could be to call it with:
handle(a, q)  # This would call the appropriate callback depending on the answer 

This is better than the previous example because the callbacks are defined with the choices, so adding new behaviour to handle a new choice is easy.

The handle function can already be implemented now, without having to change any of the rest of the application. See below:

def handle(a, q):
    choicesList = q['choices']
        for opt in choicesList:
            if opt['name'] == a:
                opt['callback']()
# a similar function can be written for the case that a is a future, and not a string (when `return_asyncio_coroutine = True` is used)

But this relies on me being able to add the callback Dict item to the choices List. This currently happens to work, but as it is not an official feature I cannot guarantee that this will work with future versions of PyInquire. It would be good if the callback property could be officially supported.

It would also be good if I could do the same with different types of prompts, such as input. For example:

q = {
    'type' : 'input',
    'name' : 'value',
    'message' : "choose a value",
    'callback' : lambda val : print("you typed " + val)
}

a = prompt(q)

But unlike the choices example, this currently doesn't work and gives the error:

TypeError: create_prompt_application() got an unexpected keyword argument 'callback'

Again, it would be good if the callback function could be called (with the input value) after the user has entered the input. Again, this could happen automatically, or by using some kind of handle function.

What do you think of this idea?

craigh92 avatar Apr 24 '20 19:04 craigh92

I could create a fork / branch and assign myself to this if others think it is a useful feature?

craigh92 avatar Apr 25 '20 10:04 craigh92

I've gone ahead and made a fork, as this feature was easy to implement. A working example can be found here: https://github.com/craigh92/PyInquirer/blob/master/examples/callbacks.py

craigh92 avatar Apr 25 '20 12:04 craigh92

This looks good, I would go through it but I think we have something like this. @craigh92

CITGuru avatar Apr 25 '20 12:04 CITGuru

@CITGuru Thanks for your reply.

If that is the case, could you please let me know how this is currently done?

Also, here's a better example of how it could be used:

https://github.com/craigh92/PyInquirer/blob/master/examples/calculator.py

craigh92 avatar Apr 25 '20 18:04 craigh92

I will be looking into this, this is fairly easy. I hope I could get enough time

CITGuru avatar Jul 08 '20 08:07 CITGuru