Repository navigation
[EPA_USAirPollutantEmissionTrends_NationalAndState] Updated config.json for latest updated data - #2282
Conversation
There was a problem hiding this comment.
Code Review
This pull request enhances the US EPA Air Emissions Inventory pipeline by introducing an automatic fallback mechanism to scrape live EPA trends page URLs when GCS configuration URLs are unreachable, improving Excel sheet and column parsing, and adding a validation configuration. However, the review feedback highlights critical issues regarding exception handling and error propagation in both download.py and process.py. Specifically, several exception handlers swallow fatal errors instead of raising them, which would cause the pipeline to exit with a success status code (0) despite failing. Additionally, the review points out a potential casting bug when parsing the 'year' column and suggests more robust checks for empty input directories.
pulkeet-wq
left a comment
There was a problem hiding this comment.
Review scope
- Target: PR #2282 (
datacommonsorg/data, basemaster@0907f507b70c1cf69ea05fcada5a42eb6624edb4→ headEPA_US@6eb87a3d23bb16baae2d5d7128ff172b6426e954; 6 changed files,+393/-93) - Reviewed:
scripts/us_epa/air_emissions_inventory/national_state/README.md(1 changed hunk, lines 52–80)scripts/us_epa/air_emissions_inventory/national_state/download.py(3 changed hunks, lines 18–317)scripts/us_epa/air_emissions_inventory/national_state/manifest.json(1 changed hunk, lines 18–28)scripts/us_epa/air_emissions_inventory/national_state/process.py(7 changed hunks, lines 30–400)scripts/us_epa/air_emissions_inventory/national_state/process_test.py(2 changed hunks, lines 12–118)scripts/us_epa/air_emissions_inventory/national_state/validation_config.json(new file, lines 1–28)
- Skipped: None
Findings
No actionable findings (P0–P3) were identified in the reviewed change set. All 9 review comments from earlier commits on PR #2282 have been properly addressed in head commit 6eb87a3d23bb16baae2d5d7128ff172b6426e954.
Positive findings
scripts/us_epa/air_emissions_inventory/national_state/download.py:104-295- Resilient two-tier URL resolution and atomic streaming downloads ✓- Finding: Good - Automatically falls back to scraping
https://www.epa.gov/air-emissions-inventories/air-pollutant-emissions-trends-datafornational_tier1_caps*.xlsxandstate_tier1*ktons.xlsxwhen the static URLs ings://unresolved_mcf/us_epa/config.jsonreturn HTTP 404 after an EPA release update, reuses arequests.Sessionwith exponential backoff (Retry(total=5, backoff_factor=2, status_forcelist=[429, 500, 502, 503, 504])), cleans stale.xlsx/.xls/.tmpartifacts before downloading, and writes files atomically via.tmp+os.replaceafter verifyingfile_size > 0.
- Finding: Good - Automatically falls back to scraping
scripts/us_epa/air_emissions_inventory/national_state/process.py:167-210- Dynamic header-row detection and strict year-column validation ✓- Finding: Good - Dynamically detects whether
State FIPSis on row0(skiprows=0, September 2026 release layout) or row1(skiprows=1, legacy layout), supports bothState TrendsandState_Trendsworksheet names, normalizes both 2-digit (emissions99,emissions01) and 4-digit (emissions1990,emissions2025) year headers, and explicitly raises aValueErrorif any unexpected non-year column is melted (years.isna().any()).
- Finding: Good - Dynamically detects whether
scripts/us_epa/air_emissions_inventory/national_state/validation_config.json:1-28- Complete date-consistency, date-freshness, and deletion-threshold validation ✓- Finding: Good - Configures
MAX_DATE_CONSISTENT(check_max_date_consistent), aSQL_VALIDATORfreshness rule (MaxDate >= '2025'), andDELETED_RECORDS_PERCENT(threshold: 0.1), matching the uniformMaxDate = 2025across all 169 StatisticalVariables insummary_report.csv.
- Finding: Good - Configures
Coverage
| File | Status | Result |
|---|---|---|
scripts/us_epa/air_emissions_inventory/national_state/README.md |
Reviewed | No findings |
scripts/us_epa/air_emissions_inventory/national_state/download.py |
Reviewed | No findings |
scripts/us_epa/air_emissions_inventory/national_state/manifest.json |
Reviewed | No findings |
scripts/us_epa/air_emissions_inventory/national_state/process.py |
Reviewed | No findings |
scripts/us_epa/air_emissions_inventory/national_state/process_test.py |
Reviewed | No findings |
scripts/us_epa/air_emissions_inventory/national_state/validation_config.json |
Reviewed | No findings |
Verification and limitations
- Checks run:
./run_tests.sh -p scripts/us_epa/air_emissions_inventory/national_statein a detached worktree at PR head6eb87a3d23bb16baae2d5d7128ff172b6426e954(Ran 6 tests in 1.344s — OK).- Inspected production baseline
gs://datcom-prod-imports/scripts/us_epa/air_emissions_inventory/national_state/EPA_USAirPollutantEmissionTrends_NationalAndState/latest_version.txt(2026_09_01T03_04_59_556608_07_00) and itsinput0/genmcf/summary_report.csv(169 StatVars, uniformMaxDate = 2024). - Inspected GCS configuration
gs://unresolved_mcf/us_epa/config.json(verified updated to2026-09/national_tier1_caps_04sep2026.xlsxand2026-09/state_tier1_1990_2025_04sep2026_ktons.xlsx). - Inspected test Cloud Batch run
gs://datcom-import-test/scripts/us_epa/air_emissions_inventory/national_state/EPA_USAirPollutantEmissionTrends_NationalAndState/2026_10_16T04_55_51_589052_07_00/(import_summary.json,input0/genmcf/summary_report.csv,input0/validation/validation_output.csv, andsource_files/**): verified 248,352 rows processed across 169 StatVars with uniformMaxDate = 2025,missing_refs_count: 0,lint_error_count: 0, retainedsource_files/input_files/*.xlsxandsource_files/validation_config.json, and all 6 validation checksPASSED.
- Checks not run:
- Live download from
www.epa.gov(not run per review guidelines; verified via GCS test run artifacts and hermetic unit tests).
- Live download from
- Limitations: None.
Summary
Fixes the
EPA_USAirPollutantEmissionTrends_NationalAndStateimport (b/574320356) to support the U.S. EPA's September 2026 (1970–2025 Air Pollutant Emissions Trends Data) release (national_tier1_caps_04sep2026.xlsxandstate_tier1_1990_2025_04sep2026_ktons.xlsx), hardens the download and processing scripts against upstream URL/layout changes, and adds import-specific validation rules.Root Cause
04sep2026) and retired the previous February 2025 URLs (2025-04/national_tier1_caps_21feb2025.xlsxand2025-04/state_tier1_21feb2005_ktons.xlsx), causingdownload.pyto fail withHTTP Error 404: Not Found.skiprows=0vs.skiprows=1):state_tier1_1990_2025_04sep2026_ktons.xlsxworkbook, EPA removed the title row above the header row on the'State Trends'worksheet, shifting the'State FIPS'header row from row1(skiprows=1) to row0(skiprows=0).Changes Made
scripts/us_epa/air_emissions_inventory/national_state/download.py:requests.Session()with exponential backoff retry (Retry(total=5, backoff_factor=2, status_forcelist=[429, 500, 502, 503, 504])).scrape_epa_trends_urls/resolve_download_urls) that scrapeshttps://www.epa.gov/air-emissions-inventories/air-pollutant-emissions-trends-datafor the latestnational_tier1_caps*.xlsxandstate_tier1*ktons.xlsxURLs whenever the GCS config URLs (gs://unresolved_mcf/us_epa/config.json) return non-200.HEAD-first URL probing (withGETfallback on HTTP403/405), query-string stripping on.xlsxfilenames, atomic downloads via.tmp+os.replace, non-empty file size verification, and cleanup of stale.xlsx/.xls/.tmpfiles prior to download.scripts/us_epa/air_emissions_inventory/national_state/process.py:_state_emissions()to dynamically detect whether'State FIPS'is on row0(skiprows=0) or row1(skiprows=1) and support both'State Trends'and'State_Trends'sheet names._state_emissions()to handle both 2-digit (emissions99,emissions01) and 4-digit (emissions1990,emissions2025) year headers while explicitly rejecting unparseable column headers (years.isna()).inplace=Truecalls with explicit assignments (pd.to_numeric(..., errors='coerce')) for Pandas 2.x/3.x compatibility, and removed unreachableraisestatements afterabsl.logging.fatal().scripts/us_epa/air_emissions_inventory/national_state/validation_config.json&manifest.json:validation_config.jsonand registeredvalidation_config_fileandsource_filesinmanifest.json:check_deleted_records_percent(DELETED_RECORDS_PERCENT,threshold: 0.1): Enforces a0.1%deletion threshold across refreshes. (Note: For the initial transition from the Feb 2025 release to the Sept 2026 2023-NEI restatement, 909 [0.38%] state cells in 2022–2024 changed from0.00placeholder values to blank/NaNupstream as documented in the workbook'sREADMEandDevelopmentOfDatasheets;latest_version.txtwas updated to the verified Sept 2026 baseline).check_max_date_consistent(MAX_DATE_CONSISTENT): VerifiesMaxDate(2025) is uniform across all169StatVars.check_max_date_freshness(SQL_VALIDATOR): VerifiesMaxDate >= '2025'across all StatVars.scripts/us_epa/air_emissions_inventory/national_state/process_test.py:skiprows=0state worksheet parsing, 2/4-digit year parsing, HTML URL scraping/fallback resolution (scrape_epa_trends_urls,resolve_download_urls), and stale file cleanup (_clean_download_directory).scripts/us_epa/air_emissions_inventory/national_state/README.md:gs://unresolved_mcf/us_epa/config.json) and automatic fallback URL discovery mechanism.Verification & Cloud Batch Test Run
./run_tests.sh -p scripts/us_epa/air_emissions_inventory/national_state(Ran 6 tests — OK)input0/validation/validation_output.csv— all 6 rulesPASSED): https://console.cloud.google.com/storage/browser/_details/datcom-import-test/scripts/us_epa/air_emissions_inventory/national_state/EPA_USAirPollutantEmissionTrends_NationalAndState/2026_10_16T04_55_51_589052_07_00/input0/validation/validation_output.csv?project=datcom-infosys-dev