Expense summary command-line tool
Turn lines of expense data into a trustworthy summary. The program reads category and amount pairs, rejects malformed entries without crashing, totals valid expenses by category and prints both a category report and the overall spend.
Skills you will practise
- input parsing
- dictionaries
- functions
- exceptions
- sorting and formatting
Project requirements
- Read until the input ends.
- Accept lines in category,amount format.
- Skip empty, malformed, negative or non-numeric amounts.
- Print categories alphabetically with amounts to two decimal places.
- Print the grand total and the number of rejected lines.
Build it in stages
- 1
Parse one record
Write a function that splits once at the comma, trims both fields and converts the amount to float. Return a clear success or failure result.
- 2
Accumulate valid expenses
Use a dictionary keyed by category. Add repeated categories instead of replacing their previous totals.
- 3
Track rejected input
Catch only the conversion and shape errors you expect. Count rejected lines without hiding unrelated programming mistakes.
- 4
Render the report
Move formatting into a function that sorts categories, prints fixed two-decimal amounts and ends with the overall total and rejected count.
Starter code
def parse_expense(line):
# Return (category, amount) or None.
pass
totals = {}
rejected = 0
# Read lines, validate them and build the report.
Expected result
For input food,12.50 / travel,8 / food,3.25 / broken, the report contains food 15.75, travel 8.00, total 23.75 and rejected 1.
Progressive hints
Hint 1
split(',', 1) prevents extra commas from silently creating too many fields.
Hint 2
Use totals.get(category, 0) when adding a repeated category.
Hint 3
Keep calculation values numeric; apply :.2f only when printing.
Solution guidance
Show the approach after you attempt the project
The maintainable design has three parts: parse one line, accumulate valid data and render the finished report. This separation makes boundary cases testable without simulating the whole program. Catch ValueError around float conversion, reject non-positive categories or negative amounts explicitly, and let unexpected exceptions surface. Dictionary accumulation preserves one source of truth, while sorting only at output time avoids coupling storage to presentation.