simvx.core.event_bus

Typed event bus with weak handler references.

Handlers subscribe against a dataclass event type. Calling

meth:

EventBus.publish with an instance of that dataclass synchronously fans the event out to every live handler subscribed for the exact class. There is no MRO walk: a handler for Parent does NOT receive publishes of Child(Parent) – subclasses must subscribe themselves. This keeps dispatch predictable and O(1) per event class.

Vocabulary (subscribe/publish/unsubscribe) is intentionally distinct from

class:

Signal’s connect/emit/disconnect: an EventBus is a typed pub/sub hub, while a Signal is a per-instance callback list. Different shapes, so different verbs.

Handlers are stored as weak references:

  • Bound methods are wrapped in :class:weakref.WeakMethod so the subscription is automatically dropped when the owning instance is garbage collected.

  • Free functions and other callables are stored via :class:weakref.ref. CPython 3.13+ supports weakrefs to module-level functions, but local closures and functools.partial objects do not. Those raise

    class:

    TypeError at subscribe time – callers must use a method on a long-lived object, or hold their own strong reference and pass a module-level function.

Two dispatch modes:

  • meth:

    publish – synchronous. Handlers run in registration order on the calling thread before publish returns.

  • meth:

    publish_deferred – queues the event. The queue is drained when

    meth:

    flush_deferred is called (typically once per frame).

Threading: the bus assumes a single-threaded engine. There are no locks. Calling publish from a non-main thread is undefined behaviour.

Module Contents

Classes

EventBus

Typed publish/subscribe bus keyed on dataclass event types.

Data

API

simvx.core.event_bus.EventCls

None

simvx.core.event_bus.Handler

None

class simvx.core.event_bus.EventBus[source]

Typed publish/subscribe bus keyed on dataclass event types.

Initialization

__slots__

(‘_subs’, ‘_deferred’)

subscribe(event_cls: simvx.core.event_bus.EventCls, handler: simvx.core.event_bus.Handler) None[source]

Register handler for events of exactly event_cls.

Bound methods are stored via :class:weakref.WeakMethod. Other callables use :class:weakref.ref; if the callable does not support weak references (e.g. a local closure or

Class:

functools.partial), a :class:TypeError is raised.

unsubscribe(event_cls: simvx.core.event_bus.EventCls, handler: simvx.core.event_bus.Handler) None[source]

Remove handler from event_cls. Idempotent.

publish(event: Any) None[source]

Synchronously fan event out to handlers of its exact type.

Raises :class:TypeError if event is not a dataclass instance. Dead weak references are pruned lazily during iteration.

publish_deferred(event: Any) None[source]

Queue event for the next :meth:flush_deferred call.

flush_deferred() None[source]

Drain the deferred queue, dispatching each event via :meth:publish.