simvx.core.event_bus

Typed event bus keyed on dataclass event types.

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.

Each event class has its own :class:Signal, so a handler’s lifetime follows the signal rule:

  • A bound method of a :class:Node is held weakly, and its subscription ends when the node is destroyed (:meth:Node.destroy, or change_scene, which destroys the scene it replaces) or garbage-collected. Leaving the tree without being destroyed (remove_child) does not end it.

  • Every other callable (a lambda, a closure, a :class:functools.partial, a free function, a method of a plain object) is held strongly and fires until it is unsubscribed, even when it captures a node that was destroyed.

Two dispatch modes:

  • meth:

    publish: synchronous. Handlers run in subscription 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.

A bound method of a :class:Node is held weakly and dropped when the node is destroyed or collected; any other callable is held until

Meth:

unsubscribe. Subscribing a handler that is already subscribed does nothing.

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

Remove handler from event_cls. Idempotent.

handler matches by equality, so a freshly bound method finds the subscription made with an earlier binding of the same method.

disconnect_from_module(module_name: str) → int[source]

Drop every handler defined in module_name; return how many.

Hot reload calls this before reloading a module, so the old version of a handler stops firing and the old module can be collected.

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. Handlers run in subscription order. Subscriptions of collected nodes are pruned during dispatch.

Unsubscribing takes effect immediately, as it does for a

Class:

Signal: a handler removed by an earlier handler in this same dispatch is not called. Unsubscribing mid-dispatch nearly always means the subscriber is being torn down, so calling it anyway is wrong.

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.