Practical data workflows
Project: validated study report
Read CSV, validate records, and write grouped totals.
Lesson 63 of 63
Reading: about 2 min
Lesson + practice: about 22 min
Difficulty: Intermediate
On this page5 sections
Build an end-to-end practice workflow. The example creates its own input file, demo_sessions.csv, so it never touches the practice bundle.
For file practice, download the Python practice files v1.0.0 bundle. The examples write their own files, so the samples stay unchanged. Work on a copy if you edit a sample.
Worked example
import csv
from collections import defaultdict
from pathlib import Path
source = Path("demo_sessions.csv")
source.write_text("subject,minutes\nPython,20\nSQL,25\nPython,30\n", encoding="utf-8")
totals = defaultdict(int)
with source.open(newline="", encoding="utf-8") as file:
reader = csv.DictReader(file)
if reader.fieldnames != ["subject", "minutes"]:
raise ValueError("unexpected CSV columns")
for row in reader:
line_number = reader.line_num
if None in row:
raise ValueError(f"extra field on line {line_number}")
subject = row["subject"]
if not isinstance(subject, str) or not subject.strip():
raise ValueError(f"invalid subject on line {line_number}")
try:
minutes = int(row["minutes"])
except (TypeError, ValueError) as error:
raise ValueError(f"invalid minutes on line {line_number}") from error
if minutes <= 0:
raise ValueError(f"invalid minutes on line {line_number}")
totals[subject.strip()] += minutes
with Path("summary.csv").open("w", newline="", encoding="utf-8") as file:
writer = csv.writer(file)
writer.writerow(["subject", "minutes"])
for subject in sorted(totals):
writer.writerow([subject, totals[subject]])
print(Path("summary.csv").read_text(encoding="utf-8"), end="")subject,minutes Python,50 SQL,25
Why this works
The pipeline parses text, rejects missing or extra fields, accumulates totals, and writes a sorted CSV. reader.line_num reports the physical line where a record ends.
Another case
Check an export by reading it back: the subject totals should add up to the total of the source rows.
import csv
from io import StringIO
exported = StringIO("subject,minutes\nPython,50\nSQL,25\n")
print(sum(int(row["minutes"]) for row in csv.DictReader(exported)))75
Practice
Point source at your copy of the sample sessions.csv from the practice bundle and delete the write_text line. Add a row SQL,5 to that copy, rerun, and predict the exported totals.
Check the practice result
Reveal answer
The SQL total becomes 30; Python remains 50.
Try another case
If one row had minutes 0, what would the script do?
Check your answer
Reveal answer
It stops with ValueError("invalid minutes on line N") before writing summary.csv.
Your progress
Reveal the check answer or reach the end to complete this lesson.