Skip to content

Latest commit

 

History

History
95 lines (82 loc) · 4.49 KB

AGENTS.md

File metadata and controls

95 lines (82 loc) · 4.49 KB

Agent guide

Guidance for AI assistants working in this repository.

Setup

pip install -e ".[dev]"
pytest tests/ -v

No network access is needed for tests; every HTTP call is mocked with unittest.mock.patch on requests.Session.get / requests.Session.post, and the retry sleep hook is replaced so the suite never waits.

Project structure

datalastic/
  __init__.py     public exports (Client, Envelope, models, exceptions, __version__)
  _version.py     the version string; the only place it is defined
  client.py       Client + _get/_post/_request/_handle + retry policy + base URLs + stat()
  vessels.py      VesselsResource (8 methods)
  ports.py        PortsResource (find, get)
  routes.py       RoutesResource (calculate)
  intel.py        IntelResource (8 maritime_reports endpoints)
  reports.py      ReportsResource (submit, get, list_all)
  models.py       dict-backed data classes, each with .raw, .meta and __repr__; ResultList
  exceptions.py   exception hierarchy
tests/test_client.py

Key conventions

  • Auth is the x-api-key header. Set once on _session in __init__. Never injected into query params or the POST body.
  • Three base URLs. BASE_V0 (default), BASE_EXT (sea routes, SAT-E), BASE_MR (all intel endpoints). Pass base= to _get().
  • Date params are renamed. Python from_date / to_date are sent as the from / to query keys. vessel_type in vessels.find() is sent as type to avoid shadowing the builtin.
  • None filtering. Always strip None values before building the request ({k: v for k, v in params.items() if v is not None}).
  • Validate before HTTP. Required-parameter checks raise ValueError before any request is made. Client settings (timeout, max_retries, backoff_factor, retry_after_max, retry_on_status) are validated in __init__; retry_on_status accepts only 408, 429 and 5xx.
  • Bulk uses repeated params. vessels.bulk() builds a list of (key, value) tuples so identifiers are sent as mmsi=x&mmsi=y.
  • Response envelope. _get() / _post() return an Envelope with .data and .meta (always a dict, empty when the response had none). Resource methods unwrap it: with_meta(Model(env.data), env.meta) for a single model, list_of(Model, env.data, env.meta) for a collection.
  • Every result carries .meta. Models inherit it from _Base, so every model __init__ must call super().__init__() first. Collections return ResultList, a list subclass with .meta and .next_token; it must stay list-compatible (equality with a plain list, indexing, slicing, len).
  • Pagination. .next_token reads meta["next"]; pass it back as next= to vessels.find() / vessels.in_radius().
  • Logical failure on 200. meta.success explicitly falsy raises APIError (status 200, message from meta.message). Missing meta or a missing success key is treated as success.
  • Retries live in Client._request(). Connection errors and timeouts are retried for GET only (POST creates reports, so it is not idempotent). Statuses in retry_on_status (default (429,)) are retried for both verbs. Retry-After is honored in delta-seconds and HTTP-date forms and capped at retry_after_max; otherwise the wait is backoff_factor * 2 ** attempt.
  • Version. Defined in _version.py only. __init__ re-exports it and client.py builds the User-Agent from it. pyproject.toml repeats the string and a test asserts the two match.
  • Models never raise on missing fields. They use .get() and keep the raw payload in .raw.

Exception hierarchy

DatalasticError
├── AuthenticationError       401
├── InsufficientCreditsError  402
├── NotFoundError             404
├── RateLimitError            429
└── APIError                  everything else; has .status_code

Timeouts, connection errors, non-JSON bodies, missing data keys, and a 200 with meta.success falsy all map to APIError.

Testing conventions

  • Build fake responses with the make_response() / ok() helpers in tests/test_client.py, and build clients with make_client(), which replaces client._sleep so retries never really wait.
  • Every resource method has a happy-path test plus validation-error tests.
  • Assert the called URL prefix to confirm the correct base URL is used.
  • Assert query params / JSON body to confirm renaming, and assert the x-api-key session header for auth.
  • Keep tests offline — never hit the live API.