Upgrade Your Python CLI with Questionary: Stop Your Scripts from Crashing Due to User Input Errors

Python tutorial - IT technology blog
Python tutorial - IT technology blog

A 2 AM Incident and the Fate of the input() Function

At exactly 2 AM, my phone buzzed incessantly. A critical production automation script had suddenly frozen, causing a chain reaction of delayed tasks. After 15 minutes of log checking, I discovered a ridiculously simple cause: a new colleague had used the basic input() function to request configuration parameters.

While running the terminal, the operator accidentally typed a strange character into the quantity field. Instead of showing an error, the “naive” script crashed immediately with a ValueError. The interface at the time was just a wall of white text—no guidance, no menu—forcing the operator to guess what to do next.

At that moment, I realized that if we keep clinging to default input functions, the system will eventually break due to human typos.

Why Traditional input() Is a Recipe for Disaster?

If you’re just writing scripts for personal use, input() might suffice. However, when you hand tools over to others or run them on production servers, it reveals three fatal weaknesses:

  • Lack of Validation: You have to write dozens of if-else lines just to check if the user entered a valid email format or an integer. In my experience, manual validation code can take up to 40% of a CLI script’s logic.
  • Poor User Experience (UX): No selection arrows, no checkboxes. A single misplaced space can ruin everything.
  • Spaghetti Code: The more questions you ask, the more your code looks like a mess of nested while True loops.

The Solution: From Manual Fixes to Specialized Libraries

Initially, I tried to patch things by writing wrapper functions. For example:

def get_integer_input(prompt):
    while True:
        try:
            return int(input(prompt))
        except ValueError:
            print("Error! You must enter an integer.")

This saved the script from crashing but still looked very amateur. I tried argparse or click. They are powerful for parsing flags, but they lack flexibility in step-by-step interactive Q&A.

Finally, I found Questionary. This library is built on top of prompt_toolkit, transforming dry Python scripts into real CLI toolsets with smooth menus and checkboxes.

Questionary – A Lifesaver for Modern CLIs

Installation is lightning fast with a single command:

pip install questionary

Here are three ways I commonly use it to replace the outdated input() function.

1. Creating a Selection Menu (Select)

Instead of forcing users to type “1”, “2”, or “Yes/No”, let them choose using arrow keys. This completely eliminates typos.

import questionary

action = questionary.select(
    "Select the action you want to perform:",
    choices=[
        "Check server status",
        "Backup data",
        "Restart service",
        "Exit"
    ]
).ask()

print(f"Executing: {action}")

2. Multi-selection (Checkbox)

This feature is extremely useful for configuring multiple options. Users simply use the Space key to mark items and Enter to confirm.

features = questionary.checkbox(
    "Select modules to install:",
    choices=["Nginx", "PostgreSQL", "Redis", "Docker"]
).ask()

print(f"Will install: {', '.join(features)}")

3. Instant Data Constraints (Validation)

This is the most valuable feature. Questionary allows data validation while the user is typing. If the format is wrong, they can’t press Enter and will receive an immediate error message.

import re

def validate_ip(text):
    pattern = r"^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$"
    if re.match(pattern, text):
        return True
    return "Invalid IP! (Example: 192.168.1.1)"

ip_address = questionary.text(
    "Enter target server IP:",
    validate=validate_ip
).ask()

Pro tip: When you need to quickly test complex regex, I often use the regex tester at toolcraft.app to verify logic before putting it into code.

Real-world Application: Server Management Script

See the power of Questionary when integrated into a practical management script. I’ll add some color for a more professional look.

import questionary
from prompt_toolkit.styles import Style

custom_style = Style([
    ('qmark', 'fg:#673ab7 bold'),
    ('question', 'bold'),
    ('answer', 'fg:#f44336 bold'),
    ('pointer', 'fg:#673ab7 bold'),
    ('highlighted', 'fg:#673ab7 bold'),
    ('selected', 'fg:#cc5454'),
])

def main():
    print("--- MANAGEMENT SYSTEM V1.0 ---")
    
    env = questionary.select(
        "Select environment:",
        choices=["Staging", "Production", "Local"],
        style=custom_style
    ).ask()

    if env == "Production":
        sure = questionary.confirm(
            "WARNING: You are affecting Production. Continue?",
            default=False
        ).ask()
        if not sure: return

    service_name = questionary.text(
        "Service Name (e.g., nginx):",
        validate=lambda text: True if len(text) > 0 else "Cannot be empty!"
    ).ask()

    task = questionary.select(
        f"Action for {service_name}:",
        choices=["Restart", "Stop", "Status"]
    ).ask()

    print(f"\n[OK] Processing {task} for {service_name} on {env}...")

if __name__ == "__main__":
    main()

A Perspective from the Engineering Room

Since switching to Questionary, I haven’t been woken up in the middle of the night due to silly input errors. The operations team is also more enthusiastic because the CLI interface now looks “pro” and is as easy to use as actual software.

The lesson learned: Never fully trust user input. Limit their choices with menus and validate everything possible. Questionary doesn’t just make the code cleaner; it’s a solid insurance policy for your system.

If you’re building automation tools or internal utilities, try integrating Questionary right away. The results will definitely surprise you.

Share: