When building a command line application (CLI), developers use CLI Option Prompt [typer]. However, if you need more interactivity and simplicity on the terminal, you are likely to use typer.prompt().
Like every library in development, we have to pause and consider: How much control are we really giving up when we depend on typer.prompt() to make our CLI more interactive?
I have been building a CLI application to better track and predict cervical cancer in women. The Typer library was great in creating visually-appealing output on the terminal, until I needed to enable a filtering option. I wanted to give my user the option of filtering health profiles based on a single ID or leave blank to provide an unfiltered output. However, in my testing, I realized that by pressing ENTER without inputting any value, typer.prompt() re-prompted me to input a value, instead of accepting an empty string. I got into a loop of prompts.
Despite expecting user_id to be "", the prompt came up again!
As usual, I thought that my logic was wrong, so I went back different 'best practices' in CLI:
- I began by guarding user_id by changing from:
user_id = typer.prompt("Filter by user ID (or leave blank)").strip() or None
list_all_profiles(user_id=int(user_id) if user_id else None)
To:
user_input = typer.prompt("Filter by user ID (or leave blank)").strip()
user_id = int(user_input) if user_input else None
list_all_profiles(user_id=user_id)
- After option 1 failed, I tried added isdigit() to eliminate catch non-numeric issues, but that failed, and the loop continued.
- Next, I wrapped the code in a try-except block with return values to prevent re-looping due to unexpected errors and value-errors, but I kept incurring an endless loop of re-prompting.
Until I came across an 8-year old Stack Overflow issue [Stack Overflow] about Python's Click limit with empty prompts. While the issue had Click's syntax, I decided to replicate it on typer.prompt:
elif choice == '2':
try:
typer.secho("Leave filters blank to view all profiles.", fg=typer.colors.BRIGHT_BLACK)
user_input = typer.prompt("Filter by user ID (or leave blank)", default="").strip()
user_id = int(user_input) if user_input else None
list_all_profiles(user_id=user_id)
except ValueError:
typer.secho("Invalid filter values. Please use numbers or leave blank.", fg=typer.colors.RED)
except Exception as e:
typer.secho(f"Unexpected error: {e}", fg=typer.colors.RED)
A Call to Action
Although this Prompt behavior in Typer is logical once comprehended, it is not obvious, especially for beginners. Therefore, the Prompt's interactivity would improve by:
- Typer providing advanced documentation on prompt() behavior in different scenarios.
- Providing alternatives, especially when defaults are not set.
- Clear warnings or handling of empty inputs in CLIs.
Are you exploring CLIs and Typer? Have you ran into this challenge and have ways of enhancing prompt()? Consider visiting and contributing to their GitHub repository [fastApi/typer].
Like any other bug, this prompt() problem reminded me of how all libraries have simple tools that while they simplify our codes, they demand an understanding of underlying principles.
I hope my journey with Typer and empty inputs saves someone and builds to the tool's best practices.
Top comments (0)