You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat(spreads,indicators): typed sync+async Spreads and Indicators resources (#99) (#146)
* feat(spreads,indicators): typed sync+async resources for /v1/spreads and /v1/indicators (#99)
Adds client.spreads (15 methods) and client.indicators (10 methods) on both
clients, typed from production responses captured 2026-09-13. Request
building, argument validation and envelope parsing live once in
resources/_calculated_metrics.py so sync and async cannot drift.
A key the server always emits is required; a malformed 200 raises
OilPriceAPIError(code="MALFORMED_RESPONSE") with the raw body. Blank
selectors, invalid dates, start>end and >20 batch codes are refused before
any request. congressional-trades is not exposed (never returned data).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015ao5paex73xXvuM424Libo
* fix(spreads,indicators): raise ValidationError for local refusals, not ValueError (#99)
A builtin ValueError escaped the documented `except OilPriceAPIError`
catch-all (#123). Local refusals now go through one helper matching
_url._reject: ValidationError(message, field, value, status_code=None),
since no request was sent (#134). format_date's ValueError is re-raised as
ValidationError with the right field. All methods are new, so no dual-base
subclass is needed.
Tests assert the exact type, status_code None and field; proven red by
temporarily restoring ValueError (35 failed).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015ao5paex73xXvuM424Libo
---------
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
0 commit comments