Build a Command-Line To-Do List Application with Data Persistence in Python
A persistent command-line to-do list that saves tasks as JSON, supporting add, show, toggle done, and quit commands.
Python code
49 linesimport json
import os
TODO_FILE = "todos.json"
def load_todos():
if not os.path.exists(TODO_FILE):
return []
with open(TODO_FILE, "r") as f:
return json.load(f)
def save_todos(todos):
with open(TODO_FILE, "w") as f:
json.dump(todos, f, indent=2)
def show_todos(todos):
if not todos:
print("No todos yet.")
return
for i, todo in enumerate(todos, 1):
status = "[x]" if todo["done"] else "[ ]"
print(f"{i}. {status} {todo['task']}")
def add_todo(todos, task):
todos.append({"task": task, "done": False})
def toggle_todo(todos, index):
if 1 <= index <= len(todos):
todos[index - 1]["done"] = not todos[index - 1]["done"]
if __name__ == "__main__":
todos = load_todos()
while True:
print("\nCommands: show, add <task>, done <num>, quit")
cmd = input("> ").strip()
if cmd == "quit":
save_todos(todos)
break
elif cmd == "show":
show_todos(todos)
elif cmd.startswith("add "):
add_todo(todos, cmd[4:])
elif cmd.startswith("done "):
try:
toggle_todo(todos, int(cmd.split()[1]))
except (ValueError, IndexError):
print("Invalid number.")
else:
print("Unknown command.")
Output
Commands: show, add <task>, done <num>, quit
> add Buy milk
> add Write report
> show
1. [ ] Buy milk
2. [ ] Write report
> done 1
> show
1. [x] Buy milk
2. [ ] Write report
> quit
How it works
The app uses a JSON file (todos.json) for persistent storage across sessions. The load_todos function reads the file if it exists, otherwise returns an empty list. Commands are parsed from user input and modify the in-memory list, and save_todos writes the list back to the file when quitting. Task items are stored as dictionaries with task and done keys, making it easy to extend with fields like priority or due date.
Common mistakes
- Forgetting to call `save_todos` before exiting, causing data loss.
- Not handling the case where `todos.json` is malformed (e.g., corrupted JSON).
- Assuming user input is always well-formed; not catching `ValueError` when parsing numbers.
Variations
- Use a SQLite database instead of JSON for more complex queries and multi-user support.
- Add subcommands with `argparse` for a more polished CLI experience (e.g., `todo add 'Buy milk'`).
Real-world use cases
- Personal task management in a terminal without requiring a GUI.
- A simple project for learning CRUD operations and JSON file I/O in Python.
- Prototyping a lightweight ticketing or issue tracker for small teams.
Sponsored
More from Files & data
- Build a Python Script That Detects and Deletes Empty Files Across Folders easy
- Compare Two Folder Structures and Find Differences in Python easy
- Compress and Extract ZIP Files Programmatically in Python easy
- Convert CSV Files to JSON in Python easy
- Convert Image to ASCII Art in Python medium
- Create a Personal Knowledge Base That Searches Notes Instantly in Python easy
Keep learning
Related tutorials and quizzes for this topic.