babylon.engine.observer_adapter
ProtocolObserverAdapter for thread-safe GUI callback delivery.
This module provides a thread-safe bridge between the simulation engine’s observer notifications and GUI callbacks.
Feature: 006-gui-protocol-extension Date: 2026-01-31
- Thread Safety Architecture:
_lock protects _callbacks list during register/unregister
notify() creates snapshot BEFORE iterating callbacks
Callbacks receive SimulationSnapshot (frozen), NOT SimulationState reference
Callback exceptions are caught and logged (per ADR003)
- Why This Matters:
GUI callbacks NEVER hold a reference to mutable Simulation internals
Snapshot is created at a single consistent point in time
GUI thread can process the snapshot at leisure without races
Complete isolation between engine thread and GUI thread
See also
data-model.md#ProtocolObserverAdapter: Class specification
plan.md#Per-Tick Update Rule: Notification sequence
research.md#1: PyQt6 thread communication research
Classes
|
Thread-safe bridge between simulation and GUI callbacks. |
- class babylon.engine.observer_adapter.ProtocolObserverAdapter(simulation)[source]
Bases:
objectThread-safe bridge between simulation and GUI callbacks.
This adapter ensures GUI callbacks receive frozen snapshots rather than live references to mutable simulation state, providing complete thread safety for cross-thread GUI integration.
- Parameters:
simulation (SimulationState)
- _simulation
Reference to simulation for snapshot creation.
- _callbacks
Registered GUI callbacks.
- _lock
Synchronization for callback list modification.
Example
>>> from babylon.engine.simulation import Simulation >>> sim = Simulation.from_sqlite(["26163"]) >>> adapter = ProtocolObserverAdapter(sim) >>> >>> def my_callback(tick: int, snapshot: SimulationSnapshot) -> None: ... print(f"Tick {tick}: {len(snapshot.territories)} territories") >>> >>> adapter.register(my_callback) >>> # ... simulation runs in another thread ... >>> adapter.notify(tick=5) # Called by engine after step()
- __init__(simulation)[source]
Initialize adapter with simulation reference.
- Parameters:
simulation (
SimulationState) – Simulation instance implementing SimulationState protocol. Used to create snapshots via get_snapshot().- Return type:
None
- register(callback)[source]
Register a GUI callback for tick notifications.
Thread-safe: may be called from any thread. Idempotent: duplicate registration is ignored (callback invoked once per tick).
- Parameters:
callback (
Callable[[int,SimulationSnapshot],None]) – Function to call with (tick, snapshot) after each step().- Return type:
- unregister(callback)[source]
Remove a previously registered callback.
Thread-safe: may be called from any thread. No-op if callback was not registered.
- Parameters:
callback (
Callable[[int,SimulationSnapshot],None]) – The callback function to remove.- Return type:
- notify(tick)[source]
Notify all registered callbacks with frozen snapshot.
Thread-safe: creates snapshot before iteration, exceptions logged. Callbacks receive immutable snapshot, not live simulation reference.
Critical: Snapshot is created BEFORE iterating callbacks. This ensures: 1. All callbacks see the same consistent state 2. GUI code cannot race with engine mutations 3. Callback processing time does not affect snapshot consistency