01 Learn
Memory disappears; files persist.
A TaskManager list exists only while the program runs. JSON is familiar structured text: json.dump() writes Python lists and dictionaries to a file, while json.load() reads them back.
import json
def save_tasks(self, path="data/tasks.json"):
data = {"task_id": task.task_id, "title": task.title, "completed": task.completed}
with open(path, "w", encoding="utf-8") as file:
json.dump([data], file, ensure_ascii=False, indent=2)
JSON cannot directly store a custom Task object. Save a dictionary with task_id, title, and completed, then create a new Task from that dictionary after loading.
save_tasks(path="data/tasks.json") and load_tasks(path="data/tasks.json") use the default path for normal work. In a test, pass a separate path so test data never changes your real data/tasks.json file. A successful load replaces self.tasks rather than appending to it, so repeated loading does not create duplicates.
↳Clear file policy: If the selected path does not exist, load_tasks() leaves the current list unchanged. If JSON is invalid, report a readable error and keep the current list unchanged.
Reconstructing one Tasksaved = {"task_id": "task-1", "title": "Read", "completed": True}
task = Task(saved["task_id"], saved["title"])
task.completed = saved["completed"]
The dictionary holds plain JSON values. The reconstructed Task is again an object with attributes and methods.
Save and load predictably
- Save plain dataConvert every Task into a dictionary, then use json.dump() with encoding="utf-8".
- Load a fresh listRead JSON with json.load(), reconstruct Task objects, and replace self.tasks only after successful loading.
Common JSON persistence mistakes
- Trying to dump a Task object directlyjson.dump() needs dictionaries, lists, strings, numbers, booleans, and null-like values, not custom objects.
02 Work locally
Keep Your Tasks Between Runs
Do this in VS Code
Continue in the Task Manager project from Concepts 28 and 29. You will add JSON persistence to this same project, not create or download a new one.
Your existing Task Manager projecttask_manager/
├── main.py
├── models/
│ └── task.py
├── services/
│ └── task_manager.py
└── data/
└── tasks.json
Keep the Task and TaskManager methods you already built. The data folder will hold a JSON file created by your program.
Add persistence step by step
- Open the existing projectOpen the same project folder in VS Code. You will work mainly in models/task.py, services/task_manager.py, main.py, and the data folder.
- Recognize the JSON shapeOne Task object becomes one dictionary. A JSON file stores a list of those dictionaries, not Python Task objects.
- Plan the object conversionWrite down the three values every saved task needs: task_id, title, and completed. Then decide how you will create a new Task and restore its completed value after reading a dictionary.
task_data = {
"task_id": task.task_id,
"title": task.title,
"completed": task.completed,
}
- Implement save_tasks()In services/task_manager.py, import json and add an optional path parameter with the default "data/tasks.json". Convert the current list into plain dictionaries, then write that list to path with UTF-8 encoding. Calling save_tasks() uses the normal project file; a test can pass a separate path.
def save_tasks(self, path="data/tasks.json"):
with open(path, "w", encoding="utf-8") as file:
json.dump(tasks_data, file, ensure_ascii=False, indent=2)
- Implement load_tasks() safelyGive load_tasks() the same optional path parameter. Read that path, reconstruct Task objects into a fresh list, and assign self.tasks only after all reading and reconstruction succeed. If the selected file is missing, leave the current list unchanged. If JSON is invalid, show a readable error and keep the current list.
def load_tasks(self, path="data/tasks.json"):
with open(path, encoding="utf-8") as file:
saved_tasks = json.load(file)
- Demonstrate a complete save and loadIn main.py, add two tasks, save them, inspect the created JSON file, then start the program again and load the saved tasks before listing them.
python3 main.py
# or: python main.py
Example JSON file[
{"task_id": "task-1", "title": "Read the plan", "completed": false},
{"task_id": "task-2", "title": "Write notes", "completed": true}
]
JSON uses plain values. The dictionary describes task data; your Python code reconstructs the Task object after loading.
↳Manual check: add two tasks → save_tasks() → inspect data/tasks.json → restart → load_tasks() → list_tasks() After restarting, the two saved tasks should appear once. Test a missing file and invalid JSON separately without losing tasks already held in memory.
Before asking Sloby for help
- Check the JSON file pathRun main.py from the project folder so the relative path data/tasks.json points to the data folder you expect.
- Do not dump Task objects directlyA TypeError means json.dump() received a Task object. Convert every Task to a dictionary first.
- Handle a missing file calmlyFileNotFoundError is a normal first-run case. Explain it clearly and leave the current task list unchanged.
- Keep invalid JSON safeCatch JSONDecodeError, report that the file cannot be read, and do not replace self.tasks with partial data.
- Avoid duplicate tasks after loadingDo not append loaded tasks to self.tasks. Build a fresh list and replace self.tasks only after successful loading.