polish(resources): communications status Literal + V2 batch bytes-fast-path#373
Conversation
…-path #324: CommunicationsResource.list_rfqs / list_quotes (sync + async, plus list_all variants) declared 'status: str | None', the only paginated list on the SDK that did not narrow its status filter. The spec defines closed enums (RFQ.status: open|closed; Quote.status: open|accepted|confirmed| executed|cancelled) and the README advertises 'Literal types on fixed-enum kwargs' as a headline feature. Add RfqStatusLiteral / QuoteStatusLiteral to kalshi.models.communications, re-export from kalshi.models + kalshi, and narrow the eight status kwargs. Pure type-system fence, no runtime behavior change — typos now surface at the call site under mypy / IDE autocomplete instead of silently round-tripping. #329: batch_create_v2 / batch_cancel_v2 (sync + async) still serialized via request.model_dump(mode='json') -> _post(json=dict) / _delete_with_body(json=dict), paying the dict-walk pass that httpx's 'json=' encoder repeats — exactly the cost #223 measured and removed for V1 batch_create / batch_cancel. Add _build_batch_create_v2_body / _build_batch_cancel_v2_body next to the V1 builders (model_dump_json + .encode()) and route the V2 methods through _post_json / _delete_with_body_json with content=<bytes>. V2 is the spec-recommended surface for new code, so leaving the perf regression on it would regress #223's own contract. Closes #324, #329
Code Review — PR #373Both changes are correct and well-motivated. A few focused notes below. OverviewIssue #324 (Literal narrowing): Issue #329 (V2 bytes fast-path): Issues1. Trivial wrappers with no logic ( Both functions contain exactly one line of logic: return request.model_dump_json(exclude_none=True, by_alias=True).encode()The V1 builders justify their existence — they normalise def batch_create_v2(self, *, request: BatchCreateOrdersV2Request, …) -> …:
self._require_auth()
data = self._post_json(
"/portfolio/events/orders/batched",
content=request.model_dump_json(exclude_none=True, by_alias=True).encode(),
extra_headers=extra_headers,
)
return BatchCreateOrdersV2Response.model_validate(data)That also removes the four test assertions that patch 2. Multi-paragraph docstrings and issue-number references
3. Missing async status flow-through tests
Minor nit
"""Serialize the V2 batch-cancel body directly to JSON bytes. See
:func:`_build_batch_create_v2_body` for the perf rationale (#329)."""That's an unusual split for what the convention says should be one line. No issues found
Summary: #324 is clean to merge as-is. For #329 I'd inline the trivial V2 helpers and trim the docstrings before merging, plus add the two async status flow-through tests for completeness. |
…status flow tests
|
Round-2 review addressed in 4c7ea5c:
Verification: |
Code Review — PR #373OverviewTwo clean, well-scoped follow-ups: narrowing Issue #324 — Status Literal NarrowingPositives:
Nit — imports inside test methods:
# Current (inside test body)
def test_issue_324_communications_status_literal_narrowing(self) -> None:
from typing import get_args
from kalshi.models.communications import QuoteStatusLiteral, RfqStatusLiteral
...
# Preferred (module top)
from typing import get_args
from kalshi.models.communications import QuoteStatusLiteral, RfqStatusLiteralMinor concern — spec confidence for The Issue #329 — V2 Batch Bytes Fast-PathPositives:
Nit — spurious double blank line: The diff adds a blank line at Observation — test roundtrip assertion: The fast-path tests confirm No Issues Found With
SummaryTwo small nits (in-method imports, extra blank line) — neither is a blocker. The implementation is correct, minimal, and consistent with the project's established patterns. Ready to merge after the nits are addressed if desired, or as-is if they're considered acceptable for the scale of the change. |
Summary
Two LOW-severity follow-ups against the v2.4 / v3.18 surfaces: narrow the
status=kwarg onCommunicationsResource.list_rfqs/list_quotes(syncLiteralaliases mirroring the OpenAPI spec, and routethe V2 batch endpoints through the v2.4 Polish bundle: perf + testing (cursor guard O(1), model_dump_json bytes, bench scripts, from_env precedence test, integration env isolation, KalshiAuth.close terminality) #223 bytes-fast-path so they no
longer pay the dict-walk serialization cost twice per call.
Issues closed
status: str | None— should be Literal-narrowed #324 —list_rfqs/list_quotesstatus=narrowed viaRfqStatusLiteral/QuoteStatusLiteralbatch_create_v2/batch_cancel_v2now usemodel_dump_json+_post_json/_delete_with_body_json(parity with V1 Polish bundle: perf + testing (cursor guard O(1), model_dump_json bytes, bench scripts, from_env precedence test, integration env isolation, KalshiAuth.close terminality) #223)Behavioral changes
CommunicationsResource.list_rfqs(status=...)andlist_quotes(status=...)(sync + async, including
list_all_*) now declare a closedLiteralset. Runtime semantics are unchanged — Python does not enforce
Literalat runtime — but typos like
status="accpeted"are now flagged by mypy/ IDEs at the call site instead of round-tripping to the server. Matches
the project-wide pattern already used by
OrdersResource.list(status=),incentive_programs.list(status=), etc.Tests
tests/test_communications.py::TestIssue324CommunicationsStatusLiteralNarrowing— pins the closed
get_args(RfqStatusLiteral)/get_args(QuoteStatusLiteral)sets against the spec, asserts re-export from
kalshi.models+kalshi,and verifies valid status values flow through to the query string.
tests/test_orders.py::TestIssue329BatchV2BytesFastPathandtests/test_async_orders.py::TestIssue329AsyncBatchV2BytesFastPath—patch
OrdersResource/AsyncOrdersResourceto assertbatch_create_v2routes through
_post_json(content=<bytes>)(never_post(json=...))and
batch_cancel_v2routes through_delete_with_body_json(content=<bytes>)(never
_delete_with_body(json=...)).Source
Round-3 independent audit closure plan, wave
W3(LOW polish / perf).