Skip to content

#154 collapse duplicated sync/async response-shaping + align retry policy - #164

Merged
martinkersner merged 1 commit into
mainfrom
worktree-agent-a2a7702d8b365922e
Jul 4, 2026
Merged

#154 collapse duplicated sync/async response-shaping + align retry policy#164
martinkersner merged 1 commit into
mainfrom
worktree-agent-a2a7702d8b365922e

Conversation

@martinkersner

Copy link
Copy Markdown
Member

Closes #154

Summary

Collapse duplicated sync/async response-shaping and align the async retry policy with the sync (urllib3) one. Pure refactor — behavior identical, verified by an independent review pass.

Shared response-shaping (datamaxi/resources/utils.py, leaf module — no import-cycle):

  • assemble_params, raise_if_no_data, to_indexed_dataframe extracted.
  • premium.py: build_premium_params (all 20 params) + shape_premium_response extracted; aio/premium.py now imports them directly (no async copy) — identity-tested.
  • candle/ticker/wallet_status (sync+async) swap hand-copied pd.DataFrame(...).set_index(...) / empty-data blocks for the shared helpers.
  • api.py: sync side now reuses _dispatch.extract_limit_usage (was duplicated).

Retry alignment (datamaxi/_retry.py, new):

  • Pure functions reproducing urllib3 Retry semantics: GET-only, backoff 0 then backoff_factor * 2**(n-1) capped at 120s, Retry-After (seconds or HTTP-date) priority.
  • aio/_core.py rewired onto it, replacing the old linear-backoff/all-methods/no-Retry-After loop (a real behavior fix). Sync side's urllib3 Retry left untouched; _retry.py is the shared, testable description of that policy.

Tests

  • 199 passed, 118 skipped (baseline 176 passed; +23 new tests for _retry.py, shaping helpers, and sync/async premium identity). black + flake8 clean. import datamaxi / import datamaxi.aio both OK.

Reviewer nits (non-blocking, left as-is)

  • _retry.py parse_retry_after: silently returns None on malformed Retry-After and has no upper cap (urllib3 raises / caps at 21600s) — arguably safer, no real-traffic impact.
  • Stale comment at test_endpoint_param_coverage.py:176; defensive dead branch in parse_retry_after.

Scope note

cex_wallet_status.py folded into the shared helper too (issue named only candle/ticker) — same duplication pattern.

Extract transport-agnostic response-shaping into datamaxi.resources.utils
(assemble_params/raise_if_no_data/to_indexed_dataframe) and premium-specific
build_premium_params/shape_premium_response in resources/premium.py, imported
directly by aio/premium.py and aio/cex.py. Only await/transport glue is left
per-client now; sync/async can't drift on shaping.

Add datamaxi/_retry.py: pure GET-only/exponential-backoff/Retry-After policy
(mirrors urllib3 Retry semantics). Rewire aio/_core.py's hand-rolled loop
(previously linear backoff, all methods, ignored Retry-After) onto it. Sync
keeps its urllib3 Retry unchanged (well-tested, no need to touch); _retry.py
is the shared description so the two can't diverge again.

Also collapse api.py's duplicate _extract_limit_usage onto the one already
shared via _dispatch.extract_limit_usage (used by aio already).

No public API/behavior change. Extended
test_endpoint_param_coverage.py's AST extractor to recognize the new
params = build_x_params(x=x, ...) call-site shape alongside the existing
params["x"] = ... pattern it already looked for.
@martinkersner
martinkersner marked this pull request as ready for review July 4, 2026 12:26
@martinkersner
martinkersner merged commit 214913e into main Jul 4, 2026
5 checks passed
@martinkersner
martinkersner deleted the worktree-agent-a2a7702d8b365922e branch July 4, 2026 12:26
@martinkersner martinkersner self-assigned this Jul 5, 2026
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.

Collapse duplicated sync/async response-shaping (and align retry policy)

1 participant