← Back to Blog

Task Manager Project — Round 2

The foundation is solid. Tasks are added, saved, loaded, displayed.

Round 2 completes the system — show by deadline, update status, filter, delete, export report.

Update task status

    def update_status(self):
        self.show()
        if not self.tasks:
            return

        while True:
            try:
                id = int(input("Task ID to update: "))
                if id in self.tasks:
                    break
                print("ID not found.")
            except ValueError:
                print("Invalid ID. Enter a number.")

        print(f"Current status: {self.tasks[id].status}")
        status = ""
        while status not in Task.VALID_STATUSES:
            status = input("New status (pending/in progress/done): ").lower()

        self.tasks[id].status = status
        print(f"Task updated: {self.tasks[id]}")

        with open(self.filename, "w", encoding="utf-8") as f:
            for tid, task in self.tasks.items():
                f.write(f"{tid};{task.title};{task.priority};{task.status};{task.deadline};{task.created}\n")
        self.load()

We show all tasks first — the user identifies the ID visually. Then we validate the ID, show the current status, and ask for the new one. On confirmation — rewrite the file with "w", reload.

Show tasks sorted by deadline

Not just a list — a prioritized view. Tasks closest to their deadline appear first. Overdue tasks surface immediately.

    def show_by_deadline(self):
        if not self.tasks:
            print("No tasks yet.")
            return

        today = datetime.date.today()

        def days_left(item):
            id, task = item
            try:
                deadline = datetime.datetime.strptime(task.deadline, "%Y-%m-%d").date()
                return (deadline - today).days
            except ValueError:
                return 9999

        sorted_tasks = sorted(self.tasks.items(), key=days_left)

        for id, task in sorted_tasks:
            try:
                deadline = datetime.datetime.strptime(task.deadline, "%Y-%m-%d").date()
                diff     = (deadline - today).days
                if diff < 0:
                    urgency = f"OVERDUE by {abs(diff)} days"
                elif diff == 0:
                    urgency = "DUE TODAY"
                else:
                    urgency = f"{diff} days left"
            except ValueError:
                urgency = "invalid date"
            print(f"{id}. {task} | {urgency}")

A negative difference — deadline has passed. Zero — due today. The rest counts down. Invalid dates are pushed to the end without breaking the sort.

Output:

1. [PENDING] Plan meeting | priority: high | deadline: 2025-04-30 | DUE TODAY
3. [IN PROGRESS] Review code | priority: medium | deadline: 2025-05-02 | 2 days left
2. [PENDING] Buy groceries | priority: low | deadline: 2025-05-05 | 5 days left
4. [DONE] Write report | priority: high | deadline: 2025-05-10 | 10 days left

Filter tasks

    def filter_tasks(self):
        print("Filter by:")
        print("1 - Priority")
        print("2 - Status")
        choice = input("Choose: ")

        if choice == "1":
            priority = ""
            while priority not in Task.VALID_PRIORITIES:
                priority = input("Priority (low/medium/high): ").lower()
            results = {id: t for id, t in self.tasks.items() if t.priority == priority}

        elif choice == "2":
            status = ""
            while status not in Task.VALID_STATUSES:
                status = input("Status (pending/in progress/done): ").lower()
            results = {id: t for id, t in self.tasks.items() if t.status == status}

        else:
            print("Invalid choice.")
            return

        if not results:
            print("No tasks match your filter.")
            return

        for id, task in results.items():
            print(f"{id}. {task}")

Two filter modes — priority and status. Dict comprehension builds the results in one line.

Delete a task

    def delete(self):
        self.show()
        if not self.tasks:
            return

        while True:
            try:
                id = int(input("Task ID to delete: "))
                if id in self.tasks:
                    break
                print("ID not found.")
            except ValueError:
                print("Invalid ID. Enter a number.")

        print(f"Deleting: {self.tasks[id]}")
        confirm = input("Confirm? (yes/no): ").lower()
        if confirm == "yes":
            del self.tasks[id]
            with open(self.filename, "w", encoding="utf-8") as f:
                for tid, task in self.tasks.items():
                    f.write(f"{tid};{task.title};{task.priority};{task.status};{task.deadline};{task.created}\n")
            self.load()
            print("Task deleted.")
        else:
            print("Cancelled.")

Deletion with confirmation — one of the few places in the course where we ask twice before acting. A deleted task is gone. The confirm step is deliberate.

Export report

    def export_report(self):
        today    = datetime.date.today().strftime("%Y-%m-%d")
        filename = f"{self.name}_report_{today}.txt"

        with open(filename, "w", encoding="utf-8") as f:
            f.write(f"Task Report — {self.name}\n")
            f.write(f"Generated: {today}\n")
            f.write("=" * 30 + "\n")
            f.write(f"Total:       {len(self.tasks)}\n")
            f.write(f"Pending:     {sum(1 for t in self.tasks.values() if t.status == 'pending')}\n")
            f.write(f"In progress: {sum(1 for t in self.tasks.values() if t.status == 'in progress')}\n")
            f.write(f"Done:        {sum(1 for t in self.tasks.values() if t.status == 'done')}\n")
            f.write("=" * 30 + "\n\n")

            for priority in ["high", "medium", "low"]:
                tasks = {id: t for id, t in self.tasks.items() if t.priority == priority}
                if tasks:
                    f.write(f"// {priority.upper()}\n")
                    for id, task in tasks.items():
                        f.write(f"{id}. [{task.status.upper()}] {task.title} | deadline: {task.deadline}\n")
                    f.write("\n")

        print(f"Report saved: {filename}")

Grouped by priority — high first, then medium, then low. Summary at the top, details below. Filename includes the task list name and today's date.

The exported report:

Task Report — daily
Generated: 2025-05-01
==============================
Total:       4
Pending:     2
In progress: 1
Done:        1
==============================

// HIGH
1. [DONE] Write report | deadline: 2025-05-01
4. [PENDING] Plan meeting | deadline: 2025-05-03

// MEDIUM
3. [IN PROGRESS] Review code | deadline: 2025-05-02

// LOW
2. [PENDING] Buy groceries | deadline: 2025-04-30

The complete menu

task_list = TaskList("daily")
task_list.load()

print(task_list)

while True:
    print("\nTask Manager")
    option = input("1-Add\n2-Show all\n3-Show by deadline\n4-Update status\n5-Filter\n6-Delete\n7-Export report\nq-Quit\nChoose: ")
    if option == "1":
        task_list.add()
        print("Task added successfully!")
    elif option == "2":
        task_list.show()
    elif option == "3":
        task_list.show_by_deadline()
    elif option == "4":
        task_list.update_status()
    elif option == "5":
        task_list.filter_tasks()
    elif option == "6":
        task_list.delete()
    elif option == "7":
        task_list.export_report()
    elif option == "q":
        break
    else:
        print("Invalid option.")

Two classes. Seven operations. A system you can use tomorrow morning.

What This Code Can Become — next.

[ login to bookmark ] // copied! 34 views · 4 min
// resources
Exercise task_manager.py
← prev Task Manager Project — Round 1 next → Task Manager Project — What This Code Can Become
// 0 comments
// No comments yet. Be the first.
// leave a comment

// Your comment will appear after approval.