fix: ZIP rep lookup — handle GEOID20 for 119th Congress TIGERweb layers

The 119th Congressional Districts layer uses 2020 Census vintage field
names (GEOID20, STATEFP20, CD119FP) instead of GEOID. The GEOID check
was silently falling through; added GEOID20 fallback, isdigit() guard,
try/except on CD field parsing, and debug logging of unparseable layers.

Authored by: Jack Levy
This commit is contained in:
Jack Levy
2026-03-15 10:29:09 -04:00
parent 3d19cd571a
commit 4cada298ab

View File

@@ -93,9 +93,11 @@ async def get_members_by_zip(zip_code: str, db: AsyncSession = Depends(get_db)):
if "Congressional" not in (item.get("layerName") or ""):
continue
attrs = item.get("attributes", {})
# GEOID = 2-char state FIPS + 2-char district (e.g. "1218" = FL-18)
geoid = str(attrs.get("GEOID") or "").strip()
if len(geoid) == 4:
# GEOID / GEOID20 — 2-char state FIPS + 2-char district (e.g. "0618" = CA-18)
# 119th Congress layers use GEOID20 (2020 Census vintage)
geoid = str(attrs.get("GEOID") or attrs.get("GEOID20") or "").strip()
if len(geoid) == 4 and geoid.isdigit():
state_fips = geoid[:2]
district_fips = geoid[2:]
state_code = _FIPS_TO_STATE.get(state_fips)
@@ -103,16 +105,24 @@ async def get_members_by_zip(zip_code: str, db: AsyncSession = Depends(get_db)):
if state_code:
break
# Fallback: explicit field names
# Fallback: explicit field names (e.g. CD119FP + STATEFP20)
cd_field = next((k for k in attrs if re.match(r"CD\d+FP$", k)), None)
state_field = next((k for k in attrs if "STATEFP" in k.upper()), None)
if cd_field and state_field:
try:
state_fips = str(attrs[state_field]).zfill(2)
district_fips = str(attrs[cd_field])
district_fips = str(attrs[cd_field]).zfill(2)
state_code = _FIPS_TO_STATE.get(state_fips)
district_num = str(int(district_fips)) if district_fips.strip("0") else None
if state_code:
break
except (ValueError, TypeError):
pass
logger.debug(
"ZIP %s: could not parse layer %r — attrs: %s",
zip_code, item.get("layerName"), list(attrs.keys()),
)
if not state_code:
logger.warning(