Skip to main content

Simplify the creation of GUI elements in terminals and Jupyter Notebooks

Project description

EZInput

PyPI Python Version Downloads Docs License Tests Coverage Contributors GitHub stars GitHub forks DOI

EZInput Logo

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:
    • ipywidgets and ipyfilechooser for Jupyter notebooks
    • prompt-toolkit for terminal interfaces
    • pyyaml for 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 EZInput instance per analysis task or computational pipeline
  • The order you add widgets is the order they appear on screen
  • Use remember_value=True parameter 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:

  1. Loaded parameters (from load_parameters())
  2. Remembered values (from previous runs, if remember_value=True parameter)
  3. Explicit defaults (passed via default= parameter)
  4. 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

🤝 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 from ezinput.ezinput_jupyter import EZInputJupyter

gui = EZInputJupyter() gui.add_text('name', description='Name:', style={'description_width': 'initial'})


## Example: Adding a Custom Widget

```python
# Pass a widget class (with args/kwargs)
gui.add_custom_widget('slider', widgets.IntSlider, min=0, max=10, value=5)

# Or pass an already-instantiated widget
dropdown = widgets.Dropdown(options=['A', 'B', 'C'], value='A')
gui.add_custom_widget('dropdown', dropdown)

Examples

Terminal Example

from ezinput import EZInput

gui = EZInput(title="Terminal Example")
gui.add_text("username", "Enter your username:", remember_value=True)
gui.add_int_range("age", "Enter your age:", 18, 100, remember_value=True)
gui.save_settings()

Jupyter Notebook Example

from ezinput import EZInput

gui = EZInput(title="Jupyter Example")
gui.add_text("username", description="Enter your username:", remember_value=True)
gui.add_int_range("age", description="Enter your age:", vmin=18, vmax=100, remember_value=True)
gui.show()

License

This project is licensed under the MIT License. See the LICENSE file for details.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

ezinput-0.0.11.tar.gz (29.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

ezinput-0.0.11-py3-none-any.whl (23.9 kB view details)

Uploaded Python 3

File details

Details for the file ezinput-0.0.11.tar.gz.

File metadata

  • Download URL: ezinput-0.0.11.tar.gz
  • Upload date:
  • Size: 29.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for ezinput-0.0.11.tar.gz
Algorithm Hash digest
SHA256 05fcfa97bbd65ce5d6fea6945671ac479d5a5a308bce7d6967d6779bf3112ed9
MD5 09ae96c0de8c80cc03e4549bd80b451a
BLAKE2b-256 afd59aac37782da3cec3e4785be7c1ef048cd0954cc09dddf9fc327ef6f6c56b

See more details on using hashes here.

File details

Details for the file ezinput-0.0.11-py3-none-any.whl.

File metadata

  • Download URL: ezinput-0.0.11-py3-none-any.whl
  • Upload date:
  • Size: 23.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for ezinput-0.0.11-py3-none-any.whl
Algorithm Hash digest
SHA256 018e4b11eaf67432302c81d34589e27a0137c1e5dd16d5b4510cbe5cf6f6cdb5
MD5 1a8a652d57e1f1efcd8a367bb5e8f2c3
BLAKE2b-256 5a76bcb6011b7755d79da1884ecbc7f9c63c50fcd8d3002e585f97a990e25077

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page