Skip to main content

Automatically generate desktop GUIs for Typer CLI applications using Flet

Project description

Typer2UI

Automatically generate desktop GUIs for existing Typer CLI applications using Flet.

Overview

Typer2UI is a Python library that bridges the gap between command-line interfaces and graphical user interfaces. If you have a Typer-based CLI application, you can instantly create a desktop GUI for it with just a few lines of code.

Key Features

  • Zero or minimal code changes to your existing Typer app
  • Automatic GUI generation from Typer commands and parameters
  • Simple, elegant API - ui(component) for all output
  • Auto-update components - modify components and see changes instantly
  • Progressive rendering - update UI in real-time with context managers
  • Rich UI components - Tables, Markdown, Buttons, Rows, Columns, and more
  • Type-aware controls - text fields, dropdowns, checkboxes based on parameter types
  • Real-time output streaming - see output as it's produced for long-running commands
  • Clean, modern interface powered by Flet

Installation

Using pip

pip install typer2ui

This will automatically install typer and flet as dependencies if they're not already present.

For development

# Clone the repository
git clone https://github.com/rados4y/typer2ui.git
cd typer2ui

# Create a virtual environment
python -m venv .venv
source .venv/bin/activate  # On Windows: .venv\Scripts\activate

# Install in development mode
pip install -e .

Quick Start

Here's a minimal example to get you started:

# my_app.py
import typer
import typer2ui as tu

# Create the Typer app
app = typer.Typer()

# Create the UI wrapper
ui = tu.Ui(
    app,
    title="My App",
    description="A graphical interface for my CLI app"
)

@app.command()
def greet(name: str, excited: bool = False):
    """Greet someone with a friendly message."""
    punctuation = "!" if excited else "."

    # Use ui() to output components
    ui(tu.Md(f"# Hello {name}{punctuation}"))
    ui(tu.Text("Thanks for using Typer2UI!"))

@app.command()
def add(a: int, b: int):
    """Add two numbers together."""
    result = a + b

    # You can also use print()
    print(f"{a} + {b} = {result}")

if __name__ == "__main__":
    # Launch the GUI
    ui.app()

Run it:

# Launch GUI
python my_app.py

# Or run CLI directly with --cli flag
python my_app.py --cli greet "World" --excited
python my_app.py --cli add 5 10

That's it! Your CLI app now has a fully functional GUI.

The Simple API

Universal Output: ui(component)

Instead of multiple output methods, Typer2UI has one simple pattern:

# Output any component
ui(tu.Text("Hello"))
ui(tu.Md("# Header"))
ui(tu.Table(cols=["Name"], data=[["Alice"]]))

# Or return a component (auto-displayed)
@app.command()
def get_data():
    return tu.Table(cols=["Name"], data=[["Bob"]])

Available Components

Text & Markdown

ui(tu.Text("Plain text"))
ui(tu.Md("**Bold** and *italic* with markdown"))
ui(tu.Md("""
# Report
- Item 1
- Item 2
"""))

Tables

ui(tu.Table(
    cols=["Name", "Age", "City"],
    data=[
        ["Alice", 30, "NYC"],
        ["Bob", 25, "LA"],
    ],
    title="Users"
))

Layout Components

# Horizontal layout
ui(tu.Row([
    tu.Button("Save", on_click=save_data),
    tu.Button("Cancel", on_click=cancel),
]))

# Vertical layout
ui(tu.Column([
    tu.Md("# Dashboard"),
    tu.Table(cols=["Metric", "Value"], data=get_metrics()),
]))

Interactive Components

# Buttons (GUI only)
ui(tu.Button("Click me", on_click=lambda: print("Clicked!")))

# Links (GUI only)
ui(tu.Link("Learn more", on_click=open_docs))

# Text input (GUI only)
ui(tu.TextInput(
    label="Name",
    value="",
    on_change=lambda text: print(f"Changed to: {text}")
))

Auto-Update Components

One of Typer2UI's most powerful features: components automatically update when modified!

@app.command()
def process_items():
    # Create and present a table
    table = tu.Table(cols=["Item", "Status"], data=[])
    ui(table)  # Present it

    # Add rows - table auto-updates in real-time!
    for i in range(10):
        table.add_row([f"Item {i}", "Processing..."])
        time.sleep(0.5)

    ui(tu.Md("✓ Complete!"))

