Building a Personal Task Manager in Python: Journey, Functionality & Debugging


Introduction
As a beginner learning Python, I wanted to build a project that ties together many concepts I’ve recently learned — classes, decorators, file handling, JSON, exception handling, and more. This led me to create a Personal Task Manager, a simple yet functional CLI app that helps manage tasks with categories, timestamps, and status tracking.
In this article, I have shared my journey building it, explained how it works under the hood, and discussed some of the bugs I faced and fixed along the way. You can check the project out on GitHub here:
🔗 Personal Task Manager on GitHub
Why This Project?
I wanted something simple but meaningful. A task manager checked all the boxes:
Helps reinforce OOP concepts
Involves file operations and JSON
Uses decorators, timestamps, and error handling
Can be run from the command line, mimicking real-world utility
Features of the Task Manager
Add tasks with categories and timestamps
View all tasks with status and metadata
Mark tasks as done
Delete tasks
View tasks filtered by category
Persistent storage with JSON files
Logging decorator to track method calls
How It Works
The whole logic is organized in a clean TaskManager
class (inside taskmanager.py
) with the following flow:
Tasks are stored in a list of dictionaries.
Each task has attributes like
task
,done
,timestamp
, andcategory
.All actions (add, delete, mark done, view) call a central
save_tasks()
to update thetasks.json
file.A decorator wraps key functions to log what’s being executed.
The
run.py
script allows users to interact via a simple CLI.
Going Underneath: How Each Action Works
1. Add Task
When you add a task, the program creates a dictionary containing the task description, a “done” status set to False
, the current timestamp, and the category. This dictionary is appended to a list of tasks, which is then saved to a JSON file to persist data.
2. View Tasks
The program checks if any tasks exist and iterates through each one, displaying its index, completion status, task text, category, and timestamp in a neat, readable format.
3. Mark as Done
To mark a task done, the program updates the “done” flag for the task at the specified index, then saves the updated list back to the file.
4. Delete Task
Deletion removes the task from the internal list by index and saves the updated list to the file.
5. View by Category
Filtering by category scans all tasks and prints only those that match the user’s chosen category, ignoring case sensitivity.
6. Logger Decorator
A custom decorator wraps key methods to print log messages when they are called. This helped me track program flow during development and debugging.
7. File Operations
The program reads from and writes to a tasks.json
file using Python’s json
module. It gracefully handles missing or corrupted files by starting fresh if needed.
Bugs and Debugging
Fixing KeyError Due to Inconsistent Task Data Keys in JSON Storage:
One major bug I encountered was regarding incorrect use of dictionary keys — specifically, a KeyError
caused by mismatched key names like "task"
vs "title"
. Learned about the importance of consistent naming and carefully checking data structures.*
Another challenge was ensuring the program didn’t crash when the task file was missing or empty. Adding exception handling around file loading solved this, letting the program start with an empty list gracefully.
I also implemented a logging decorator that prints function calls, which made it easier to trace execution during testing.
*The program faced a runtime KeyError because it tried to access a key ("task") in task dictionaries that wasn’t always present. This happened when older saved data used a different key name ("title") for the task description. The inconsistency in data structure caused the code to break during task display or manipulation. To resolve this, the fix involved updating the data loading logic to detect and normalize these key differences—specifically, converting any "title" keys to "task" when loading tasks from the JSON file. This ensured all tasks followed a consistent format, preventing errors and improving robustness when handling persisted data.
Final Thoughts
This project was a great learning experience to combine many Python concepts into a useful tool. I’m excited to keep improving it, perhaps adding a GUI or integrating with online task services.
Feel free to check out my code on GitHub, and reach out if you have any tips or feedback!
Subscribe to my newsletter
Read articles from Sagnik Dev directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
