Parameterize reports by date and region safely
In this article (6 sections)
Report parameters should make a calculation reusable without making its meaning ambiguous. Validate dates, timezones, allowed regions and required fields before reading data. Record the selected parameters with the output so the result can be reproduced.
A missing filter should not silently mean “all regions” unless that is the explicit contract. Likewise, an invalid date should fail rather than fall back to today's date and produce a different report.
Define a small configuration contract
The original automation configuration has four required fields: period start, period end, region and maximum extraction lag.
Timestamps must use the fixture's UTC format, and start must precede end. Region must be one of all, North, South or Unknown. Extraction lag must be a nonnegative integer number of seconds.
Unknown configuration keys are rejected. That catches misspelled settings instead of letting the script ignore them while the analyst believes a filter was applied.
Test each allowed region and invalid input
import json
from pathlib import Path
from pipeline import load_source,validate_config,ReportError
base = json.loads(Path('report-config.json').read_text())
totals = {}
for region in ('all','North','South','Unknown'):
selected,metrics,evidence = load_source('events.csv','source-manifest.json',dict(base,region=region))
totals[region]=metrics['amount_paise']
assert totals=={'all':3500,'North':1000,'South':2000,'Unknown':500}
assert totals['North']+totals['South']+totals['Unknown']==totals['all']
invalid = [dict(base,region='north'),dict(base,region="North' OR 1=1 --"),
dict(base,period_start=base['period_end']),
dict(base,period_end='2026-01-12'),dict(base,extra_filter=True)]
for config in invalid:
try:
validate_config(config)
except ReportError:
pass
else:
raise AssertionError('invalid configuration accepted')
print({'verified_region_totals_paise':totals,'invalid_cases_rejected':len(invalid)})Lowercase north is rejected under this exact-value contract. Another interface could normalize it deliberately, but that normalization should be documented and tested. The example does not accept arbitrary expressions as filters.
Separate validation from query parameter binding
This pipeline filters parsed records in Python. If a report queries a database, use the database driver's parameter binding for values rather than interpolating user text into SQL. An allowlist provides business validation; parameter binding provides a separate query-construction safeguard.
Table names, column names and sort directions generally need controlled selection from known query structures rather than ordinary value binding. Do not pass a free-form SQL fragment as a convenient “advanced filter” without a carefully designed authorization and query policy.
The region string resembling SQL syntax above is simply rejected. No database request or injection attempt is made by this teaching example.
Preserve the parameter set in run identity
The lab hashes a canonical representation of configuration into the report's run identity. Changing all to North produces a different output version, while reordering JSON keys does not change the canonical configuration hash.
This makes the analytical scope inspectable. A filename such as weekly_report.csv alone cannot tell a reviewer which region or period it contains.
Be deliberate about parameters that affect evidence versus presentation. A different currency conversion policy changes the analytical result; a different chart color may not. The versioning design should reflect the reproducibility claim being made.
Check source readiness for the requested period
Valid parameters do not guarantee valid source coverage. The pipeline separately checks that the source watermark reaches the requested end and that extraction timing fits the contract.
If a user requests a period beyond the source's coverage, return a clear failure instead of a partial total presented as complete. For an empty but fully covered period, an observed zero can be legitimate; distinguish that from an unavailable source.
Exercise: serialize the same configuration with different JSON key order and verify that the canonical configuration hash stays the same. Then change only the region and verify that the run identity changes while the original output remains available.
NeuraPath's Data Analytics with Generative AI course connects reusable scripts with precise business scope. Good parameterization makes variation explicit while preserving validation and reproducibility.
Continue learning
This article is part of the Reliable reporting automation sequence. Use the neighbouring tasks when you need the prerequisite or the next application.
- Review the prerequisite or neighbouring task in Build a reconciliation step into every automated report.
- Continue with Separate secrets from report configuration.
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