Skip to content

refactor(transport): one driver for paginate-through-the-executor - #371

Merged
thodson-usgs merged 1 commit into
DOI-USGS:mainfrom
thodson-usgs:refactor/run-paginated-driver
Aug 12, 2026
Merged

refactor(transport): one driver for paginate-through-the-executor#371
thodson-usgs merged 1 commit into
DOI-USGS:mainfrom
thodson-usgs:refactor/run-paginated-driver

Conversation

@thodson-usgs

@thodson-usgs thodson-usgs commented Aug 12, 2026

Copy link
Copy Markdown
Collaborator

What

Extracts run_paginated into transport/pagination.py: the one home for the "compose paginate strategies into a fetch, hand the plan to FanOut, resume" scaffold, and migrates its three copies — stats.get_data, wateruse._fan_out, and ratings._search — onto it.

Why

The scaffold existed three times (#369 added the third) and had already drifted: only Statistics honored a caller-injected client, only Water Use mapped raw transport errors to the typed taxonomy, and each spelled the first-request canonical-URL convention itself. An adapter should supply only its strategies — what a page is, where the cursor lives, how errors decode, how to shape the result — which is the division of labor wateruse._fan_out's own docstring already claimed. Now it is true in code for all three.

Notable call

Water Use's in-fetch TransportError → network_error wrap is deleted rather than ported. The executor's _normalize_failure already produces the identical typed NetworkError for deterministic transport failures, so the wrap was redundant with machinery that landed after it was written. test_permanent_transport_failure_remains_a_network_error pins this and passes unchanged against the driver (its monkeypatch retargeted to the page walk's home).

No layers-contract change: transport is a single layer, and the new pagination → fanout edge cannot cycle (fanout does not import pagination; the adapters composed the two, which is precisely what moved down).

Testing

  • Full offline suite: 787 passed (net −31 lines outside the new helper; no behavior change).
  • mypy --strict, ruff, xenon, complexipy, lint-imports all pass.

Rebased onto main after #369 merged; the diff is this PR's single commit.

🤖 Generated with Claude Code

https://claude.ai/code/session_01BTaSm7HmVb94RSJiKW4WAS

@thodson-usgs
thodson-usgs force-pushed the refactor/run-paginated-driver branch from 27f4243 to c5c0a63 Compare August 12, 2026 21:29
Three adapters carried the same ~20-line scaffold -- build a fetch that
hands each request to paginate, borrow the executor's shared client,
construct FanOut with RetryPolicy.from_env() and a first-request
canonical URL, resume -- and had already drifted: only Statistics
honored a caller-injected client, only Water Use mapped raw transport
errors, and each spelled the canonical-URL convention itself.

run_paginated (transport/pagination.py) is that scaffold's one home.
An adapter now supplies only its strategies -- what a page is, where
the cursor lives, how errors decode, and optionally how to shape the
result -- exactly the division of labor wateruse._fan_out's docstring
already claimed for itself; now it is true in code for all three:

- stats.get_data: one-item plan, caller-injected client honored via
  the driver's client= parameter.
- wateruse._fan_out: per-location plan; its TransportError ->
  network_error wrap is deleted rather than ported, because the
  executor's _normalize_failure already produces the identical typed
  NetworkError -- test_permanent_transport_failure_remains_a_network_error
  passes unchanged against the driver (patch retargeted to the page
  walk's home).
- ratings._search: one-item plan, verify= via client_options.

No layers-contract change: transport is one layer, and the new
pagination -> fanout edge cannot cycle (fanout does not import
pagination; adapters composed the two, which is exactly what moved
down here).

Full offline suite: 786 passed. mypy --strict, ruff, xenon,
complexipy, import-linter all pass.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BTaSm7HmVb94RSJiKW4WAS
@thodson-usgs
thodson-usgs force-pushed the refactor/run-paginated-driver branch from c5c0a63 to 5f58b1b Compare August 12, 2026 21:38
@thodson-usgs
thodson-usgs marked this pull request as ready for review August 12, 2026 21:40
@thodson-usgs
thodson-usgs merged commit 61428b5 into DOI-USGS:main Aug 12, 2026
11 checks passed
@thodson-usgs
thodson-usgs deleted the refactor/run-paginated-driver branch August 12, 2026 21:40
thodson-usgs added a commit to thodson-usgs/dataretrieval-python that referenced this pull request Aug 12, 2026
Absorbs DOI-USGS#368, DOI-USGS#369, and DOI-USGS#371. Eight files conflicted; three of the
resolutions were more than textual:

- ``wateruse.py``: main edited the implementation this branch had
  already renamed to ``nwdc.py``, so git conflicted the shim against
  it. Kept the shim and ported DOI-USGS#371's ``run_paginated`` migration into
  ``nwdc.py``, preserving ``adapter="nwdc"``.
- ``cql.py``: took main's version wholesale. This branch's two changes
  there (``redirected(OGC_API_URL)`` and ``adapter="waterdata"``) are
  subsumed by DOI-USGS#368 routing ``get_cql`` through
  ``waterdata.utils.get_ogc_data``, which already applies both.
- ``ratings.py``: took main's rewritten implementation and re-applied
  this branch's only contribution to it (``redirected(STAC_URL)``),
  plus adapter scoping on both drives.

Three breaks were semantic, not textual -- git merged them cleanly and
they would have failed at import or call time, because main added
callers of names this branch renamed or deleted:

- ``transport/pagination.run_paginated`` imported ``_CONCURRENCY_DEFAULT``
  (deleted here in favour of ``configuration.DEFAULT_CONCURRENCY``) and
  called ``RetryPolicy.from_env`` (renamed to ``from_configuration``).
  It now takes an ``adapter`` argument and threads it to both the retry
  policy and the executor, which is what makes per-adapter ``retries``
  and ``concurrency`` tables reach the three getters that use it.
- ``ogc/engine``'s ``cql_body`` branch (new in DOI-USGS#368) called
  ``from_env`` and dropped the adapter; both fixed.
- ``get_ogc_data`` gained ``cql_body`` from main and ``adapter`` here;
  both parameters kept.

969 passed, mypy --strict clean, all hooks including import-linter pass.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BTaSm7HmVb94RSJiKW4WAS
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