Before this lesson
Complete Python functions, exceptions and file reading. Understand grouped accumulation in dictionaries.
What you will be able to do
Combine parsing, validation, grouping and sorting into an explainable batch report.
Understand the mechanism
Define course and minutes columns, grouped totals and row-level errors. Separate parsing from reporting. The self-contained sample uses an in-memory stream that can later be replaced by an encoded file.
Use the CSV parser rather than splitting commas because quoted fields can contain delimiters. Validate headers and bounded integer minutes; rejected rows must not contribute to totals.
Accumulate by course and use a deterministic secondary sort key. Report source line numbers and state the partial-success policy instead of implying all rows were accepted.
Extend through explicit edge cases and define duplicate semantics before deduplicating. Identical rows can represent separate sessions rather than accidental copies.
Runnable example
Use Python 3.11 or later. Save lesson.py in a separate practice directory and run python3 lesson.py, or py lesson.py on Windows. Examples use only the standard library.
import csv
from io import StringIO
source = "course,minutes\nPython,25\nSQL,20\nPython,35\nJava,invalid\nSQL,-5\n"
reader = csv.DictReader(StringIO(source))
if reader.fieldnames != ["course", "minutes"]:
raise ValueError("Expected course,minutes headers")
totals = {}
errors = []
for row in reader:
course = (row.get("course") or "").strip()
try:
minutes = int(row.get("minutes") or "")
if not course or not 0 <= minutes <= 240:
raise ValueError("invalid row")
except ValueError:
errors.append(reader.line_num)
continue
totals[course] = totals.get(course, 0) + minutes
for course, minutes in sorted(totals.items(), key=lambda item: (-item[1], item[0])):
print(f"{course}: {minutes}")
print("Rejected lines:", errors)
Trace and verify
Expect Python 60, SQL 20 and rejected lines five and six. Header-only input has no totals. Test quoted names and explicitly decide whether reordered headers are accepted.
Common mistakes and boundaries
This is not an unbounded upload service. The report summarizes records and does not claim duration alone measures learning quality.
Practice challenge
Extract summarize(stream), return totals and errors, then export and re-read a summary CSV.
Reference solution and reasoning
Keep output outside the calculation and use a CSV writer with explicit headers. Test valid, empty and invalid cases, extending diagnostics with reasons.