First project · 45–60 minutes

Build a receipt parser.

Connect strings, lists, dictionaries, loops, functions, errors, and JSON in one small program. The input is messy on purpose; the output should be predictable.

INPUT

Plain text, not perfect data

Each line should look like name|quantity|price. Some lines will be blank, malformed, or contain a number that cannot be converted.

OUTPUT

One result dictionary

Return items, a grand total, and a list of errors. Printing is only a view of that result, not the result itself.

RULES

Standard library only

Use Python's built-in strings, lists, dictionaries, functions, exceptions, and json module. No packages, files, network, or input().

01 / BUILD PLAN

Five small steps

  1. 01

    Clean the lines

    Split the receipt into lines. Strip whitespace and skip empty lines, but keep the line number so an error message can point to the right row.

  2. 02

    Parse the fields

    Split each line on the pipe character. Require exactly three fields, convert quantity to int and price to float, and reject empty names.

  3. 03

    Validate the values

    A quantity must be positive and a price cannot be negative. Collect an error and continue; one bad row should not destroy the whole receipt.

  4. 04

    Calculate the totals

    Build an item dictionary with a rounded line_total. Sum the line totals once, at the end, so the grand total cannot drift from the rows.

  5. 05

    Return and display

    Return a dictionary with items, total, and errors. Format a readable report in a separate function, then print a JSON summary for inspection.

02 / OUTPUT

The shape to aim for

A predictable structure is easier to test than a pile of printed text.

{
  "items": [
    {"name": "Latte", "qty": 2, "price": 4.5, "line_total": 9.0}
  ],
  "total": 18.75,
  "errors": []
}
03 / WORKSPACE

Your workspace

The starter runs and returns an empty result. Fill in the TODO, then run it. The solution includes the valid receipt and a malformed receipt as a self-check.

Your workspaceRuns locally · no account
First run downloads Pyodide from a CDN. Run the starter, then compare your output with the checks below.
04 / CHECK

Acceptance checks

  • parse_receipt returns a dictionary with items, total, and errors.
  • The valid sample produces three items and a total of 18.75.
  • Blank lines are ignored.
  • Tea|one|3.00 and Broken become errors instead of crashing the program.
  • The solution's self-check prints checks passed.
05 / EXTEND

Take it further

Add a discount

Accept an optional discount rate, validate it, and apply it to the grand total. Keep the original total visible in the result.

Read from CSV

When the csv module is comfortable, replace the pipe-separated fixture with a small CSV file and reuse the same validation.

Write tests first

Turn the three acceptance cases into assert statements. Run them after every change before you touch the formatting.