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 typer_ui as tg

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

# Create the UI wrapper
ui = tg.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(tg.Md(f"# Hello {name}{punctuation}"))
    ui(tg.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(tg.Text("Hello"))
ui(tg.Md("# Header"))
ui(tg.Table(cols=["Name"], data=[["Alice"]]))

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

Available Components

Text & Markdown

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

Tables

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

Layout Components

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

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

Interactive Components

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

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

# Text input (GUI only)
ui(tg.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 = tg.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(tg.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(tg.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(tg.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 typer_ui as tg
import time

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

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

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

    ui(tg.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(tg.Md(f"# Processing {count} files"))

    with ui(tg.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(tg.Md("✓ **All files processed!**"))

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

@app.command()
def analyze():
    """Return data for automatic display."""
    return tg.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(tg.Text("Hello"))

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

# Context manager
with ui(tg.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 typer_ui module:

import typer_ui as tg

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

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

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

# Interactive (GUI only)
tg.Button("text", on_click=callback)
tg.Link("text", on_click=callback)
tg.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.4.0.tar.gz (45.0 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.4.0-py3-none-any.whl (48.8 kB view details)

Uploaded Python 3

File details

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

File metadata

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

File hashes

Hashes for typer2ui-0.4.0.tar.gz
Algorithm Hash digest
SHA256 fcc5704cfbabb449cd0c5327f04070eca295dd58227996abb260ac7a30677b2e
MD5 c032c520781ff1d205b4ed2ce17d598f
BLAKE2b-256 a87824d4cfb9106e51c8ef35f5237dbe28fae844b9db0b959758590363d1cbb9

See more details on using hashes here.

File details

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

File metadata

  • Download URL: typer2ui-0.4.0-py3-none-any.whl
  • Upload date:
  • Size: 48.8 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.4.0-py3-none-any.whl
Algorithm Hash digest
SHA256 cdb5747835ab13f96ee8b98ce34b11fdbc9c5bf46a4842175f0445bafaef9d89
MD5 0bc933cc5b7b0b7a6a66425c18d1d5a2
BLAKE2b-256 a47931ec1b0c4094f7f9e2570fbd8ddf51d8718f837d644e86d1c86ddf531fd2

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