Skip to content

Expose census appends, match_type, raw payloads and rate limits - #34

Merged
MiniCodeMonkey merged 1 commit into
mainfrom
feat/api-surface-gaps
Aug 28, 2026
Merged

Expose census appends, match_type, raw payloads and rate limits#34
MiniCodeMonkey merged 1 commit into
mainfrom
feat/api-surface-gaps

Conversation

@MiniCodeMonkey

Copy link
Copy Markdown
Member

Closes four gaps in the client's public surface. These surfaced while reviewing a contractor-built Dagster skill that had to fall back to the third-party pygeocodio package: every one of these was a reason it could not use the official client cleanly.

Ready for review. No version bump is included, so a release is a separate call once this is approved.

Changes

Census appends had no public accessor. Requesting fields=["census2023"] stored the data only on the private fields._census dict, so consumers had to write result.fields._census["census2023"]["full_fips"] to reach the single most useful append field. Adds fields.census, fields.get_census(year), fields.census_years and fields.census_data, matching how the other appends are already exposed. get_census() accepts 2023, "2023" or "census2023". The private dict and the dynamic fields.census2023 attributes are untouched.

# before
fips = result.fields._census["census2023"]["full_fips"]
# after
fips = result.fields.census.full_fips

match_type and address_lines were silently dropped. Both are returned on every v2 result but were absent from GeocodingResult, so the data was lost on parse. Both are now populated for single and batch responses. A full diff of the raw v2 JSON keys against the dataclass confirms these were the only two missing.

No way to recover the raw payload. There was no raw, to_dict(), or equivalent, and dataclasses.asdict() is lossy and leaks the private _census key. Adds raw and to_dict() to both GeocodingResponse and GeocodingResult, so pipelines can cache the untouched response and add derived columns later without re-fetching and re-paying for the lookup.

Rate limit headers were not exposed. The X-RateLimit-* headers were logged at debug level only. Adds a RateLimit model exposed as GeocodingResponse.rate_limit and Geocodio.rate_limit, parsed case-insensitively and populated before error handling so it is available on 4xx and 5xx too. Worth noting the API sends x-ratelimit-period rather than x-ratelimit-reset; both are modelled and the raw header dict is kept on RateLimit.headers.

Compatibility

Backward compatible. New dataclass fields are appended, so positional construction still works, and existing attribute access is unchanged.

Verification

  • pytest tests/unit/ -- 115 passed (9 new)
  • pytest tests/e2e/ -- 45 passed against the live API (4 new)
  • flake8 src/ --ignore=E501 -- clean; black --check and isort --check-only clean
  • mypy -- 19 errors, identical to the baseline on main, none on new lines

All four changes were also verified by hand against api.geocod.io/v2.

Reviewer notes

  • fields.census returns the most recent vintage when several are present in the response. Multi-vintage callers should use get_census(year). Worth a sanity-check that this is the behaviour you want.
  • raw is a real dataclass field, so dataclasses.asdict() output now includes it and roughly duplicates the payload. It is repr=False, so reprs are unaffected.
  • Unmatched batch entries get raw={} rather than the {query, response} wrapper, keeping result.raw consistently "the API result object". The wrapper stays reachable via response.raw.

…imits

Four gaps in the public surface, found while a consumer had to fall back
to a third-party client:

- Census appends were only reachable through the private `fields._census`
  dict. Adds `fields.census`, `fields.get_census(year)`,
  `fields.census_years` and `fields.census_data`, consistent with how the
  other appends are exposed. The private dict and the dynamic
  `fields.census2023` attributes keep working.
- `match_type` and `address_lines` are returned on every v2 result but
  were silently dropped by `GeocodingResult`. Both are now parsed, for
  single and batch responses alike.
- Adds `raw` / `to_dict()` on `GeocodingResponse` and `GeocodingResult`,
  so pipelines can cache the untouched payload instead of a lossy
  projection.
- Parses the `X-RateLimit-*` headers into a `RateLimit` model, exposed as
  `GeocodingResponse.rate_limit` and `Geocodio.rate_limit`.

No version bump -- release is a separate call.
@MiniCodeMonkey
MiniCodeMonkey merged commit 95799c1 into main Aug 28, 2026
1 check passed
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