Repository navigation
polish(models): AwareDatetime in WS payloads, V1 Literals, UnixSecondsTimestamp alias, Decimal NaN reject - #292
Conversation
…nt market_lifecycle seconds unit WS payload models predated #234's REST AwareDatetime rollout, so they accepted naive RFC3339 strings that REST callers couldn't. Align the two by retyping the datetime fields on UserOrdersPayload (4 fields) and the communications payloads (5 fields) to pydantic.AwareDatetime — a string without an offset now raises ValidationError at parse rather than silently producing a tz-unaware datetime that breaks arithmetic against tz-aware peers in MarketPosition/Settlement. MarketLifecyclePayload's *_ts fields are intentionally left as bare int. The AsyncAPI spec example payload uses Unix **seconds** (e.g. open_ts: 1694635200, 2023-09-13), not ms — so the lack of the _ts_ms suffix carried by sibling channels is correct. Added a comment so readers stop wondering.
…le response fields; UnixSecondsTimestamp alias
- V1 CreateOrderRequest tightens side/action/time_in_force/self_trade_prevention_type
from bare str to the same Literal aliases V2 uses (SideLiteral, ActionLiteral,
TimeInForceLiteral, SelfTradePreventionTypeLiteral). V1 keeps its yes/no side
vocabulary (V2 is bid/ask). Caller passing side='foo' now fails at construction,
matching V2 — closes the deprecation-window drift before V1 sunset (~May 2026).
- portfolio.MarketPosition / historical.Trade keep total_traded, position,
count as 'T | None' without default=None. The OpenAPI spec marks the
underlying wire keys (total_traded_dollars, position_fp, count_fp) as
**required**, so omission must still raise ValidationError — only the
observed JSON null is admitted. Added docstring notes explaining the
intentional non-default so the audit doesn't re-flag them.
- types.UnixSecondsTimestamp: Annotated[int, …] alias for int64 Unix-seconds
wire timestamps. Internal type-aid only (not re-exported via kalshi.__init__).
Applied to Balance.updated_ts, Deposit.created_ts/finalized_ts,
Withdrawal.created_ts/finalized_ts so the int-vs-AwareDatetime split is
greppable when balances/positions are read side-by-side.
- Drift checker (tests/test_contracts.py) now classifies pydantic
AwareDatetime/NaiveDatetime and ForwardRef('datetime') as kind='datetime',
matching what those models actually validate at runtime.
`f"{Decimal('NaN'):f}"` returns the literal string `"NaN"`, and
`_coerce_decimal` previously short-circuited on the `isinstance(value,
Decimal)` branch — a caller doing arithmetic that produced NaN and then
constructing a `CreateOrderRequest(yes_price=that_nan)` would ship
`"NaN"` straight to a real-money order placement endpoint.
`_coerce_decimal` now computes the Decimal first, then `is_finite()`-
guards it, raising `ValueError` on NaN/+Inf/-Inf. One branch protects
every DollarDecimal / FixedPointCount / MultiplierDecimal field at both
parse and serialize.
Closes #270
Code Review — PR #292Wave 3 of the post-v2.4 audit. Solid batch of correctness improvements. Three minor issues worth addressing before merge, plus one lower-priority note. OverviewFive independent items land together:
All items have targeted tests. The changes are surgical and match existing conventions. Issues1.
|
Closes #270
Part of #273 (post-v2.4 audit), Wave 3.