Guidance for AI assistants working in this repository.
pip install -e ".[dev]"
pytest tests/ -vNo 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.
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
- Auth is the
x-api-keyheader. Set once on_sessionin__init__. Never injected into query params or the POST body. - Three base URLs.
BASE_V0(default),BASE_EXT(sea routes, SAT-E),BASE_MR(allintelendpoints). Passbase=to_get(). - Date params are renamed. Python
from_date/to_dateare sent as thefrom/toquery keys.vessel_typeinvessels.find()is sent astypeto avoid shadowing the builtin. - None filtering. Always strip
Nonevalues before building the request ({k: v for k, v in params.items() if v is not None}). - Validate before HTTP. Required-parameter checks raise
ValueErrorbefore any request is made. Client settings (timeout,max_retries,backoff_factor,retry_after_max,retry_on_status) are validated in__init__;retry_on_statusaccepts only 408, 429 and 5xx. - Bulk uses repeated params.
vessels.bulk()builds a list of(key, value)tuples so identifiers are sent asmmsi=x&mmsi=y. - Response envelope.
_get()/_post()return anEnvelopewith.dataand.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 callsuper().__init__()first. Collections returnResultList, alistsubclass with.metaand.next_token; it must stay list-compatible (equality with a plain list, indexing, slicing,len). - Pagination.
.next_tokenreadsmeta["next"]; pass it back asnext=tovessels.find()/vessels.in_radius(). - Logical failure on 200.
meta.successexplicitly falsy raisesAPIError(status 200, message frommeta.message). Missingmetaor a missingsuccesskey 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 inretry_on_status(default(429,)) are retried for both verbs.Retry-Afteris honored in delta-seconds and HTTP-date forms and capped atretry_after_max; otherwise the wait isbackoff_factor * 2 ** attempt. - Version. Defined in
_version.pyonly.__init__re-exports it andclient.pybuilds theUser-Agentfrom it.pyproject.tomlrepeats 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.
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.
- Build fake responses with the
make_response()/ok()helpers intests/test_client.py, and build clients withmake_client(), which replacesclient._sleepso 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-keysession header for auth. - Keep tests offline — never hit the live API.