Python Typer Tutorial: Build CLIs with Python in Minutes

Learn how to build CLIs with Python using Typer in a few simple steps.



Python Typer Tutorial: Build CLIs with Python in Minutes
Image by Author | Created on Canva

 

In this tutorial, we'll build a Command Line Interface (CLI) using Typer, a Python library that makes building CLIs fast and simple. Typer also leverages Python's type hints.

This tutorial will walk you through how to build a CLI for a schedule tracker. Specifically, we’ll learn how to:

  • Set up Typer
  • Add commands
  • Handle task, time, and priority—input and data types correctly

Let’s get started!

 

Step 1: Install Typer

 

First, let's install Typer:

$ pip3 install typer

 

Installing Typer automatically installs all the required dependencies, which facilitates the command-line interface functionality. Please install Typer in a virtual environment for the project.

Here’s the GitHub repository for this simple project.

 

Step 2: Create the Basic CLI

 

Let’s start by creating a simple CLI that can add a task to a schedule with the correct time format.

Create a Python file named schedule_tracker.py.

Import the required libraries and modules. The typer.Typer() instance (app) manages the CLI commands.

import typer
from datetime import datetime
import json
from typing import List

app = typer.Typer()

 

We define a few helper functions to load the schedule from and save it to a JSON file:

SCHEDULE_FILE = "schedule.json"

def load_schedule() -> List[dict]:
    try:
        with open(SCHEDULE_FILE, "r") as f:
            return json.load(f)
    except (FileNotFoundError, json.JSONDecodeError):
        return []

def save_schedule(schedule: List[dict]):
    with open(SCHEDULE_FILE, "w") as f:
        json.dump(schedule, f, default=str, indent=4)

 

Because we have a time associated with each task, let’s create a helper function that parses the string to a valid time object:

def parse_time(t: str) -> datetime.time:
    try:
        return datetime.strptime(t, "%H:%M").time()
    except ValueError:
        typer.echo("Invalid time format. Please use HH:MM.")
        raise typer.Exit()

 

Create the basic add_task command. The task (a description of the task), the time, and priority define each task item:

@app.command()
def add_task(
	task: str,
	time: str = typer.Option(..., help="Time in HH:MM format"),
	priority: int = typer.Option(1, help="Priority of the task")
):
    schedule = load_schedule()
    task_time = parse_time(time)
    schedule.append({"task": task, "time": task_time.strftime("%H:%M"), "priority": priority})
    save_schedule(schedule)
    typer.echo(f"Task '{task}' added at {task_time.strftime('%H:%M')} with priority {priority}")

if __name__ == "__main__":
	app()

 

Step 3: Run the CLI

 

Now run schedule_tracker.py to add tasks like so:

$ python3 schedule_tracker.py add-task "Team meeting" --time "14:00" --priority 2

 

Which outputs:

Task 'Team meeting' added at 14:00 with priority 2

 

Now you have a working CLI that accepts tasks with associated time and priority!

 

Step 4: Add More Commands

 

Let’s add more functionality to our schedule tracker, such as viewing and removing tasks.

First, add a command to view tasks sorted by time:

@app.command()
def list_tasks():
    """List all scheduled tasks."""
    schedule = load_schedule()
    if not schedule:
        typer.echo("No tasks found.")
        return
    for task in sorted(schedule, key=lambda x: x["time"]):
        @app.command()
        print(f"Task {i}: {task['task']}")
        print(f"  Time: {task['time']}")
        print(f"  Priority: {task['priority']}")
        print("-" * 40)  # Add a separator line for better readability

 

You can modify this function as needed to sort tasks by priority as well.

Let’s also add a command to remove tasks by their index number:

@appcommand()
def remove_task(task_number: int):
    """Remove a task by its number."""
    schedule = load_schedule()
    if 0 < task_number <= len(schedule):
        removed_task = schedule.pop(task_number - 1)
        save_schedule(schedule)  # Save the updated schedule
        typer.echo(f"Removed task '{removed_task['task']}' scheduled at {removed_task['time']}") 
    else: 
        typer.echo(f"Invalid task number. Choose a number between 1 and {len(schedule)}.")

 

Step 5: Test the Improved CLI

 

Now, test the following commands.

Add multiple tasks:

$ python3 schedule_tracker.py add-task "Code review" --time "10:30" --priority 1
$ python3 schedule_tracker.py add-task "Client meeting" --time "12:00" --priority 3

 

Doing so, you'll see:

Task 'Code review' added at 10:30 with priority 1
Task 'Client meeting' added at 12:00 with priority 3

 

View all tasks:

$ python3 schedule_tracker.py list-tasks

 

Running this command outputs:

Task 0: Code review
  Time: 10:30
  Priority: 1
----------------------------------------
Task 1: Client meeting
  Time: 12:00
  Priority: 3
----------------------------------------
Task 2: Team meeting
  Time: 14:00
  Priority: 2
----------------------------------------

 

Remove a task:

$ python3 schedule_tracker.py remove-task 1

 

This outputs:

Removed task 'Team meeting' scheduled at 14:00

 

View the updated task list:

$ python3 schedule_tracker.py list-tasks

 

We should now see the following output:

Task 0: Code review
  Time: 10:30
  Priority: 1
----------------------------------------
Task 1: Client meeting
  Time: 12:00
  Priority: 3
----------------------------------------

 

Wrapping Up

 

That’s all for this tutorial. As seen, with Typer, you can create simple yet powerful CLIs in just minutes. In this tutorial, we built a schedule tracker that handles tasks and time input validation efficiently.

You can now improve the version we’ve built. You can extend this project by adding more features like recurring tasks, reminders, or exporting the schedule. Or you can try building a similar app for tracking expenses.

Happy coding!

 

 

Bala Priya C is a developer and technical writer from India. She likes working at the intersection of math, programming, data science, and content creation. Her areas of interest and expertise include DevOps, data science, and natural language processing. She enjoys reading, writing, coding, and coffee! Currently, she's working on learning and sharing her knowledge with the developer community by authoring tutorials, how-to guides, opinion pieces, and more. Bala also creates engaging resource overviews and coding tutorials.