Skip to content

Commit e026e64

Browse files
committed
feat: add economics support
- Add Economics model for ACS economics data - Add economics to GeocodioFields - Add unit and integration tests for economics
1 parent 4efdefd commit e026e64

File tree

4 files changed

+80
-4
lines changed

4 files changed

+80
-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
17+
Demographics, Economics
1818
)
1919
from .exceptions import InvalidRequestError, AuthenticationError, GeocodioServerError
2020

@@ -229,6 +229,11 @@ def _parse_fields(self, fields_data: dict | None) -> GeocodioFields | None:
229229
if "acs-demographics" in fields_data else None
230230
)
231231

232+
economics = (
233+
Economics.from_api(fields_data["acs-economics"])
234+
if "acs-economics" in fields_data else None
235+
)
236+
232237
return GeocodioFields(
233238
timezone=timezone,
234239
congressional_districts=congressional_districts,
@@ -240,4 +245,5 @@ def _parse_fields(self, fields_data: dict | None) -> GeocodioFields | None:
240245
census2023=census2023,
241246
acs=acs,
242247
demographics=demographics,
248+
economics=economics,
243249
)

src/geocodio/models.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,19 @@ class Demographics(_HasExtras, ApiModelMixin):
151151
extras: Dict[str, Any] = field(default_factory=dict, repr=False)
152152

153153

154+
@dataclass(slots=True, frozen=True)
155+
class Economics(_HasExtras, ApiModelMixin):
156+
"""
157+
American Community Survey economics data.
158+
"""
159+
median_household_income: Optional[int] = None
160+
mean_household_income: Optional[int] = None
161+
per_capita_income: Optional[int] = None
162+
poverty_rate: Optional[float] = None
163+
unemployment_rate: Optional[float] = None
164+
extras: Dict[str, Any] = field(default_factory=dict, repr=False)
165+
166+
154167
@dataclass(slots=True, frozen=True)
155168
class GeocodioFields:
156169
"""
@@ -167,6 +180,7 @@ class GeocodioFields:
167180
census2023: Optional[CensusData] = None
168181
acs: Optional[ACSSurveyData] = None
169182
demographics: Optional[Demographics] = None
183+
economics: Optional[Economics] = None
170184

171185

172186
# ──────────────────────────────────────────────────────────────────────────────

tests/e2e/test_api.py

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -325,4 +325,38 @@ def test_integration_with_demographics(client):
325325
if fields.demographics.asian_population is not None:
326326
assert isinstance(fields.demographics.asian_population, int)
327327
if fields.demographics.hispanic_population is not None:
328-
assert isinstance(fields.demographics.hispanic_population, int)
328+
assert isinstance(fields.demographics.hispanic_population, int)
329+
330+
331+
def test_integration_with_economics(client):
332+
"""Test real API call with economics field."""
333+
# Test address
334+
address = "1600 Pennsylvania Ave NW, Washington, DC"
335+
336+
# Request additional fields
337+
response = client.geocode(
338+
address,
339+
fields=["acs-economics"]
340+
)
341+
342+
# Verify response structure
343+
assert response is not None
344+
assert len(response.results) > 0
345+
result = response.results[0]
346+
347+
# Verify fields data
348+
fields = result.fields
349+
assert fields is not None
350+
351+
# Check economics data
352+
if fields.economics:
353+
if fields.economics.median_household_income is not None:
354+
assert isinstance(fields.economics.median_household_income, int)
355+
if fields.economics.mean_household_income is not None:
356+
assert isinstance(fields.economics.mean_household_income, int)
357+
if fields.economics.per_capita_income is not None:
358+
assert isinstance(fields.economics.per_capita_income, int)
359+
if fields.economics.poverty_rate is not None:
360+
assert isinstance(fields.economics.poverty_rate, float)
361+
if fields.economics.unemployment_rate is not None:
362+
assert isinstance(fields.economics.unemployment_rate, float)

tests/test_models.py

Lines changed: 24 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
4+
GeocodioFields, GeocodingResult, GeocodingResponse, Location, StateLegislativeDistrict, SchoolDistrict, CensusData, Demographics, Economics
55
)
66

77

@@ -184,4 +184,26 @@ def test_demographics_extras():
184184
assert demographics.asian_population == 100
185185
assert demographics.hispanic_population == 100
186186
assert demographics.get_extra("extra_field") == "extra value"
187-
assert demographics.get_extra("nonexistent", "default") == "default"
187+
assert demographics.get_extra("nonexistent", "default") == "default"
188+
189+
190+
def test_economics_extras():
191+
# Test that extra fields are stored in extras
192+
data = {
193+
"median_household_income": 75000,
194+
"mean_household_income": 85000,
195+
"per_capita_income": 35000,
196+
"poverty_rate": 10.5,
197+
"unemployment_rate": 5.2,
198+
"extra_field": "extra value"
199+
}
200+
201+
economics = Economics.from_api(data)
202+
203+
assert economics.median_household_income == 75000
204+
assert economics.mean_household_income == 85000
205+
assert economics.per_capita_income == 35000
206+
assert economics.poverty_rate == 10.5
207+
assert economics.unemployment_rate == 5.2
208+
assert economics.get_extra("extra_field") == "extra value"
209+
assert economics.get_extra("nonexistent", "default") == "default"

0 commit comments

Comments
 (0)