Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
name: CI

on:
push:
branches: [main, chore/ci-setup]
workflow_dispatch:

jobs:
test-and-lint:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4

- name: Install uv
uses: astral-sh/setup-uv@v5

- name: "Set up Python"
uses: actions/setup-python@v5
with:
python-version: "3.11"
# python-version-file: "pyproject.toml"

- name: Install dependencies
run: |
uv sync
uv pip install .
uv pip install .[dev]
- name: Run tests
run: |
uv run pytest
- name: Lint with flake8
run: |
uv run flake8 src/ --ignore=E501
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,9 @@ Development Installation

3. Install development dependencies:
```bash
pip install -e ".[dev]"
pip install -r pyproject.toml -r requirements-dev.txt
pip install .
pip install .[dev]
pip install -r requirements-dev.txt
```

Usage
Expand Down
9 changes: 4 additions & 5 deletions src/geocodio/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
# Set up logger early to capture all logs
logger = logging.getLogger("geocodio")

# flake8: noqa: F401
from geocodio.models import (
GeocodingResponse, GeocodingResult, AddressComponents,
Location, GeocodioFields, Timezone, CongressionalDistrict,
Expand All @@ -28,7 +29,9 @@ class GeocodioClient:
BASE_PATH = "/v1.8" # keep in sync with Geocodio's current version

@staticmethod
def get_status_exception_mappings() -> Dict[int, type[BadRequestError | InvalidRequestError | AuthenticationError | GeocodioServerError]]:
def get_status_exception_mappings() -> Dict[
int, type[BadRequestError | InvalidRequestError | AuthenticationError | GeocodioServerError]
]:
"""
Returns a list of status code to exception mappings.
This is used to map HTTP status codes to specific exceptions.
Expand All @@ -40,7 +43,6 @@ def get_status_exception_mappings() -> Dict[int, type[BadRequestError | InvalidR
500: GeocodioServerError,
}


def __init__(self, api_key: Optional[str] = None, hostname: str = "api.geocod.io"):
self.api_key: str = api_key or os.getenv("GEOCODIO_API_KEY", "")
if not self.api_key:
Expand Down Expand Up @@ -286,7 +288,6 @@ def create_list(
logger.debug(f"Response content: {response.text}")
return self._parse_list_response(response.json(), response=response)


def get_lists(self) -> PaginatedResponse:
"""
Retrieve all lists.
Expand Down Expand Up @@ -347,7 +348,6 @@ def delete_list(self, list_id: str) -> None:

self._request("DELETE", endpoint, params)


@staticmethod
def _parse_list_response(response_json: dict, response: httpx.Response = None) -> ListResponse:
"""
Expand All @@ -369,7 +369,6 @@ def _parse_list_response(response_json: dict, response: httpx.Response = None) -
http_response=response,
)


def _parse_fields(self, fields_data: dict | None) -> GeocodioFields | None:
if not fields_data:
return None
Expand Down
5 changes: 3 additions & 2 deletions src/geocodio/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@
"""

from __future__ import annotations

from dataclasses import dataclass
from typing import Optional, List
from typing import Optional, List, Union


# ──────────────────────────────────────────────────────────────────────────────
Expand All @@ -18,7 +19,7 @@ class GeocodioErrorDetail:
A typed record returned by Geocodio on errors.
"""
message: str
code: Optional[int] = None # e.g. HTTP status or internal
code: Optional[int] = None # e.g. HTTP status or internal
errors: Optional[List[str]] = None # field‑specific validation messages


Expand Down
30 changes: 15 additions & 15 deletions src/geocodio/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from __future__ import annotations

from dataclasses import dataclass, field
from typing import Any, List, Optional, Dict, TypeVar, Type, ClassVar, Union
from typing import Any, List, Optional, Dict, TypeVar, Type

import httpx

Expand Down Expand Up @@ -51,19 +51,19 @@ class Location:
@dataclass(frozen=True)
class AddressComponents(_HasExtras, ApiModelMixin):
# core / always-present
number: Optional[str] = None
predirectional: Optional[str] = None # e.g. "N"
street: Optional[str] = None
suffix: Optional[str] = None # e.g. "St"
postdirectional: Optional[str] = None
formatted_street: Optional[str] = None # full street line

city: Optional[str] = None
county: Optional[str] = None
state: Optional[str] = None
zip: Optional[str] = None # Geocodio returns "zip"
postal_code: Optional[str] = None # alias for completeness
country: Optional[str] = None
number: Optional[str] = None
predirectional: Optional[str] = None # e.g. "N"
street: Optional[str] = None
suffix: Optional[str] = None # e.g. "St"
postdirectional: Optional[str] = None
formatted_street: Optional[str] = None # full street line

city: Optional[str] = None
county: Optional[str] = None
state: Optional[str] = None
zip: Optional[str] = None # Geocodio returns "zip"
postal_code: Optional[str] = None # alias for completeness
country: Optional[str] = None

# catch‑all for anything Geocodio adds later
extras: Dict[str, Any] = field(default_factory=dict, repr=False)
Expand All @@ -73,7 +73,7 @@ class AddressComponents(_HasExtras, ApiModelMixin):
class Timezone(_HasExtras, ApiModelMixin):
name: str
utc_offset: int
observes_dst: Optional[bool] = None # new key documented by Geocodio
observes_dst: Optional[bool] = None # new key documented by Geocodio
extras: Dict[str, Any] = field(default_factory=dict, repr=False)


Expand Down
Loading