Make documentation standalone and generalize examples

This commit is contained in:
Melvin Strobl
2026-10-25 14:43:20 +01:00
parent 13bf0f76d7
commit bdb18b99da
57 changed files with 553 additions and 481 deletions
@@ -1,6 +1,6 @@
"""Who may see a device's camera: superusers only, or every member too.
openpanel ROADMAP C4. ``viewers`` on a device covers its ``image`` and
``viewers`` on a device covers its ``image`` and
``video`` messages, their bytes, frames on the socket and its live view. A
device credential is bounded by its dashboards instead.
"""
+1 -1
View File
@@ -1,6 +1,6 @@
"""Cameras on a device: frames over its socket, demand, and what a screen fetches.
openpanel ROADMAP C1. A device reports a ``camera`` port that sends only while
A device reports a ``camera`` port that sends only while
somebody wants it. Demand is what the viewer sockets want plus what running
flows read, mapped onto the device's on-demand ports and sent to its socket.
"""
+1 -1
View File
@@ -1,6 +1,6 @@
"""Live view: WebRTC signalling relayed between a viewer's socket and a device's.
openpanel ROADMAP L1. The server routes by session, holds a device to two
The server routes by session, holds a device to two
viewers, ends a session when either socket goes or no answer comes, and hands
out TURN credentials in coturn's REST scheme.
"""
+1 -7
View File
@@ -1,10 +1,4 @@
"""What the house port needed from the built-in nodes.
Three additions, each with a device behind it: an MQTT filter that actually
routes what it subscribed to, a value lifted out of the object a device wraps
it in, and a wait that differs per message because a shutter takes longer to
come up than to go down.
"""
"""Device messaging with MQTT filters, wrapped values and per-message delays."""
from fluksio.flow.messages import DType, MessageSpec
from fluksio.flow.nodes import MqttNode
+4 -9
View File
@@ -211,11 +211,8 @@ def test_only_advisory_codes_are_flagged_advisory():
def test_a_producer_that_cannot_run_does_not_strand_its_consumer():
"""One wave, two producers of one consumer, and one of them never ready.
The house's shape: a battery reading wakes the boiler arbiter and the
watering-pump trigger in the same wave, and the DMX encoder reads both. The
pump waits on a pulse that only exists at 02:00, so it is never ready — and
passing over it used to leave the encoder unreachable, which put every
boiler and plug command into its message and no further.
The ready producer must reach its consumer even when a sibling is
waiting for an input. The consumer can use that sibling's stored value.
"""
ran = []
@@ -268,10 +265,8 @@ def test_a_producer_that_cannot_run_does_not_strand_its_consumer():
def test_a_quiet_producer_does_not_veto_a_noisy_sibling():
"""Two report-by-exception producers, one consumer, and only one with news.
The house reads both boilers into one DMX encoder through `rbe` nodes. The
kitchen boiler is unchanged almost always, so it returns nothing — and
while that held the encoder's dependency count up, the main boiler's
command reached its message and got no further.
A producer that publishes nothing must not block a shared consumer
from processing its sibling's new value.
"""
ran = []
+5 -5
View File
@@ -50,11 +50,11 @@ def test_a_service_comes_back_and_its_url_follows(monkeypatch):
async def scenario() -> None:
agent = Agent()
agent.worker = RemoteWorker(
name="amcomp",
name="gpu-worker",
labels=["gpu"],
send=agent.send_json,
loop=asyncio.get_running_loop(),
host="10.0.0.5",
host="192.0.2.5",
)
hub = RemoteWorkerHub()
node = ServiceNode(
@@ -78,7 +78,7 @@ def test_a_service_comes_back_and_its_url_follows(monkeypatch):
hub.attach(agent.worker)
await until(lambda: bool(agent.serves()))
await until(lambda: url() == "http://10.0.0.5:8110")
await until(lambda: url() == "http://192.0.2.5:8110")
first = agent.serves()[0]
assert first["argv"] == ["serve", "--port", "8110"]
assert health[-1] == "ok"
@@ -88,7 +88,7 @@ def test_a_service_comes_back_and_its_url_follows(monkeypatch):
await until(lambda: url() == "")
assert "degraded" in health[health.index("ok") :]
await until(lambda: len(agent.serves()) == 2)
await until(lambda: url() == "http://10.0.0.5:8110")
await until(lambda: url() == "http://192.0.2.5:8110")
# Stopping the flow ends the call on the worker, and empties the url.
await node.stop()
@@ -110,7 +110,7 @@ def test_a_service_that_never_gets_healthy_reads_down(monkeypatch):
async def scenario() -> None:
agent = Agent()
agent.worker = RemoteWorker(
name="amcomp",
name="gpu-worker",
labels=["gpu"],
send=agent.send_json,
loop=asyncio.get_running_loop(),
+1 -5
View File
@@ -116,11 +116,7 @@ def test_one_flows_failure_does_not_stand_another_down():
def test_two_tasks_on_one_flow_do_not_spend_each_others_budget():
"""The house's power flow: an MQTT subscriber and its keepalive publisher.
Both die with the same broker. Sharing one budget meant the flow was stood
down after half the restarts either task was allowed on its own.
"""
"""A subscriber and publisher each get a full restart budget."""
tries = {"sub": 0, "pub": 0}
def crasher(which: str):