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.