. . c o d e c h u . .
. \ | / e v e n t s \ | .
((((( ── ((•)) ──────────── ((•)) ── )))))
' / | \ / | '
' ' scan.* ui.click '
Thread-safe multi-channel pub/sub — emit from anywhere, listen everywhere.
codechu-events
Thread-safe multi-channel event bus for Python. Pure stdlib, ~150 LOC.
pip install codechu-events
What it gives you
- Multi-channel pub/sub with glob-pattern filtering:
["scan.*", "ui.click"] - Thread-safe — emit from any thread, never blocks
- Bounded queues per subscriber — slow consumers drop events, fast publishers never wait
- Sync + async iteration —
for ev in sub:orasync for ev in sub.aiter(): - Context manager for clean unsubscribe:
with bus.subscribe_ctx([...]) as sub: - Heartbeat support for dead-connection detection on idle channels
- Resource limits — max subscribers + max queue depth, bounded by design
- Stats for monitoring (subscriber count, drop count, queue depth)
Quick examples
Basic usage
Construct a Bus() explicitly — there is no module-level default, so
ownership and lifetime stay in the caller's hands.
from codechu_events import Bus
bus = Bus()
with bus.subscribe_ctx(["scan.*"]) as sub:
bus.emit("scan.started", path="/home")
bus.emit("scan.progress", count=42)
bus.emit("scan.finished", count=128, ok=True)
bus.emit("foo.bar") # filtered out
for ev in sub:
print(ev["event"], ev)
Multiple isolated buses
A single process can run multiple independent buses — useful for separating domains (e.g. UI events vs telemetry) or for testing:
from codechu_events import Bus
ui_bus = Bus()
telemetry_bus = Bus(max_subscribers=128) # larger cap for telemetry
ui_sub = ui_bus.subscribe(["ui.*"])
telemetry_sub = telemetry_bus.subscribe(["metric.*"])
ui_bus.emit("ui.click", button="ok")
telemetry_bus.emit("metric.fps", value=58)
# ui_sub only sees ui.click; telemetry_sub only sees metric.fps
Custom subscription class (field-based filter)
For filtering beyond glob, subclass Subscription and override matches():
from codechu_events import Bus, Subscription
class PanelFilter(Subscription):
"""Only events with event['panel'] == 'suggestion'."""
def matches(self, event_type, event=None):
if event is None:
return True # cheap type-check pass; final check at push
return event.get("panel") == "suggestion"
bus = Bus()
sub = bus.subscribe(["*"], subscription_class=PanelFilter)
bus.emit("scan.started", panel="suggestion") # delivered
bus.emit("scan.started", panel="treemap") # rejected
Async iteration
import asyncio
from codechu_events import Bus
bus = Bus()
async def consume():
with bus.subscribe_ctx(["scan.*"], heartbeat_sec=5.0) as sub:
async for ev in sub.aiter():
print(ev)
asyncio.run(consume())
Documentation
- API reference — every public symbol, glob syntax, heartbeat semantics.
- Migration guide — v0.1 → v0.2 (module-level shims removed).
- Recipes — singleton bus, isolated buses, async, backpressure, heartbeat, tests.
API reference
Bus
| Method | Purpose |
|---|---|
Bus(max_subscribers=64, queue_max=200) |
Construct an independent bus. |
bus.emit(event_type, **fields) |
Publish event. Never blocks. |
bus.subscribe(types=["*"], heartbeat_sec=5.0) |
Create a Subscription. Caller must unsubscribe(). |
bus.subscribe_ctx(types, heartbeat_sec=5.0) |
Context manager (auto-unsubscribe on exit). |
bus.unsubscribe(sub) |
Idempotent removal + sub.close(). |
bus.stats() |
Dict with subscriber count, total emitted, drop counts. |
bus.subscriber_count() |
Active subscription count. |
bus.reset() |
Close all subscriptions and zero counters. |
Subscription
| Member | Purpose |
|---|---|
for ev in sub: |
Sync blocking iteration. Auto-emits _keepalive on idle. |
async for ev in sub.aiter(): |
Async iteration with event loop. |
sub.dropped |
Count of events dropped due to slow consumer. |
sub.received |
Count of events accepted. |
sub.close() |
Stop iteration (sentinel injected). |
Resource limits
| Constant | Default | Tweakable |
|---|---|---|
QUEUE_MAX |
200 | Max events per subscriber queue (drops on overflow) |
MAX_SUBSCRIBERS |
64 | Max concurrent subscribers |
DEFAULT_HEARTBEAT_SEC |
5.0 | Idle keepalive interval |
Exceeding MAX_SUBSCRIBERS raises SubscriberLimitExceeded.
License
MIT — see LICENSE.
Part of Codechu.
Metadata
Release files for codechu-events 0.3.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| codechu_events-0.3.0.tar.gz | 14.8 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| codechu_events-0.3.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 26.6 kB
Release files / codechu_events-0.3.0.tar.gz
| Download URL | codechu_events-0.3.0.tar.gz |
|---|---|
| Size | 14.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
057ad1be022595ffff10744c58c7a4eef21cdf00421f755ef71bf223ee862f25
|
|
BLAKE2b-256 checksum How to use checksums |
4d6deebf8ad9c9cc3250ada1e227339c1766711d94f7ad608ed0a9e8d87299a9
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
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.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on May 20, 2026.
Transparency logRelease files / codechu_events-0.3.0-py3-none-any.whl
| Download URL | codechu_events-0.3.0-py3-none-any.whl |
|---|---|
| Size | 11.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
5cf8275b5b67b6daf7484a3422049578681f01d35fd9649576e02f5c23caf8de
|
|
BLAKE2b-256 checksum How to use checksums |
69e3f4bf2d8c91853bd56f1d7434b21c8e2ddf773668c03cadda5f367b78b32c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
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.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on May 20, 2026.
Transparency log