Skip to content

Commit 25816de

Browse files
committed
feat: add families support
- Add Families model for ACS families data - Add families to GeocodioFields - Add unit and integration tests for families
1 parent e026e64 commit 25816de

File tree

4 files changed

+90
-4
lines changed

4 files changed

+90
-4
lines changed

src/geocodio/client.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
GeocodingResponse, GeocodingResult, AddressComponents,
1515
Location, GeocodioFields, Timezone, CongressionalDistrict,
1616
CensusData, ACSSurveyData, StateLegislativeDistrict, SchoolDistrict,
17-
Demographics, Economics
17+
Demographics, Economics, Families
1818
)
1919
from .exceptions import InvalidRequestError, AuthenticationError, GeocodioServerError
2020

@@ -234,6 +234,11 @@ def _parse_fields(self, fields_data: dict | None) -> GeocodioFields | None:
234234
if "acs-economics" in fields_data else None
235235
)
236236

237+
families = (
238+
Families.from_api(fields_data["acs-families"])
239+
if "acs-families" in fields_data else None
240+
)
241+
237242
return GeocodioFields(
238243
timezone=timezone,
239244
congressional_districts=congressional_districts,
@@ -246,4 +251,5 @@ def _parse_fields(self, fields_data: dict | None) -> GeocodioFields | None:
246251
acs=acs,
247252
demographics=demographics,
248253
economics=economics,
254+
families=families,
249255
)

src/geocodio/models.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,21 @@ class Economics(_HasExtras, ApiModelMixin):
164164
extras: Dict[str, Any] = field(default_factory=dict, repr=False)
165165

166166

167+
@dataclass(slots=True, frozen=True)
168+
class Families(_HasExtras, ApiModelMixin):
169+
"""
170+
American Community Survey families data.
171+
"""
172+
total_households: Optional[int] = None
173+
family_households: Optional[int] = None
174+
nonfamily_households: Optional[int] = None
175+
married_couple_households: Optional[int] = None
176+
single_male_households: Optional[int] = None
177+
single_female_households: Optional[int] = None
178+
average_household_size: Optional[float] = None
179+
extras: Dict[str, Any] = field(default_factory=dict, repr=False)
180+
181+
167182
@dataclass(slots=True, frozen=True)
168183
class GeocodioFields:
169184
"""
@@ -181,6 +196,7 @@ class GeocodioFields:
181196
acs: Optional[ACSSurveyData] = None
182197
demographics: Optional[Demographics] = None
183198
economics: Optional[Economics] = None
199+
families: Optional[Families] = None
184200

185201

186202
# ──────────────────────────────────────────────────────────────────────────────

tests/e2e/test_api.py

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -359,4 +359,42 @@ def test_integration_with_economics(client):
359359
if fields.economics.poverty_rate is not None:
360360
assert isinstance(fields.economics.poverty_rate, float)
361361
if fields.economics.unemployment_rate is not None:
362-
assert isinstance(fields.economics.unemployment_rate, float)
362+
assert isinstance(fields.economics.unemployment_rate, float)
363+
364+
365+
def test_integration_with_families(client):
366+
"""Test real API call with families field."""
367+
# Test address
368+
address = "1600 Pennsylvania Ave NW, Washington, DC"
369+
370+
# Request additional fields
371+
response = client.geocode(
372+
address,
373+
fields=["acs-families"]
374+
)
375+
376+
# Verify response structure
377+
assert response is not None
378+
assert len(response.results) > 0
379+
result = response.results[0]
380+
381+
# Verify fields data
382+
fields = result.fields
383+
assert fields is not None
384+
385+
# Check families data
386+
if fields.families:
387+
if fields.families.total_households is not None:
388+
assert isinstance(fields.families.total_households, int)
389+
if fields.families.family_households is not None:
390+
assert isinstance(fields.families.family_households, int)
391+
if fields.families.nonfamily_households is not None:
392+
assert isinstance(fields.families.nonfamily_households, int)
393+
if fields.families.married_couple_households is not None:
394+
assert isinstance(fields.families.married_couple_households, int)
395+
if fields.families.single_male_households is not None:
396+
assert isinstance(fields.families.single_male_households, int)
397+
if fields.families.single_female_households is not None:
398+
assert isinstance(fields.families.single_female_households, int)
399+
if fields.families.average_household_size is not None:
400+
assert isinstance(fields.families.average_household_size, float)

tests/test_models.py

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import pytest
22
from geocodio.models import (
33
AddressComponents, Timezone, CongressionalDistrict,
4-
GeocodioFields, GeocodingResult, GeocodingResponse, Location, StateLegislativeDistrict, SchoolDistrict, CensusData, Demographics, Economics
4+
GeocodioFields, GeocodingResult, GeocodingResponse, Location, StateLegislativeDistrict, SchoolDistrict, CensusData, Demographics, Economics, Families
55
)
66

77

@@ -206,4 +206,30 @@ def test_economics_extras():
206206
assert economics.poverty_rate == 10.5
207207
assert economics.unemployment_rate == 5.2
208208
assert economics.get_extra("extra_field") == "extra value"
209-
assert economics.get_extra("nonexistent", "default") == "default"
209+
assert economics.get_extra("nonexistent", "default") == "default"
210+
211+
212+
def test_families_extras():
213+
# Test that extra fields are stored in extras
214+
data = {
215+
"total_households": 1000,
216+
"family_households": 600,
217+
"nonfamily_households": 400,
218+
"married_couple_households": 400,
219+
"single_male_households": 100,
220+
"single_female_households": 100,
221+
"average_household_size": 2.5,
222+
"extra_field": "extra value"
223+
}
224+
225+
families = Families.from_api(data)
226+
227+
assert families.total_households == 1000
228+
assert families.family_households == 600
229+
assert families.nonfamily_households == 400
230+
assert families.married_couple_households == 400
231+
assert families.single_male_households == 100
232+
assert families.single_female_households == 100
233+
assert families.average_household_size == 2.5
234+
assert families.get_extra("extra_field") == "extra value"
235+
assert families.get_extra("nonexistent", "default") == "default"

0 commit comments

Comments
 (0)