Complete Implementation
import json
from pathlib import Path
from datetime import datetime
from dataclasses import dataclass, asdict
TODO_FILE = Path("todos.json")
@dataclass
class Task:
id: int
title: str
done: bool = False
priority: str = "medium"
created: str = ""
def __post_init__(self):
if not self.created:
self.created = datetime.now().strftime("%Y-%m-%d %H:%M")
class TodoApp:
def __init__(self):
self.tasks: list[Task] = []
self._next_id = 1
self.load()
def load(self):
if TODO_FILE.exists():
data = json.loads(TODO_FILE.read_text())
self.tasks = [Task(**t) for t in data["tasks"]]
self._next_id = data.get("next_id", len(self.tasks) + 1)
def save(self):
TODO_FILE.write_text(json.dumps(
{"tasks": [asdict(t) for t in self.tasks], "next_id": self._next_id}, indent=2
))
def add(self, title, priority="medium"):
task = Task(id=self._next_id, title=title, priority=priority)
self.tasks.append(task); self._next_id += 1; self.save(); return task
def complete(self, task_id):
task = next((t for t in self.tasks if t.id == task_id), None)
if task: task.done = True; self.save()
return task
def delete(self, task_id):
task = next((t for t in self.tasks if t.id == task_id), None)
if task: self.tasks.remove(task); self.save(); return True
return False
app = TodoApp()
ICONS = {"high": "π΄", "medium": "π‘", "low": "π’"}
while True:
print("\n[1]List [2]Add [3]Complete [4]Delete [q]Quit")
c = input("> ").strip().lower()
if c == "q": break
elif c == "1":
for t in sorted(app.tasks, key=lambda x: {"high":0,"medium":1,"low":2}[x.priority]):
print(f" [{t.id}] {'β' if t.done else 'β'} {ICONS[t.priority]} {t.title}")
elif c == "2":
title = input("Title: "); p = input("Priority [medium]: ") or "medium"
task = app.add(title, p); print(f"Added #{task.id}")
elif c == "3":
tid = int(input("Task ID: "))
print("Done!" if app.complete(tid) else "Not found.")
elif c == "4":
tid = int(input("Task ID: "))
print("Deleted." if app.delete(tid) else "Not found.")ποΈ Practical Exercise
Improve the to-do app:
- Add the ability to mark a task as complete and show its status.
- Persist tasks to a JSON file so they survive restarts.
- Add a command to delete a task by its number.
- Add a due date to each task.
π₯ Challenge Exercise
Turn the to-do app into a small task manager: support priorities, due dates, and filtering (e.g. show only incomplete or overdue tasks), persist everything to a file or SQLite database, and organize the code into clear functions or a class. Bonus: add a command-line interface with argparse so tasks can be managed via terminal commands.
π Summary
- This project builds a to-do list that adds, lists, completes, and removes tasks.
- Tasks are stored in a list (or objects) and persisted to a file or database.
- Completion status, due dates, and priorities enrich each task.
- Filtering surfaces relevant tasks (incomplete, overdue).
- Organizing logic into functions or a class keeps it maintainable.
- It can grow into a CLI tool, web app, or GUI.
Interview Questions on Building a To-Do App
- How would you model a task and a task list in Python?
- How do you persist the task list between runs?
- How would you implement marking tasks complete?
- How do you add filtering (e.g. by status or due date)?
- How would you structure the code as it grows?
- How would you add a command-line interface?
- How could you turn this into a web or GUI app?
Related Topics
FAQ
Persist them to storage β a JSON file is the simplest option, or SQLite for structured queries. Load the saved tasks on startup and write them back whenever they change.
As the app grows beyond a few fields, a Task class (or dataclass) keeps related data and behavior together and is easier to extend than parallel lists or bare dictionaries. For a tiny app, a list of dicts is fine.
Use the standard-library argparse module to define commands like add, list, done, and remove with arguments, so the app can be driven from the terminal.
Reuse the task logic and add a Flask or FastAPI layer with routes for listing and modifying tasks, plus templates or a JSON API. Separating the data logic from the interface makes the transition smooth.
