Data AnalyticsPython foundations for analysts

Build a command-line report with argparse

PK
Pankit Kumar
Sr. Data Scientist at Parexel (a Goldman Sachs–backed company) · 20 September 2026 · 3 min read
Technically reviewed by Ishaan Sharma
In this article (6 sections)

A command-line interface makes a report's inputs visible: source file, reporting period and output location become arguments rather than edits inside a script. That helps a colleague or scheduler reproduce the same operation without opening a notebook.

The interface is only useful when its validation, output contract and exit status are equally explicit. A program that accepts a month but quietly ignores it is reproducible in the wrong way.

Run the supplied report

Open a terminal in the Python reporting lab directory and inspect the interface:

text
python report.py --help
python report.py --input raw_orders.csv --output my-january-report --month 2026-01

The second command creates accepted_orders.csv, rejected_records.csv and summary.json inside the named directory. It overwrites those filenames on a repeated run, so use a deliberate output location.

Expected January summary values are four paid orders, two known customers and INR 47.50. The source contains three rejected records and one identical replay. Accordingly, the report is marked partial and exits with code 2 under this lab's convention.

Separate argument parsing from business validation

The script uses argparse to require input, output and month arguments, with pathlib.Path for filesystem values. Its month_bounds function then checks the YYYY-MM format and calendar validity.

Missing an argument is an interface error. Supplying 2026-13 reaches business validation and fails because that month does not exist. Keeping these responsibilities distinct makes the error easier to diagnose.

The standard-library argparse documentation covers required options, type conversion and generated help. The lab deliberately uses a small compatible feature set and was executed with Python 3.12.0.

Test the public interface, not just internal functions

This example starts the actual script with the current Python interpreter and uses a temporary output directory:

python
import json
from pathlib import Path
import subprocess
import sys
from tempfile import TemporaryDirectory

with TemporaryDirectory() as directory:
    output = Path(directory) / "january"
    result = subprocess.run(
        [sys.executable, "report.py", "--input", "raw_orders.csv",
         "--output", str(output), "--month", "2026-01"],
        capture_output=True, text=True, check=False,
    )
    assert result.returncode == 2
    summary = json.loads((output / "summary.json").read_text(encoding="utf-8"))
    assert summary["paid_amount_inr"] == "47.50"
    assert summary["quality_status"] == "partial_rejected_records"
    assert json.loads(result.stdout) == summary
    print("CLI exit status and written summary agree")

Passing arguments as a list avoids constructing a shell command from filenames. check=False is intentional because this fixture's partial result is expected; the assertion still rejects an unexpected status.

Keep machine output and diagnostics usable

The program prints JSON to standard output and sends logging diagnostics to standard error. A caller can parse the JSON without first deleting warning lines. The saved summary remains the durable local artifact for review.

Do not infer success solely from the existence of an output file. A prior run could have created it. Validate the current process result and the source hash recorded in the current summary.

For production scheduling, use an explicit working directory or absolute paths, record the interpreter environment and define how partial reports are handled. This small lab does not implement atomic publication of multiple output files or a production retry system.

Make errors part of the interface

Try a missing input path, an invalid month and a conflicting order ID in a copied fixture. Each should fail visibly. Also run --help without data access: help should describe usage rather than require a successful report first.

The lab's 15-test suite includes the partial-result CLI path and separate validation cases. Adding a new option should include a test of its observable effect, not merely a check that argparse accepted the spelling.

Exercise: run January and February into separate directories. Verify INR 47.50 and INR 17.00 respectively, and write a short handoff explaining why both reports carry the same source-level rejection count.

NeuraPath's Data Analytics with Generative AI course connects Python scripting with repeatable reporting. A clear CLI turns an analysis into something another person can run and inspect.

Continue learning

This article is part of the Python foundations for analysts sequence. Use the neighbouring tasks when you need the prerequisite or the next application.

PK
Pankit Kumar
Lead Instructor, NeuraPath Academy

Pankit Kumar has 10 years in Data Science & AI, building and shipping production systems in regulated pharma and clinical environments. He is a freelance trainer at Boston Institute of Analytics, AnalytixLabs and Scaler, and has taught this material to thousands of working professionals.

This article is part of our Data Analytics with Generative AI programme — 3–4 months. The full analyst stack — Excel, SQL, Power BI and Python pipelines — then a generative-AI layer you can prove is right.

Explore Data Analytics with Generative AI
Counselling is free · no obligation

Not sure which programme fits?

Tell us your background and we will map it to the right entry point — including saying so when a cheaper programme is the better fit. A counsellor replies within one working day.