Simplify the creation of GUI elements in terminals and Jupyter Notebooks
Project description
EZInput
Write once, run everywhere - Create interactive GUIs that work seamlessly in both Jupyter notebooks and terminal environments with the exact same code.
EZInput is a Python library that simplifies creating user interfaces for data science, image analysis, and computational research. Whether you're prototyping in a notebook or deploying a command-line tool, your UI code remains identical.
✨ Key Features
- 🔄 Unified API: Same code works in Jupyter notebooks (.ipynb) and terminal scripts (.py)
- 📋 Copy-Pastable: Move code between notebooks and scripts without modification
- 💾 Auto-Persistence: Widget values are automatically saved and restored between sessions
- 🎯 Type-Safe: Validated inputs with type checking (int, float, text, paths, etc.)
- 🎨 Rich Widgets: Sliders, dropdowns, text inputs, file pickers, and more
- ⚡ Zero Boilerplate: No environment detection code needed - it just works
Note: This project is currently in alpha stage and may undergo API changes.
🎯 Perfect For
- Image analysis pipelines requiring user parameters
- Data science workflows with interactive configuration
- Research tools that need both notebook and CLI interfaces
- Teaching and tutorials with reproducible parameter sets
📦 Installation
Install EZInput using pip:
pip install ezinput
For development with all optional dependencies:
pip install ezinput[all]
Requirements
- Python >= 3.9
- Dependencies are automatically installed:
ipywidgetsandipyfilechooserfor Jupyter notebooksprompt-toolkitfor terminal interfacespyyamlfor configuration persistence
🚀 Quick Start
The Simplest Example
from ezinput import EZInput
# Create a GUI (works in both Jupyter and terminal!)
gui = EZInput("my_app")
# Add widgets - order of adding determines display order
name = gui.add_text("name", "Enter your name:")
age = gui.add_int_range("age", "Select age:", 18, 100)
confirm = gui.add_check("confirm", "Proceed with analysis?")
# In Jupyter: display the widgets
gui.show()
# Access values
print(f"Hello {name.value}, you are {age.value} years old")
if confirm.value:
print("Starting analysis...")
Running Jupyter Notebooks from Terminal
Execute notebooks as scripts using the ezinput command:
# Run a notebook from terminal
ezinput my_notebook.ipynb
# The notebook will execute with terminal-style prompts
# for all EZInput widgets
This is perfect for:
- Running analysis pipelines in batch mode
- Deploying notebook-based tools as CLI applications
- CI/CD integration
💡 Copy-Paste Friendly: This exact code works in both:
- Jupyter notebooks (.ipynb files) - displays interactive widgets
- Terminal scripts (.py files) - shows interactive prompts
Run in terminal with:
python my_script.py
Real-World Example: Image Analysis
Here's a complete example for an image analysis pipeline:
from ezinput import EZInput
import numpy as np
# One EZInput instance per analysis task recommended
gui = EZInput("image_analysis_v1")
# Configuration section
gui.add_label(value="=== Image Processing Parameters ===")
input_file = gui.add_text("input", "Input image path:",
placeholder="/path/to/image.tif")
threshold = gui.add_float_range("threshold", "Detection threshold:",
0.0, 1.0)
min_size = gui.add_int_range("min_size", "Minimum object size (pixels):",
10, 1000)
gui.add_label(value="=== Output Options ===")
save_results = gui.add_check("save", "Save results to disk?")
output_format = gui.add_dropdown("format", ["PNG", "TIFF", "JPEG"],
"Output format:")
# Display GUI (in Jupyter) or collect inputs (in terminal)
gui.show()
# Your analysis code using the values
def run_analysis(values):
"""Process image with user-provided parameters."""
print(f"Processing {values['input'].value}")
print(f"Using threshold: {values['threshold'].value}")
print(f"Minimum size: {values['min_size'].value}")
# Your image processing code here
# ...
if values['save'].value:
print(f"Saving as {values['format'].value}")
# Add a callback button (in Jupyter: creates button, in terminal: executes after show())
gui.add_callback("process", run_analysis, gui.get_values(),
description="Run Analysis")
Key Points:
- Widget tags (like
"input","threshold") must be unique within each GUI instance - Create one
EZInputinstance per analysis task or computational pipeline - The order you add widgets is the order they appear on screen
- Use
remember_value=Trueparameter on widgets to persist values between runs
Terminal vs Jupyter: Same Code, Different Experience
In Jupyter Notebook:
- Widgets appear as interactive UI elements
- Sliders, dropdowns, and buttons are fully visual
- Call
gui.show()to display the interface
In Terminal:
- Interactive prompts appear sequentially
- Type-validated input with autocomplete
- Press Enter to submit each value
- Run with:
python your_script.py
📚 Core Concepts
1. Automatic Environment Detection
EZInput automatically detects whether it's running in Jupyter or terminal:
from ezinput import EZInput
# No environment detection code needed!
gui = EZInput("my_app")
# Or import specific versions if needed:
from ezinput import EZInputJupyter # Jupyter-specific
from ezinput import EZInputPrompt # Terminal-specific
2. Value Persistence & Priority
Values are automatically saved to ~/.ezinput/{title}.yml. Priority order:
- Loaded parameters (from
load_parameters()) - Remembered values (from previous runs, if
remember_value=Trueparameter) - Explicit defaults (passed via
default=parameter) - Widget defaults (empty string, 0, False, etc.)
# Values automatically persist when remember_value=True (default for most widgets)
gui = EZInput("my_app")
age = gui.add_int_range("age", "Age:", 0, 120, remember_value=True)
# Next time: shows the previously entered value!
# Load from specific configuration file
gui = EZInput("my_app")
gui.load_parameters("experiment_config.yml")
# Or save current values to share
gui.save_parameters("my_optimal_params.yml")
3. Configuration Files
Create shareable configuration files:
gui = EZInput("my_analysis")
# ... add widgets and collect values ...
# Save current values
gui.save_parameters("my_config.yml") # Explicit filename
# or
gui.save_parameters("") # Auto-named: my_analysis_parameters.yml
# Share this file with colleagues!
# They can load it:
gui2 = EZInput("my_analysis", params_file="my_config.yml")
Config file location:
- Explicit saves: wherever you specify
- Auto-saved settings:
~/.ezinput/{title}.yml
Resetting to defaults:
# Clear all remembered values - returns widgets to original defaults
gui.restore_defaults()
# ⚠️ Important: Re-run your cell (Jupyter) or script (terminal) to see the reset take effect
# The method removes the memory file but doesn't immediately change displayed widgets
🎨 Available Widgets
All widgets work identically in Jupyter and terminal. Here's the complete reference:
Text Input Widgets
| Widget | Description | Example |
|---|---|---|
add_text() |
Single-line text input | gui.add_text("name", "Your name:") |
add_text_area() |
Multi-line text input | gui.add_text_area("notes", "Comments:") |
# Text input with placeholder
email = gui.add_text("email", "Email address:",
placeholder="user@example.com")
# Multi-line text area
notes = gui.add_text_area("description", "Project description:",
placeholder="Enter detailed description...")
Numeric Input Widgets
| Widget | Description | Example |
|---|---|---|
add_int_range() |
Integer slider/input with bounds | gui.add_int_range("count", "Count:", 1, 100) |
add_float_range() |
Float slider/input with bounds | gui.add_float_range("alpha", "Alpha:", 0.0, 1.0) |
add_int_text() |
Integer input (no bounds) | gui.add_int_text("age", "Age:") |
add_float_text() |
Float input (no bounds) | gui.add_float_text("weight", "Weight:") |
add_bounded_int_text() |
Integer input with validation | gui.add_bounded_int_text("percent", "%:", 0, 100) |
add_bounded_float_text() |
Float input with validation | gui.add_bounded_float_text("ratio", "Ratio:", 0.0, 1.0) |
# Slider-style (Jupyter) or validated prompt (terminal)
iterations = gui.add_int_range("iter", "Iterations:", 10, 1000)
# Free-form number input
temperature = gui.add_float_text("temp", "Temperature (°C):")
# Bounded input with automatic clamping
percentage = gui.add_bounded_int_text("coverage", "Coverage %:", 0, 100)
Selection Widgets
| Widget | Description | Example |
|---|---|---|
add_check() |
Boolean yes/no or checkbox | gui.add_check("verbose", "Enable verbose output?") |
add_dropdown() |
Single selection from list | gui.add_dropdown("method", ["A", "B", "C"], "Method:") |
# Boolean checkbox (Jupyter) or yes/no prompt (terminal)
debug = gui.add_check("debug", "Enable debug mode?")
# Dropdown with autocomplete in terminal
algorithm = gui.add_dropdown("algo",
["linear", "rbf", "polynomial"],
"Interpolation method:")
File & Path Widgets
| Widget | Environment | Description |
|---|---|---|
add_path_completer() |
Terminal only | Path input with autocomplete |
add_file_upload() |
Jupyter only | Visual file picker |
# Terminal: autocomplete-enabled path input
input_file = gui.add_path_completer("input", "Select input file:")
# Jupyter: visual file browser
input_file = gui.add_file_upload("input", accept="*.tif")
Display Widgets
| Widget | Description | Example |
|---|---|---|
add_label() |
Static text/header | gui.add_label(value="=== Settings ===") |
add_output() |
Output display area (Jupyter) | gui.add_output("results") |
add_HTML() |
Rich HTML content (Jupyter only) | gui.add_HTML("info", "<b>Note:</b> ...") |
# Section headers
gui.add_label(value="=== Input Parameters ===")
# Output area for results (Jupyter)
gui.add_output("results")
with gui["results"]:
print("Analysis complete!")
# Rich formatting (Jupyter only)
gui.add_HTML("warning", '<p style="color:red">⚠️ Experimental feature</p>')
Callback & Actions
# add_callback ensures naming consistency between Jupyter and terminal
def process_data(values):
"""Process data with current parameter values."""
threshold = values["threshold"].value
method = values["method"].value
print(f"Processing with {method} at threshold {threshold}")
# Your processing code here...
# In Jupyter: creates a button
# In terminal: executes immediately
gui.add_callback("run", process_data, gui.get_values(),
description="Start Processing")
Why add_callback?
The name maintains API consistency between Jupyter (button-based) and terminal (immediate execution) interfaces.
💡 Best Practices
1. Unique Widget Tags
# ✅ Good: unique tags
gui.add_text("input_file", "File:")
gui.add_text("output_file", "Output:")
# ❌ Bad: duplicate tags
gui.add_text("file", "File:")
gui.add_text("file", "Output:") # Overwrites the first one!
2. One GUI Per Task
# ✅ Good: separate GUIs for different analyses
preprocessing_gui = EZInput("preprocessing_v1")
analysis_gui = EZInput("main_analysis_v2")
# ❌ Avoid: reusing the same GUI instance for different purposes
gui = EZInput("multi_purpose") # Config files may conflict
3. Meaningful Titles
# ✅ Good: descriptive, versioned titles
gui = EZInput("cell_segmentation_v2")
gui = EZInput("image_denoising_2024")
# ✅ Also good: user/project specific
gui = EZInput("john_experiment_setup")
# ❌ Avoid: generic titles that may conflict
gui = EZInput("test")
gui = EZInput("gui")
4. Display Order Matters
# Widgets appear in the order you add them
gui = EZInput("my_app")
# This order...
gui.add_label(value="=== Step 1 ===")
gui.add_text("name", "Name:")
gui.add_int_range("age", "Age:", 0, 120)
gui.add_label(value="=== Step 2 ===")
gui.add_check("confirm", "Confirm?")
# ...is the order users see them in
gui.show()
📖 Documentation
- Full Documentation: Comprehensive guides and API reference
- Widget Gallery: Interactive examples of all widgets
- Tutorials: Step-by-step guides
- API Reference: Detailed method documentation
🤝 Contributing
Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.
📄 License
This project is licensed under the MIT License - see the LICENSE.txt file for details.
Made with ❤️ for the scientific Python community
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file ezinput-0.0.18.tar.gz.
File metadata
- Download URL: ezinput-0.0.18.tar.gz
- Upload date:
- Size: 29.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4a0a4b3aaefd1f1992a7622c82d75f6a9ac89c92617e2a503c6c7ea01c1871f6
|
|
| MD5 |
49ffafe504aa679be24a685c117527ce
|
|
| BLAKE2b-256 |
d0ec2004c82fa30dfe051f4f4fdd058cf2f91666ab7023b3a62176c3eb2bf9a5
|
File details
Details for the file ezinput-0.0.18-py3-none-any.whl.
File metadata
- Download URL: ezinput-0.0.18-py3-none-any.whl
- Upload date:
- Size: 23.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
aa226e7ab694338e97885d04c044aa9ef2fc8480801faf6d030413ed05951f45
|
|
| MD5 |
30edfaf1ad01142b2047444cefa1312a
|
|
| BLAKE2b-256 |
bac53d13f3e4a7b1f9d71f492b124ae6f3750ec2be6932a70243431c46e2ea57
|