Skip to content

Encode HUD Fair Market Rents as a CSV-backed lookup (Phase 1)#8318

Open
PavelMakarchuk wants to merge 2 commits into
mainfrom
hud-fmr-encoding
Open

Encode HUD Fair Market Rents as a CSV-backed lookup (Phase 1)#8318
PavelMakarchuk wants to merge 2 commits into
mainfrom
hud-fmr-encoding

Conversation

@PavelMakarchuk
Copy link
Copy Markdown
Collaborator

Summary

Phase 1 of the housing-payment-standards work discussed with Matt Unrath: stand up a HUD Fair Market Rent data store so future Section 8 / LIHTC / housing-aid variables have a faithful, refreshable national source of truth.

Pattern mirrors the existing ACA SLCSP rating-areas approach (parameters/gov/hhs/medicaid/geography/): a CSV in the parameter tree, loaded once at import via a sibling __init__.py, queried at variable-formula time with a pandas merge.

What's in this PR

File Purpose
policyengine_us/parameters/gov/hud/fmr/fair_market_rents.csv County × bedrooms × year FMR lookup table
policyengine_us/parameters/gov/hud/fmr/__init__.py Loads the CSV with county_fips as zero-padded string
policyengine_us/parameters/gov/hud/fmr/README.md Schema, refresh workflow, regulatory references
policyengine_us/variables/gov/hud/hud_fair_market_rent.py New variable; returns monthly FMR × 12 for the household's county
policyengine_us/tools/download_hud_fmr.py One-shot script that fetches the full ~3,000-row county file via the HUD API
policyengine_us/tests/policy/baseline/gov/hud/hud_fair_market_rent.yaml 4 lookup tests (LA County FY2025, unmapped county, multi-bedroom, year-not-in-data)
changelog.d/hud-fmr-encoding.added.md

What's deliberately out of scope

  • SAFMR ZIP-level resolution. Phase 1B. Drops in via another CSV (small_area_fair_market_rents.csv) and a sibling lookup; same pattern.
  • PHA actual payment standards (Matt's spreadsheets). Phase 2. Overlay table layered on top of the FMR store; the lookup chain becomes PHA → SAFMR → county FMR with a source_level companion variable for provenance.
  • Refactoring pha_payment_standard.py away from its current LA-County hardcoded prototype. Deferred to Phase 2 so existing tests stay green and the data-infrastructure piece can land cleanly first.
  • Multi-year backfill beyond FY2025. The download script appends, so 2018-2024 lands by re-running with --year YYYY.

Seed data note

The CSV currently has 5 placeholder LA County rows (one per bedroom count) so the new variable's tests have something concrete to bind to. These should be replaced before merge by running tools/download_hud_fmr.py with a free HUD API key (register at https://www.huduser.gov/hudapi/). I'm leaving the PR in draft until that swap happens.

Test plan

  • policyengine-core test policyengine_us/tests/policy/baseline/gov/hud -c policyengine_us — 70 passed (4 new + 66 existing, no regressions)
  • make format clean
  • Replace placeholder CSV with real FY2025 county FMR data via download_hud_fmr.py
  • CI green

🤖 Generated with Claude Code

Phase 1 of housing-payment-standards work: establish a HUD-FMR data
store separate from the existing LA-only pha_payment_standard
prototype. CSV pattern mirrors the ACA SLCSP rating-areas approach
(parameters/gov/hud/fmr/fair_market_rents.csv loaded by sibling
__init__.py).

- New variable hud_fair_market_rent looks up monthly FMR by
  (county_fips, bedrooms, year) and returns annualised dollars.
- Seed CSV ships with a placeholder LA County FY2025 row so tests
  bind to real schema; tools/download_hud_fmr.py populates the full
  ~3,000-row county file from HUD's API with a free key.
- README documents the schema, refresh workflow, and Phase 1B
  follow-up (SAFMR ZIP-level resolution).

pha_payment_standard.py untouched — Phase 2 will refactor it to
read from the FMR store with a PHA-actual overlay layered on top.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@codecov
Copy link
Copy Markdown

codecov Bot commented May 14, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 100.00%. Comparing base (8cb60e7) to head (713fb3d).
⚠️ Report is 23 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff            @@
##              main     #8318   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files            3         1    -2     
  Lines           63        17   -46     
=========================================
- Hits            63        17   -46     
Flag Coverage Δ
unittests 100.00% <100.00%> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Replaces the 5-row LA County placeholder with HUD's full FY2025 county
FMR table (4,765 counties × 5 bedroom counts = 23,825 rows), pulled
from HUD User's FY25_FMRs.xlsx.

Adds tools/convert_hud_fmr_xlsx.py: reads HUD's Excel via the
python-calamine engine (works around HUD's malformed metadata
timestamps that openpyxl rejects), maps HUD's column names to the
PE schema, de-duplicates on (state, county_fips, year, bedrooms),
and merges into the existing CSV so future years just append.

Existing hud_fair_market_rent tests pass unchanged — LA County FY2025
FMR values in the placeholder happened to match HUD's actual published
values exactly ($1,900 / $2,160 / $2,750 / $3,573 / $3,920 monthly for
0/1/2/3/4 bedroom).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@PavelMakarchuk PavelMakarchuk marked this pull request as ready for review May 14, 2026 22:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant