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)
| 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)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| 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.