sartoriuslib.manager¶
SartoriusManager (multi-balance orchestrator), BalanceManager alias,
DeviceResult, ErrorPolicy. See
Async quickstart §Multi-device
and Design §11.
sartoriuslib.manager ¶
Multi-balance orchestrator — :class:SartoriusManager.
The manager coordinates many :class:~sartoriuslib.devices.balance.Balance
instances across one or more serial ports. Operations across different
physical ports run concurrently through
:func:anyio.create_task_group; operations against the same port
serialise through that port's shared
:class:~sartoriuslib.protocol.xbpi.client.XbpiProtocolClient lock.
Port identity is canonicalised before comparison so a balance
referenced via both /dev/ttyUSB0 and /dev/serial/by-id/...
(or COM3 and com3 on Windows) collapses to one client —
critical for the single-in-flight invariant. Pre-built
:class:Transport sources use the object's :func:id as the key so
caller-owned transports aren't accidentally shared.
Error handling is controlled by :class:ErrorPolicy:
- :attr:
ErrorPolicy.RAISE— manager collects all results, and if any balance failed, raises an :class:ExceptionGroupafter the task group joins. - :attr:
ErrorPolicy.RETURN— every balance produces a :class:DeviceResultcontainer; callers inspect.error.
Resource lifecycle goes through an internal tracking structure that
unwinds LIFO on :meth:close or __aexit__. Per-port clients are
ref-counted so the last :meth:remove on a shared port triggers the
transport close.
Design reference: docs/design.md §11.
DeviceResult
dataclass
¶
Per-device result container — value or error, never both.
:attr:protocol is populated by :class:SartoriusManager from the
balance's session so error samples from the
:mod:~sartoriuslib.streaming layer can still record which
protocol produced the failure. Non-manager
:class:~sartoriuslib.streaming.PollSource stubs may leave it
None.
ErrorPolicy ¶
Bases: Enum
How the manager surfaces per-device failures.
Under :attr:RAISE, the manager collects every balance's result
and — if any call failed — raises an :class:ExceptionGroup
containing the per-device exceptions after the task group joins.
Under :attr:RETURN, each balance produces a :class:DeviceResult
and the caller inspects .error per entry.
SartoriusManager ¶
Coordinator for many balances across one or more serial ports.
Operations run concurrently across different physical ports (via
:func:anyio.create_task_group) and serialise on the same-port
client lock. Per-balance failures are surfaced per
:attr:error_policy:
- :attr:
ErrorPolicy.RAISE: the manager still collects results from every balance, then raises an :class:ExceptionGroupif any failed. - :attr:
ErrorPolicy.RETURN: the mapping's values carry :class:DeviceResultcontainers with.valueor.error.
Usage::
async with SartoriusManager() as mgr:
await mgr.add("bal1", "/dev/ttyUSB0")
await mgr.add("bal2", "/dev/ttyUSB1")
readings = await mgr.poll()
Source code in src/sartoriuslib/manager.py
add
async
¶
add(
name,
source,
*,
protocol=ProtocolKind.XBPI,
serial_settings=None,
timeout=1.0,
src_sbn=1,
dst_sbn=9,
strict=False,
identify=True,
)
Register and open a balance under name.
The source discriminates lifecycle ownership:
- :class:
Balance— pre-built (via :func:open_deviceoutside the manager). The manager only tracks the name mapping; it does not take lifecycle ownership. str— serial port path ("/dev/ttyUSB0","COM3"). The manager creates a :class:SerialTransport, canonicalises the port key, and shares the transport across balances on the same bus. Mixing xBPI and SBI sessions on a shared physical port is refused; one serial link has one active protocol.- :class:
Transport— duck-typed transport. The manager invokes :func:open_deviceagainst it but does not take transport ownership.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Unique manager-level identifier. |
required |
source
|
Balance | str | Transport
|
One of the three lifecycle shapes above. |
required |
protocol
|
ProtocolKind
|
Which wire protocol to speak (per
:func: |
XBPI
|
serial_settings
|
SerialSettings | None
|
Override default serial framing. Only
honoured when |
None
|
timeout
|
float
|
Per-call default timeout. |
1.0
|
src_sbn
|
int
|
Host xBPI bus address. |
1
|
dst_sbn
|
int
|
Balance xBPI bus address. |
9
|
strict
|
bool
|
Strict prior gating (see design §6.1). |
False
|
identify
|
bool
|
Run identify on open and cache :class: |
True
|
Returns:
| Type | Description |
|---|---|
Balance
|
The opened :class: |
Raises:
| Type | Description |
|---|---|
SartoriusValidationError
|
|
SartoriusConnectionError
|
Manager is closed. |
Source code in src/sartoriuslib/manager.py
249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 | |
close
async
¶
Tear down every managed balance and port (LIFO).
Source code in src/sartoriuslib/manager.py
execute
async
¶
Dispatch a per-device Command across the requested names.
requests_by_name chooses both which balances participate and
what arguments each gets — supporting the common case of
"same command, different argument per balance".
Source code in src/sartoriuslib/manager.py
get ¶
Return the balance registered under name.
Source code in src/sartoriuslib/manager.py
poll
async
¶
Poll every (or named) balance concurrently across ports.
Returns a mapping from balance name to :class:DeviceResult
even under :attr:ErrorPolicy.RAISE — but under that policy,
any failed balance's error is re-raised as an
:class:ExceptionGroup after all balances have completed.
Source code in src/sartoriuslib/manager.py
remove
async
¶
Unregister and close the balance named name.
If name was the last balance on a shared port, the
transport for that port is closed too. A pre-built
:class:Balance source is only dropped from the manager's
registry — the caller retains lifecycle ownership.