jmri_core.beans.throttle_manager
ThrottleManager — acquire/release throttle handles per DCC address.
Throttle objects aren't NamedBeans (they're transient holds on a slot in
the command station), so they don't fit the regular Manager[T] shape.
A ThrottleManager instead provides:
acquire(address, long_address)→Throttle— get an existing throttle for address if one is already held, or create a new one.release(throttle)— let go of the throttle; subsequentacquirewith the same address will create a fresh one.- iteration yields every active throttle.
Drivers override _construct() to return their hardware-aware
Throttle subclass (e.g. LnThrottle). The base in-memory impl is
used by InternalConnection and by tests.
1"""``ThrottleManager`` — acquire/release throttle handles per DCC address. 2 3Throttle objects aren't NamedBeans (they're transient holds on a slot in 4the command station), so they don't fit the regular ``Manager[T]`` shape. 5A ``ThrottleManager`` instead provides: 6 7* ``acquire(address, long_address)`` → :class:`Throttle` — get an existing 8 throttle for *address* if one is already held, or create a new one. 9* ``release(throttle)`` — let go of the throttle; subsequent ``acquire`` 10 with the same address will create a fresh one. 11* iteration yields every active throttle. 12 13Drivers override :meth:`_construct` to return their hardware-aware 14``Throttle`` subclass (e.g. ``LnThrottle``). The base in-memory impl is 15used by ``InternalConnection`` and by tests. 16""" 17from __future__ import annotations 18 19from collections.abc import Iterator 20 21from jmri_core.beans.throttle import Throttle 22from jmri_core.events import Signal 23 24 25class ThrottleManager: 26 """Acquire/release throttle handles by DCC address.""" 27 28 def __init__(self, system_prefix: str) -> None: 29 if not system_prefix: 30 raise ValueError("system_prefix must be a non-empty string") 31 self.system_prefix = system_prefix 32 self._throttles: dict[int, Throttle] = {} 33 self.acquired: Signal[Throttle] = Signal() 34 self.released: Signal[Throttle] = Signal() 35 36 async def acquire(self, address: int, *, long_address: bool = False) -> Throttle: 37 if address in self._throttles: 38 return self._throttles[address] 39 throttle = await self._construct(address, long_address=long_address) 40 self._throttles[address] = throttle 41 await self.acquired.emit(throttle) 42 return throttle 43 44 async def release(self, throttle: Throttle) -> None: 45 existing = self._throttles.get(throttle.address) 46 if existing is not throttle: 47 return 48 del self._throttles[throttle.address] 49 await self.released.emit(throttle) 50 51 def get(self, address: int) -> Throttle | None: 52 return self._throttles.get(address) 53 54 def __iter__(self) -> Iterator[Throttle]: 55 return iter(self._throttles.values()) 56 57 def __len__(self) -> int: 58 return len(self._throttles) 59 60 async def _construct(self, address: int, *, long_address: bool) -> Throttle: 61 """Build the throttle for *address*. Driver hook.""" 62 return Throttle(address=address, long_address=long_address)
class
ThrottleManager:
26class ThrottleManager: 27 """Acquire/release throttle handles by DCC address.""" 28 29 def __init__(self, system_prefix: str) -> None: 30 if not system_prefix: 31 raise ValueError("system_prefix must be a non-empty string") 32 self.system_prefix = system_prefix 33 self._throttles: dict[int, Throttle] = {} 34 self.acquired: Signal[Throttle] = Signal() 35 self.released: Signal[Throttle] = Signal() 36 37 async def acquire(self, address: int, *, long_address: bool = False) -> Throttle: 38 if address in self._throttles: 39 return self._throttles[address] 40 throttle = await self._construct(address, long_address=long_address) 41 self._throttles[address] = throttle 42 await self.acquired.emit(throttle) 43 return throttle 44 45 async def release(self, throttle: Throttle) -> None: 46 existing = self._throttles.get(throttle.address) 47 if existing is not throttle: 48 return 49 del self._throttles[throttle.address] 50 await self.released.emit(throttle) 51 52 def get(self, address: int) -> Throttle | None: 53 return self._throttles.get(address) 54 55 def __iter__(self) -> Iterator[Throttle]: 56 return iter(self._throttles.values()) 57 58 def __len__(self) -> int: 59 return len(self._throttles) 60 61 async def _construct(self, address: int, *, long_address: bool) -> Throttle: 62 """Build the throttle for *address*. Driver hook.""" 63 return Throttle(address=address, long_address=long_address)
Acquire/release throttle handles by DCC address.
ThrottleManager(system_prefix: str)
29 def __init__(self, system_prefix: str) -> None: 30 if not system_prefix: 31 raise ValueError("system_prefix must be a non-empty string") 32 self.system_prefix = system_prefix 33 self._throttles: dict[int, Throttle] = {} 34 self.acquired: Signal[Throttle] = Signal() 35 self.released: Signal[Throttle] = Signal()
acquired: jmri_core.Signal[jmri_core.beans.Throttle]
released: jmri_core.Signal[jmri_core.beans.Throttle]
37 async def acquire(self, address: int, *, long_address: bool = False) -> Throttle: 38 if address in self._throttles: 39 return self._throttles[address] 40 throttle = await self._construct(address, long_address=long_address) 41 self._throttles[address] = throttle 42 await self.acquired.emit(throttle) 43 return throttle