Skip to main content

pondsocket

PondSocket - channel-based real-time framework for Python. Bring-your-own-server design: the core knows nothing about HTTP frameworks or WebSocket libraries. You build the layered API (Server -> Endpoint -> Channel -> User), and an adapter (e.g. pondsocket-asgi) bridges it to your HTTP stack.

Install

pip install pondsocket
pip install "pondsocket[redis]"   # multi-node deployments

Concepts

PondSocket     top-level facade, holds endpoints
  └── Endpoint   one URL path, runs the connection auth handler, owns transports
        └── Lobby     one channel pattern (e.g. "/chat/:room_id"), holds shared middleware
              └── Channel    one live channel instance, holds users + presence

Five contexts, scoped to lifecycle moments

Context When What it decides / does
ConnectionContext HTTP upgrade accept / decline socket, set initial assigns
JoinContext per channel join accept / decline membership, track presence
EventContext per incoming event broadcast, reply, update presence/assigns, evict
OutgoingContext per recipient, per send transform payload or block delivery
LeaveContext user gone final cleanup (user already removed)

Minimal example

from pondsocket import ConnectionContext, EventContext, JoinContext, PondSocket


async def auth(ctx: ConnectionContext) -> None:
    if ctx.query.get("token") != "secret":
        ctx.decline(401, "Invalid token")
        return
    ctx.accept(user_id=ctx.query.get("uid", "anon"))


async def on_join(ctx: JoinContext) -> None:
    await ctx.accept()
    await ctx.track({"status": "online"})


async def on_message(ctx: EventContext) -> None:
    await ctx.broadcast(ctx.event_name, ctx.get_payload())


pond = PondSocket()
endpoint = pond.create_endpoint("/api/socket", auth)
lobby = endpoint.create_channel("/chat/:room_id", on_join)
lobby.on_message("message", on_message)

To actually serve traffic, wrap pond in an adapter — see pondsocket-asgi for the canonical one.

Distributed (multi-node)

from redis.asyncio import Redis
from pondsocket import PondSocket
from pondsocket.distributed import RedisPubSub

redis = Redis(host="localhost", port=6379)
pubsub = RedisPubSub(redis, owns_client=True)
pond = PondSocket(pubsub=pubsub)

Cross-node broadcasts and presence events propagate via Redis PSUBSCRIBE. node_id is auto-generated when a pubsub is configured. Each broadcast carries the nodeId so emitters filter their own echo.

See pondsocket.distributed.RedisPubSub for the implementation. The PubSub protocol is implementable for other backends.

Hooks & metrics

from pondsocket import Hooks, NoopMetrics, Options, PondSocket, TokenBucketRateLimiter

hooks = Hooks(
    rate_limiter=TokenBucketRateLimiter(rate=10, capacity=20),
    metrics=NoopMetrics(),
)
pond = PondSocket(options=Options(hooks=hooks))

Auto-fired by the framework: connection_opened/connection_closed, channel_created/channel_destroyed/channel_joined/channel_left, plus on_connect/on_disconnect/before_join/after_join/before_message/after_message.

Opt-in middleware factories for per-handler instrumentation:

from pondsocket import with_metrics, with_rate_limiter

lobby.on_message(
    "message",
    on_message,
    with_rate_limiter(hooks, key_fn=lambda msg: msg.user.id),
    with_metrics(hooks),
)

Testing

InMemoryTransport is a public test utility that satisfies the Transport protocol without any network I/O:

from pondsocket import InMemoryTransport

t = InMemoryTransport("alice")
await endpoint.register_transport(t)

await t.push_inbound(some_event)
sent = await t.receive_sent()

Public API

from pondsocket import ...

  • Core: PondSocket, Endpoint, Lobby, Channel, Options, Event, User, MessageEvent, RecipientSpec
  • Contexts: ConnectionContext, JoinContext, EventContext, LeaveContext, OutgoingContext
  • Transport: Transport (Protocol), InMemoryTransport, SSEServerTransport, TransportType, OnCloseCallback, OnMessageHandler
  • PubSub: PubSub (Protocol), LocalPubSub, format_topic, match_topic, PubSubClosedError
  • Hooks: Hooks, RateLimiter, MetricsCollector, NoopMetrics, TokenBucketRateLimiter, with_rate_limiter, with_metrics
  • Wire: event_to_json, event_to_wire, parse_inbound_text, wire_to_event, event_to_pubsub_bytes, pubsub_bytes_to_event
  • Errors: PondError, status constructors, error_event

License

GPL-3.0-or-later.

Metadata

Release files for pondsocket 0.0.7

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for pondsocket 0.0.7
File Size Uploaded Provenance Actions
pondsocket-0.0.7.tar.gz 48.4 kB Without provenance Details for pondsocket-0.0.7.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for pondsocket 0.0.7
File Interpreter ABI Platform Actions
pondsocket-0.0.7-py3-none-any.whl Python 3 none any Details for pondsocket-0.0.7-py3-none-any.whl

Total release size: 90.2 kB

Release files / pondsocket-0.0.7.tar.gz

Download URL pondsocket-0.0.7.tar.gz
Size 48.4 kB
Tags Source
SHA-256 checksum
How to use checksums
2063b71052ec4461462c7a34da3c732cd3611d4ad5c9b0af72a90aa6bb4d1624
BLAKE2b-256 checksum
How to use checksums
27ef99c63867fb1578799800b0f6fcb13d95650255a4737d3cedc81361e94e6f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.0

Release files / pondsocket-0.0.7-py3-none-any.whl

Download URL pondsocket-0.0.7-py3-none-any.whl
Size 41.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
3bf240a5ba04fb97e1acb051856ac67d8033317abc262538c40c4621a3009ed8
BLAKE2b-256 checksum
How to use checksums
79b4cc0198d01444f9dc10a8dc1028e49ad964193d8b66699628aec7b70f8cdd
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.0

Security for pondsocket 0.0.7

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page