Skip to content

Comments

feat: Python client implementation for River protocol v2.0#356

Draft
Monkatraz wants to merge 3 commits intomainfrom
python-client
Draft

feat: Python client implementation for River protocol v2.0#356
Monkatraz wants to merge 3 commits intomainfrom
python-client

Conversation

@Monkatraz
Copy link
Contributor

Why

Add a Python client for the River protocol, enabling Python applications to call River services. This is a clean room implementation referencing the TypeScript client and PROTOCOL.md.

Slack thread: https://slack.com/archives/C0AEE1W8E3X/p1771490314906739

What changed

Added python-client/ directory containing a complete River v2.0 client implementation in Python:

Core modules:

  • river/types.py — Transport message types, control flags, handshake payloads, result types, ID generation
  • river/codec.py — NaiveJsonCodec (JSON) and BinaryCodec (msgpack) with CodecMessageAdapter
  • river/streams.py — Async Readable/Writable stream abstractions for procedure I/O
  • river/session.py — Session state machine with seq/ack bookkeeping, send buffer, heartbeat echo, grace periods
  • river/transport.py — WebSocketClientTransport with connection lifecycle, handshake, reconnection with exponential backoff, message dispatch
  • river/client.py — RiverClient providing rpc(), stream(), upload(), subscribe() APIs

Protocol features implemented:

  • All 4 procedure types (rpc, stream, upload, subscription)
  • Handshake with protocol version negotiation
  • Seq/ack bookkeeping with exactly-once delivery semantics
  • Send buffer for transparent reconnection (message retransmission)
  • Heartbeat echo (client echoes server heartbeats)
  • Session grace period with disconnect detection
  • Exponential backoff with jitter for reconnection (LeakyBucketRateLimit)
  • Stream lifecycle (open/close/cancel control flags)
  • Service-level errors vs protocol errors (UNEXPECTED_DISCONNECT, CANCEL, UNCAUGHT_ERROR)

Test suite (40 tests, all passing):

  • E2E tests against a TypeScript River server: rpc, stream, upload, subscription
  • Fallible procedures, concurrent operations, server-initiated cancel
  • Closed transport error handling
  • Unit tests for Readable, Writable, TransportMessage, Codec, ControlFlags
  • Test server (test_server.mjs) runs the standard test services

Running the tests:

cd python-client
python3 -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]"
# From river repo root: npx tsup  (builds the TS server)
pytest tests/ -v

Versioning

  • Breaking protocol change
  • Breaking ts/js API change

~ written by Zerg 👾

Clean room implementation of a River client in Python, referencing
the TypeScript client and PROTOCOL.md. Includes full support for
all four procedure types (rpc, stream, upload, subscription),
transparent reconnection, heartbeat echo, and seq/ack bookkeeping.

40 tests passing against the TypeScript server.
@Monkatraz Monkatraz added the zergling-authored PRs authored by Zerg label Feb 19, 2026
Replace the hand-written .mjs test server with the original .ts source.
conftest.py now runs esbuild at test session start to bundle
test_server.ts -> test_server.mjs (gitignored build artifact).

This avoids tsx/ts-node runtime module resolution issues with the
river repo's bundler-style tsconfig while keeping the test server
as authored TypeScript.
…se, and Readable edge cases

- Add CancellationService to test server with blocking + immediate handlers
- Add client-initiated cancellation tests for all 4 proc types (rpc, stream, upload, subscription)
- Add idempotent close tests (stream, subscription) and cancellation-after-transport-close
- Add eagerly-connect E2E test
- Add 17 new Readable unit tests: locking semantics, eager iteration, collect-waits-for-close, break variants
- Fix Readable to enforce locking (TypeError on double __aiter__/collect)
- Replace async generator iterator with _ReadableIterator class for synchronous break cleanup
- Fix break() to be no-op when stream already closed with empty queue
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

zergling-authored PRs authored by Zerg

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant