Project 14 — CSV Report CLI
Analyse a CSV file from the command line: filter rows, compute statistics, and generate HTML and Markdown reports using Pandas and Jinja2 templates.
What you'll learn
- 1Load and validate CSV with Pandas
- 2Filter, group, and aggregate data
- 3Render an HTML report with a Jinja2 template
- 4Export filtered data to a new CSV
Usage
csvreport data.csv --group department --agg mean --cols salary,age
csvreport data.csv --filter 'salary > 50000' --output filtered.csv
csvreport data.csv --html report.html
csvreport data.csv --md report.mdCommon Mistakes (FAQ)
Q. A comma inside a field splits my row wrong.
Don't parse CSV with line.split(','). Use pandas.read_csv (or the stdlib csv module) — they correctly handle quoted fields like "Smith, John" and embedded commas/newlines.
Q. I get a UnicodeDecodeError or mojibake on a CSV from Excel.
Excel often saves UTF-8 with a BOM. Read with encoding='utf-8-sig' (handles BOM and plain UTF-8); for legacy Korean files try 'cp949'. Always pass an explicit encoding rather than relying on the OS default.
Q. --filter 'salary > 50000' — how do I apply it safely?
Use df.query("salary > 50000") instead of eval(). Column names with spaces need backticks in the query string: df.query("`net pay` > 50000").
Q. My exported CSV has a blank line between every row (Windows).
With the csv module, open the file with newline='' . With pandas, df.to_csv('out.csv', index=False) avoids both the blank-line issue and an unwanted index column.
Q. group + aggregate returns a weird multi-index.
df.groupby('department')[['salary','age']].mean().reset_index() flattens it back to plain columns — call reset_index() before rendering to HTML/Markdown.
📝 Exercises
Try them yourself first, then open the solution to compare.
Build the CSV report CLI
Goal: Implement filtering, grouping, and HTML/Markdown output.
- --filter flag with pandas query
- --group and --agg flags
- HTML report with Jinja2
- CSV export of filtered results
All lecture materials and example code are openly available on GitHub.
View on GitHub ↗