Python Series track

Project 16 · Practice Projects

Project 16 — TUI App with curses / textual

Build a terminal user interface (TUI) for one of your earlier projects. Use curses for low-level control or the modern textual framework for high-level widgets.

Practice Projects1 min readFree lesson

Difficulty: Lv ★★★★ | Prerequisite Knowledge: Advanced Week 1 + External Libraries

Goal

An app that draws a rich UI in the terminal

Requirements

  • Use rich or textual
  • Tables, progress bars, panels, colors
  • Example: Rewrite a To-Do or Household Ledger as a TUI

Challenge Task

  • textual fullscreen + keyboard shortcuts
  • Real-time updates with Live

Installation

pip install rich
#Or
pip install textual

Assignment

Show the reference solution

Try the assignment yourself first — comparing your attempt with a working solution is where most of the learning happens.

solution.pyPython
"""TUI To-Do (rich) — pip install rich

If rich is not available, gracefully fall back."""

try:
    from rich.console import Console
    from rich.table import Table
    from rich.panel import Panel
    HAS_RICH = True
except ImportError:
    HAS_RICH = False

todos = [
    {"id": 1, "task": "Buy milk", "priority": "Medium", "done": False},
    {"id": 2, "task": "Return book", "priority": "High", "done": True},
    {"id": 3, "task": "Exercise", "priority": "Low", "done": False},
]

PRIORITY_STYLE = {"High": "red", "Medium": "yellow", "Low": "green"}

def render_rich():
    console = Console()
    table = Table(title="📋 My To-Do", show_lines=True, header_style="bold cyan")
    table.add_column("Number", justify="right", style="cyan")
    table.add_column("Status", justify="center")
    table.add_column("Priority", justify="center")
    table.add_column("To-do")
    for t in todos:
        mark = "[green]✓ Done[/]" if t["done"] else "[yellow]○ In progress[/]"
        prio = f"[{PRIORITY_STYLE[t['priority']]}]{t['priority']}[/]"
        task = f"[strike]{t['task']}[/]" if t["done"] else t["task"]
        table.add_row(str(t["id"]), mark, prio, task)
    console.print(table)
    pending = sum(1 for t in todos if not t["done"])
    console.print(Panel(f"Incomplete: [bold red]{pending}[/] items / Total {len(todos)} items", style="dim"))

def render_plain():
    print("📋 My To-Do (plain mode — pip install rich recommended)")
    for t in todos:
        mark = "[x]" if t["done"] else "[ ]"
        print(f"  {t['id']}. {mark}[{t['priority']}] {t['task']}")

def main():
    if HAS_RICH:
        render_rich()
    else:
        print("⚠️ rich not installed. Output in plain mode.")
        render_plain()

if __name__ == "__main__":
    main()

Learn this lesson with a mentor

Work through the Python Series track on your own, or join a guided cohort at our Pitampura campus and online.

Call NowEnroll Now