Project 9 — Budget Tracker
Track income and expenses by category. Generate monthly summaries, spending breakdowns, and savings rate reports — all stored in CSV.
What you'll learn
- 1Model transactions with a dataclass
- 2Categorize income vs. expense transactions
- 3Compute monthly totals, savings rate, and top expenses
- 4Load and save all data to CSV
Transaction Model
@dataclass
class Transaction:
date: str # YYYY-MM-DD
type: str # income | expense
amount: float
category: str # food, transport, salary, ...
note: str = Commands
- add <income|expense> <amount> <category> [note]
- list [--month YYYY-MM]
- summary [--month YYYY-MM]
- categories — show all categories with totals
- export <filename.csv>
Common Mistakes (FAQ)
Q. My totals are off by a cent (e.g. 0.1 + 0.2 = 0.30000000000000004).
Floating-point can't represent money exactly. For display, round(total, 2); for exact arithmetic, store amounts as integer cents (7250 = $72.50) or use decimal.Decimal. Pick one and stay consistent.
Q. Should expenses be negative or positive?
Cleanest: store a positive amount plus a type field ('income'/'expense'), then balance = sum(income) − sum(expense). Mixing signed amounts and a type field double-counts — choose one convention.
Q. How do I filter by month?
With ISO dates (YYYY-MM-DD), a string prefix compare is enough: tx.date[:7] == '2024-05'. No datetime parsing needed for month filtering.
Q. KeyError when totaling a new category.
Use collections.defaultdict(float) (or totals.get(cat, 0)) so a never-seen category starts at 0 instead of raising.
Q. After reloading the CSV, amounts won't add up.
The csv module returns every field as a string — '50' + '20' is '5020'. Convert on load: amount = float(row['amount']). Also write with newline='' on Windows to avoid blank rows.
📝 Exercises
Try them yourself first, then open the solution to compare.
Build the budget tracker
Goal: Implement all commands with CSV storage.
- Transaction dataclass
- add/list/summary/categories commands
- CSV persistence
- Monthly filtering
All lecture materials and example code are openly available on GitHub.
View on GitHub ↗