Skip to content

Commit 8b74f92

Browse files
Merge pull request #13 from Geocodio/fix/census-field-appends-issue-12
Fix: Census field appends not included in response
2 parents e33e911 + 0eb5dcc commit 8b74f92

File tree

3 files changed

+112
-19
lines changed

3 files changed

+112
-19
lines changed

src/geocodio/client.py

Lines changed: 12 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -443,20 +443,17 @@ def _parse_fields(self, fields_data: dict | None) -> GeocodioFields | None:
443443
for district in fields_data["school"]
444444
]
445445

446-
census2010 = (
447-
CensusData.from_api(fields_data["census2010"])
448-
if "census2010" in fields_data else None
449-
)
450-
451-
census2020 = (
452-
CensusData.from_api(fields_data["census2020"])
453-
if "census2020" in fields_data else None
454-
)
455-
456-
census2023 = (
457-
CensusData.from_api(fields_data["census2023"])
458-
if "census2023" in fields_data else None
459-
)
446+
# Dynamically parse all census fields (e.g., census2010, census2020, census2024, etc.)
447+
# This supports any census year returned by the API
448+
from dataclasses import fields as dataclass_fields
449+
valid_field_names = {f.name for f in dataclass_fields(GeocodioFields)}
450+
451+
census_fields = {}
452+
for key in fields_data:
453+
if key.startswith("census") and key[6:].isdigit(): # e.g., "census2024"
454+
# Only include if it's a defined field in GeocodioFields
455+
if key in valid_field_names:
456+
census_fields[key] = CensusData.from_api(fields_data[key])
460457

461458
acs = (
462459
ACSSurveyData.from_api(fields_data["acs"])
@@ -515,9 +512,6 @@ def _parse_fields(self, fields_data: dict | None) -> GeocodioFields | None:
515512
state_legislative_districts=state_legislative_districts,
516513
state_legislative_districts_next=state_legislative_districts_next,
517514
school_districts=school_districts,
518-
census2010=census2010,
519-
census2020=census2020,
520-
census2023=census2023,
521515
acs=acs,
522516
demographics=demographics,
523517
economics=economics,
@@ -528,6 +522,7 @@ def _parse_fields(self, fields_data: dict | None) -> GeocodioFields | None:
528522
provriding=provriding,
529523
provriding_next=provriding_next,
530524
statcan=statcan,
525+
**census_fields, # Dynamically include all census year fields
531526
)
532527

533528
# @TODO add a "keep_trying" parameter to download() to keep trying until the list is processed.

src/geocodio/models.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -283,7 +283,7 @@ class FFIECData(ApiModelMixin):
283283
extras: Dict[str, Any] = field(default_factory=dict, repr=False)
284284

285285

286-
@dataclass(slots=True, frozen=True)
286+
@dataclass(frozen=True)
287287
class GeocodioFields:
288288
"""
289289
Container for optional 'fields' returned by the Geocodio API.

tests/unit/test_geocode.py

Lines changed: 99 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -498,4 +498,102 @@ def batch_response_callback(request):
498498
assert resp.results[1].formatted_address == "638 E 13th Ave, Denver, CO 80203"
499499
assert resp.results[1].fields.timezone.name == "America/Denver"
500500
assert resp.results[1].fields.timezone.utc_offset == -7
501-
assert resp.results[1].fields.congressional_districts[0].district_number == 1
501+
assert resp.results[1].fields.congressional_districts[0].district_number == 1
502+
503+
504+
def test_geocode_with_census_fields(client, httpx_mock):
505+
"""Test geocoding with census field appends including all census years."""
506+
# Arrange: stub the API call with multiple census years
507+
def response_callback(request):
508+
assert request.method == "GET"
509+
assert request.url.params["fields"] == "census2010,census2020,census2023,census2024"
510+
return httpx.Response(200, json={
511+
"results": [{
512+
"address_components": {
513+
"number": "1640",
514+
"street": "Main",
515+
"suffix": "St",
516+
"city": "Sheldon",
517+
"state": "VT",
518+
"zip": "05483",
519+
"country": "US"
520+
},
521+
"formatted_address": "1640 Main St, Sheldon, VT 05483",
522+
"location": {"lat": 44.895469, "lng": -72.953264},
523+
"accuracy": 1,
524+
"accuracy_type": "rooftop",
525+
"source": "Vermont",
526+
"fields": {
527+
"census2010": {
528+
"tract": "960100",
529+
"block": "2001",
530+
"blockgroup": "2",
531+
"county_fips": "50011",
532+
"state_fips": "50"
533+
},
534+
"census2020": {
535+
"tract": "960100",
536+
"block": "2002",
537+
"blockgroup": "2",
538+
"county_fips": "50011",
539+
"state_fips": "50"
540+
},
541+
"census2023": {
542+
"tract": "960100",
543+
"block": "2003",
544+
"blockgroup": "2",
545+
"county_fips": "50011",
546+
"state_fips": "50"
547+
},
548+
"census2024": {
549+
"tract": "960100",
550+
"block": "2004",
551+
"blockgroup": "2",
552+
"county_fips": "50011",
553+
"state_fips": "50"
554+
}
555+
}
556+
}]
557+
})
558+
559+
httpx_mock.add_callback(
560+
callback=response_callback,
561+
url=httpx.URL("https://api.test/v1.9/geocode", params={
562+
"street": "1640 Main St",
563+
"city": "Sheldon",
564+
"state": "VT",
565+
"postal_code": "05483",
566+
"fields": "census2010,census2020,census2023,census2024"
567+
}),
568+
match_headers={"Authorization": "Bearer TEST_KEY"},
569+
)
570+
571+
# Act
572+
resp = client.geocode(
573+
{"city": "Sheldon", "state": "VT", "street": "1640 Main St", "postal_code": "05483"},
574+
fields=["census2010", "census2020", "census2023", "census2024"],
575+
)
576+
577+
# Assert
578+
assert len(resp.results) == 1
579+
result = resp.results[0]
580+
assert result.formatted_address == "1640 Main St, Sheldon, VT 05483"
581+
582+
# Check that all census fields are present and parsed correctly
583+
assert result.fields.census2010 is not None
584+
assert result.fields.census2010.tract == "960100"
585+
assert result.fields.census2010.block == "2001"
586+
assert result.fields.census2010.county_fips == "50011"
587+
588+
assert result.fields.census2020 is not None
589+
assert result.fields.census2020.tract == "960100"
590+
assert result.fields.census2020.block == "2002"
591+
592+
assert result.fields.census2023 is not None
593+
assert result.fields.census2023.tract == "960100"
594+
assert result.fields.census2023.block == "2003"
595+
596+
# This will fail until we fix the parsing logic
597+
assert result.fields.census2024 is not None
598+
assert result.fields.census2024.tract == "960100"
599+
assert result.fields.census2024.block == "2004"

0 commit comments

Comments
 (0)