Progressive Rendering with Context Managers

For even cleaner code, use context managers:

@app.command()
@ui.command(is_long=True)
def analyze_data():
    # Present and update in one flow
    with ui(tu.Table(cols=["Step", "Progress"], data=[])) as table:
        table.add_row(["Loading", "0%"])
        time.sleep(1)

        table.add_row(["Processing", "50%"])
        time.sleep(1)

        table.add_row(["Complete", "100%"])

GUI Customization

Use the @ui.command() decorator to customize command behavior:

@app.command()
@ui.command(is_button=True, is_long=True)
def process():
    """Long-running process with button styling."""
    with ui(tu.Table(cols=["Step", "Status"], data=[])) as t:
        for i in range(10):
            t.add_row([f"Step {i+1}", "Running..."])
            time.sleep(1)

Available options:

  • is_button (bool): Display command as a highlighted button
  • is_long (bool): Enable real-time output streaming
  • is_auto_exec (bool): Execute automatically when selected

Comprehensive Example

import typer
import typer2ui as tu
import time

app = typer.Typer()
ui = tu.Ui(app, title="Data Processor", description="Process and analyze data")

@app.command()
def show_report():
    """Display a formatted report."""
    ui(tu.Md("""
# System Report

## Summary
All systems operational.
    """))

    ui(tu.Table(
        cols=["Component", "Status", "Usage"],
        data=[
            ["CPU", "✓", "45%"],
            ["Memory", "✓", "60%"],
            ["Disk", "✓", "70%"],
        ],
        title="System Metrics"
    ))

@app.command()
@ui.command(is_button=True, is_long=True)
def process_files(count: int = 5):
    """Process multiple files with progress updates."""
    ui(tu.Md(f"# Processing {count} files"))

    with ui(tu.Table(cols=["File", "Status"], data=[])) as table:
        for i in range(count):
            table.add_row([f"file_{i}.txt", "Processing..."])
            time.sleep(0.5)

    ui(tu.Md("✓ **All files processed!**"))

@app.command()
def dashboard():
    """Show interactive dashboard."""
    ui(tu.Column([
        tu.Md("# Dashboard"),
        tu.Row([
            tu.Button("Refresh", on_click=lambda: print("Refreshing...")),
            tu.Button("Export", on_click=lambda: print("Exporting...")),
        ]),
        tu.Table(
            cols=["Metric", "Value"],
            data=[
                ["Users", "1,234"],
                ["Revenue", "$56,789"],
                ["Growth", "+12%"],
            ]
        ),
    ]))

@app.command()
def analyze():
    """Return data for automatic display."""
    return tu.Table(
        cols=["Analysis", "Result"],
        data=[
            ["Mean", "42.5"],
            ["Median", "40.0"],
            ["Std Dev", "5.2"],
        ]
    )

if __name__ == "__main__":
    ui.app()

Supported Parameter Types

Typer2UI automatically maps Python types to appropriate GUI controls:

Python Type GUI Control Notes
str Text field For string input
int Text field Numeric keyboard, validates integers
float Text field Numeric keyboard, validates floats
bool Checkbox For boolean flags
Enum Dropdown Shows all enum values as options

Example with Enums

from enum import Enum

class LogLevel(str, Enum):
    DEBUG = "debug"
    INFO = "info"
    WARNING = "warning"
    ERROR = "error"

@app.command()
def configure(level: LogLevel = LogLevel.INFO):
    """Configure logging level."""
    print(f"Log level set to: {level.value}")

In the GUI, the level parameter will appear as a dropdown with all enum values.

API Reference

Ui Class

The main entry point for Typer2UI.

Constructor:

Ui(app, *, title=None, description=None)

Parameters:

  • app (typer.Typer): The Typer application instance
  • title (str, optional): Window title for the GUI
  • description (str, optional): Description text shown at the top

Methods:

ui(component) - Universal Output

Output any UI component. Returns the component for chaining/context managers.

# Simple output
ui(tu.Text("Hello"))

# Store reference for updates
table = tu.Table(cols=["Name"], data=[])
ui(table)
table.add_row(["Alice"])  # Auto-updates!

# Context manager
with ui(tu.Table(cols=["Name"], data=[])) as t:
    t.add_row(["Bob"])

ui.command(*, is_button=False, is_long=False, is_auto_exec=False)

