pinq is a production-grade, 100% complete Python binding for the Rust inquire CLI prompt library. It provides an idiomatic Python interface to create beautiful, interactive command-line prompts across all platforms.
✨ Complete API Coverage - Every public type, function, and configuration from inquire is exposed in Python
🎨 Interactive Prompts - Text input, selections, multi-select, confirmations, passwords, dates, and more
⚡ Cross-Platform - Works perfectly on Linux, macOS, and Windows (including WSL)
🔧 Fully Configurable - Defaults, help messages, page sizes, custom formatting
🛡️ Type Safe - Full Python type hints for IDE support and type checking
🚀 Production Ready - Built with PyO3, compiled to native code via Maturin
🎯 Idiomatic Python - Builder pattern, Python enums, exception-based error handling
pip install pinqimportpinqname=pinq.prompt_text("What is your name? ")
print(f"Hello, {name}!")importpinqifpinq.prompt_confirmation("Continue? "):
print("Continuing...")
else:
print("Canceled.")importpinqlanguages= ["Python", "Rust", "Go", "JavaScript"]
choice=pinq.SelectPrompt("Pick a language:", languages).prompt()
print(f"You chose: {choice}")importpinqoptions= ["Apples", "Bananas", "Carrots", "Dates"]
selected=pinq.MultiSelectPrompt("Select fruits:", options).prompt()
print(f"Selected: {', '.join(selected)}")importpinqage=pinq.prompt_int("Your age: ")
price=pinq.prompt_float("Price: $")importpinqpassword=pinq.PasswordPrompt("Enter password: ").prompt()importpinqdate=pinq.prompt_date("Select a date: ")
print(f"Selected: {date}") # YYYY-MM-DD formatimportpinqtext=pinq.EditorPrompt("Write a message: ").prompt()All prompts support method chaining for advanced configuration:
importpinqusername= (pinq.TextPrompt("Username: ")
.with_default("admin")
.with_help_message("System administrator")
.prompt())Text Prompts:
.with_default(value)- Default value.with_help_message(text)- Help text.with_page_size(n)- Pagination size
Select/MultiSelect:
.with_default(index)/.with_defaults(indices)- Default selections.with_help_message(text)- Help text.with_page_size(n)- Items per page
All Prompts:
.with_help_message(text)- Display help below prompt.prompt_skippable()- Allow ESC to skip (returnsNone)
| Class | Purpose | Example |
|---|---|---|
TextPrompt | Free text input | Username, email |
ConfirmPrompt | Yes/no question | Delete confirmation |
PasswordPrompt | Hidden text input | Password |
SelectPrompt | Choose one from list | Pick an option |
MultiSelectPrompt | Choose multiple from list | Select features |
IntPrompt | Integer input | Count, port number |
FloatPrompt | Float input | Price, percentage |
DateSelectPrompt | Interactive calendar | Meeting date |
EditorPrompt | Multi-line editor | Long form text |
For quick prompts without configuration:
importpinqname=pinq.prompt_text("Name: ")
confirm=pinq.prompt_confirmation("Continue? ")
age=pinq.prompt_int("Age: ")
price=pinq.prompt_float("Price: ")
password=pinq.prompt_secret("Password: ")
date=pinq.prompt_date("Date: ")All prompts can raise RuntimeError for:
- NotTTY - Not running in a terminal
- IOError - Terminal communication error
- OperationCanceled - User pressed Ctrl+C or ESC
- InvalidConfiguration - Invalid prompt setup
- Parse errors - Invalid input for typed prompts
importpinqtry:
age=pinq.prompt_int("Age: ")
exceptRuntimeErrorase:
print(f"Error: {e}")Use .prompt_skippable() to allow users to skip with ESC:
importpinqoptional_comment= (pinq.TextPrompt("Comment (optional): ")
.prompt_skippable())
ifoptional_commentisNone:
print("Skipped")
else:
print(f"Comment: {optional_comment}")Full documentation available in the docs/ directory:
- overview.md - Architecture and design
- classes.md - All prompt classes and methods
- functions.md - One-liner convenience functions
- builders.md - Builder pattern guide
- enums.md - Enum types
- errors.md - Error handling reference
- examples.md - Real-world usage examples
importpinqusername=pinq.prompt_text("Username: ")
password=pinq.PasswordPrompt("Password: ").prompt()
country=pinq.SelectPrompt("Country:", ["USA", "Canada", "UK"]).prompt()
newsletter=pinq.prompt_confirmation("Subscribe? ")
print(f"Registered: {username} from {country}")importpinqport= (pinq.IntPrompt("Port: ")
.with_default(3000)
.prompt())
features= (pinq.MultiSelectPrompt("Enable:",
["Auth", "Cache", "Logging"])
.with_defaults([0, 2])
.prompt())
env=pinq.SelectPrompt("Environment:",
["dev", "staging", "prod"]).prompt()
print(f"Config: port={port}, features={features}, env={env}")importpinqname=pinq.prompt_text("Name: ")
rating=pinq.SelectPrompt("Rating:",
["Poor", "Fair", "Good", "Great"]).prompt()
feedback=pinq.EditorPrompt("Feedback:").prompt_skippable()
print(f"Survey from {name}: {rating}")
iffeedback:
print(f"Feedback: {feedback}")- ✅ Linux
- ✅ macOS
- ✅ Windows
- ✅ WSL (Windows Subsystem for Linux)
Uses the default crossterm backend which works reliably everywhere.
All types and functions are documented with full docstrings accessible via Python's help():
importpinqhelp(pinq.SelectPrompt)
help(pinq.prompt_int)- Compiled to native code - PyO3 + Maturin for maximum speed
- Minimal overhead - Direct FFI to Rust implementation
- No Python GIL - Concurrent use possible
- pinq: 0.1.0
- inquire: 0.7
- Python: 3.8+
MIT License - Same as inquire
This is a complete, production-ready binding. For bugs or feature requests related to the core prompt functionality, please refer to the inquire repository.
- inquire - The original Rust library
- PyO3 - Python bindings for Rust
- Maturin - Python package build tool
This occurs when running in a non-interactive environment:
importsysifnotsys.stdin.isatty():
print("Cannot use interactive prompts in non-TTY mode")Pressing Ctrl+C raises RuntimeError with message "Operation canceled by user":
try:
result=pinq.prompt_text("Input: ")
exceptRuntimeErrorase:
if"canceled"instr(e):
print("User interrupted")Mock pinq functions in unit tests:
fromunittest.mockimportpatch@patch('pinq.prompt_text')deftest_my_function(mock_prompt):
mock_prompt.return_value="test value"# ... test code ...Built with:
Start building interactive CLI applications with Python today! 🚀

