Create Python CLI with select interface

Question:

I’d like to create a Python CLI with an item selection interface that allows users to choose an item from a list. Something like:

Select a fruit (up/down to select and enter to confirm):
[x] Apple
[ ] Banana
[ ] Orange

I’d like users to be able to change their selection using the up/down arrows and press Enter to confirm.

Does a Python module exist with this functionality? I tried searching but couldn’t find exactly what I wanted.

The select-shell Node.js package does exactly what I want.

The pick Python module does what I want, but it uses curses and opens up a simple GUI. I would like to avoid creating a GUI and keep all output in the terminal: this likely requires updating lines displayed to the terminal.

I’m currently using click but I don’t believe it supports this functionality. I’m not sure how exactly to input this sort of feature using cmd/readline and would appreciate any insight.

Asked By: Dan Zheng

||

Answers:

After a bit of searching, I found two libraries that met my needs!

The first is python-inquirer, a Python port of Inquirer.js, a CLI library used by projects like Yeoman. I found this library to have a really nice API (built on top of blessings) but lacks polish when it comes to design/features.

The second (which I will be using) is whaaaaat, another Python port of Inquirer. This library offers functionality much closer to the original Inquirer.js and is exactly what I needed. The API is less clean than that of python-inquirer, however.

Examples:

python-inquirer example:

from pprint import pprint
import inquirer

questions = [
    inquirer.List(
        "size",
        message="What size do you need?",
        choices=["Jumbo", "Large", "Standard", "Medium", "Small", "Micro"],
    ),
]

answers = inquirer.prompt(questions)
pprint(answers)

whaaaaat example:

from whaaaaat import prompt, print_json, Separator

questions = [
    {
        "type": "list",
        "name": "theme",
        "message": "What do you want to do?",
        "choices": [
            "Order a pizza",
            "Make a reservation",
            Separator(),
            "Ask for opening hours",
            {"name": "Contact support", "disabled": "Unavailable at this time"},
            "Talk to the receptionist",
        ],
    },
    {
        "type": "list",
        "name": "size",
        "message": "What size do you need?",
        "choices": ["Jumbo", "Large", "Standard", "Medium", "Small", "Micro"],
        "filter": lambda val: val.lower(),
    },
]

answers = prompt(questions)
print_json(answers)
Answered By: Dan Zheng

For simple choices you can use the simple-term-menu package. It is simple, small and has no dependencies to other packages.

Example:

from simple_term_menu import TerminalMenu

terminal_menu = TerminalMenu(["entry 1", "entry 2", "entry 3"])
choice_index = terminal_menu.show()

simple-term-menu

Answered By: IngoMeyer

You mention the click package, and mention that you are not sure how to implement this feature. It seems like choice-options are the intended way to implement single choice questions.

The generated output will not be nearly as nice as in some of the other packages mentioned in the other answers. However, click is well maintained, active, and works on both UNIX and WIN – critical arguments if you are planning to release a library.

Answered By: miwe