fix: snapshot _connection_listeners before dispatch, not the live dict - #34
Conversation
A connection listener that calls get_vehicle() for an uncached VIN (e.g. an integration discovering a vehicle on reconnect) registers that vehicle's own connection listener from inside TeslemetryStreamVehicle __init__, mutating _connection_listeners while _update_connection_listeners() is iterating it. That raised RuntimeError: dictionary changed size during iteration, interrupting connect()/disconnect notification delivery. listen() already dispatches over a snapshot of _listeners for the same reason; _update_connection_listeners() now does the same for _connection_listeners. Reported by Codex review on #33.
💡 Codex Reviewpython-teslemetry-stream/teslemetry_stream/vehicle.py Lines 139 to 142 in 9fe8d47 When a vehicle retained fields or AGENTS.md reference: AGENTS.md:L21-L21 ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
Intent
_update_connection_listeners()iteratedself._connection_listeners.values()directly. A connection listener that callsget_vehicle()for an uncached VIN - e.g. an integration discovering a vehicle on reconnect - registers that vehicle's own connection listener fromTeslemetryStreamVehicle.__init__, mutating_connection_listenersmid-iteration and raisingRuntimeError: dictionary changed size during iteration, which interruptsconnect()/disconnect notification delivery for every other listener still due to run._update_connection_listeners()before fixing, and viatests/test_stream_lifecycle.py's new test through the realconnect()path.list(...)snapshot instead of the live dict view - the same fixlisten()already applies to_listenersfor the identical hazard (seeAGENTS.md), just without the sort/ordering requirement, since connection listeners don't share a mutable event object to race over.tests/test_stream_lifecycle.pyadds a case mirroring the existing_listenersmid-dispatch coverage: a connection listener discovering a vehicle mid-dispatch must not raise, and both the discovery and the new vehicle's own listener registration must still land correctly.