Decorator to customize command appearance and behavior.

@app.command()
@ui.command(is_button=True, is_long=True)
def process():
    print("Processing...")

ui.app()

Launch the GUI or run in CLI mode with --cli flag.

python my_app.py              # Launch GUI
python my_app.py --cli hello  # Run CLI

UI Components

All components are in the typer2ui module:

import typer2ui as tu

# Simple components
tu.Text("content")           # Plain text
tu.Md("# markdown")          # Markdown

# Data display
tu.Table(
    cols=["A", "B"],         # Column headers
    data=[["1", "2"]],       # Row data
    title="Table Title"      # Optional title
)

# Layout
tu.Row([comp1, comp2])       # Horizontal
tu.Column([comp1, comp2])    # Vertical

# Interactive (GUI only)
tu.Button("text", on_click=callback)
tu.Link("text", on_click=callback)
tu.TextInput("label", value="", on_change=callback)

Examples

Check out the examples/ directory for working examples:

  • 01_basic_typer_to_gui.py - Minimal example showing basic usage
  • 02_arguments_and_output.py - Parameters and UI components
  • 03_ui_blocks.py - Tables, layout, and composition
  • 04_customizations.py - Buttons, streaming, and advanced features

Run examples:

# GUI mode
python examples/01_basic_typer_to_gui.py

# CLI mode
python examples/01_basic_typer_to_gui.py --cli add 5 3

Features

Current Features

  • ✅ Simple, unified API with ui(component)
  • ✅ Auto-update components when modified
  • ✅ Progressive rendering with context managers
  • ✅ Rich UI components (Text, Markdown, Table, Row, Column, Button, Link)
  • ✅ Automatic GUI generation from Typer commands
  • ✅ Type-aware form controls
  • ✅ Real-time output streaming (is_long=True)
  • ✅ Command customization (is_button, is_auto_exec)
  • ✅ Both GUI and CLI modes from single entry point
  • ✅ Cross-platform (Windows, macOS, Linux)

Planned Features

  • Path/file selection widgets
  • Progress bars and spinners
  • Date/time pickers
  • Custom themes
  • Nested/grouped commands
  • Command history
  • Tabs and panels

How It Works

  1. Reflection: Analyzes your Typer app using Python's introspection
  2. GUI Generation: Creates Flet-based UI with appropriate controls
  3. Direct Execution: Calls your command functions directly (not via subprocess)
  4. Component System: Simple show_cli() and show_gui() methods for each component
  5. Auto-Update: Components track when they're presented and update automatically

Contributing

Contributions are welcome! Please feel free to submit issues or pull requests.

License

MIT License - see LICENSE file for details.

Credits

Built with:

  • Typer - CLI framework by Sebastián Ramírez
  • Flet - GUI framework based on Flutter

Made with ❤️ for the Python CLI community

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

typer2ui-0.9.0.tar.gz (49.7 kB view details)

Uploaded Source

Built Distribution

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

typer2ui-0.9.0-py3-none-any.whl (50.3 kB view details)

Uploaded Python 3

File details

Details for the file typer2ui-0.9.0.tar.gz.

File metadata

  • Download URL: typer2ui-0.9.0.tar.gz
  • Upload date:
  • Size: 49.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.5

File hashes

Hashes for typer2ui-0.9.0.tar.gz
Algorithm Hash digest
SHA256 df0c84de0b57dd6537d3f0a59f555fd36f7211b6fb0a1b97bb3f3bbfd2848a43
MD5 a6041a3825c1cc0a1ac2ea90ca977161
BLAKE2b-256 fc7c898203d95ce790f1bf8632f16e286b706c3ed80475944d005bc3dd18db22

See more details on using hashes here.

File details

Details for the file typer2ui-0.9.0-py3-none-any.whl.

File metadata

  • Download URL: typer2ui-0.9.0-py3-none-any.whl
  • Upload date:
  • Size: 50.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.5

File hashes

Hashes for typer2ui-0.9.0-py3-none-any.whl
Algorithm Hash digest
SHA256 882765de38a2a92e1a52d99034c1d9f3875f6226ed01a4697ef3ea0776ecadc3
MD5 af8ceb64737a283ff6d5306061a43617
BLAKE2b-256 0bb5e5b3781647f98a481c17c69682d4614d9e6a40cb4730db8d51accb5ae055

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