Add your description here
Project description
SpiriSynq
SpiriSynq keeps Python dataclass instances in sync across processes, machines, and languages over a Zenoh pub/sub network. Define a typed dataclass, point multiple instances at the same topic, and field changes flow between them automatically.
from dataclasses import dataclass
from SpiriSynq.syncable_objects import SyncableObject
@dataclass
class Telemetry(SyncableObject):
altitude: float = 0.0
battery: int = 100
# Process A — owns the data
t = Telemetry("drone/telemetry", synq_authoritive=True)
t.altitude = 42.5 # published to the network automatically
# Process B — mirrors it
mirror = Telemetry.from_topic("drone/telemetry")
print(mirror.altitude) # 42.5
Installation
pip install SpiriSynq
Requires Python 3.13+. A Zenoh router is optional for local use — peers discover each other directly.
How it works
Each syncable field maps to a Zenoh key expression <topic>/<field>. When a field changes, psygnal fires a signal, SpiriSynq serialises the new value to YAML, and publishes it. All subscribers on the same topic receive the update and apply it in-place without echo-looping it back.
Nested dataclass fields sync at the sub-field level: a change to robot.gps.latitude publishes to <topic>/gps/latitude, not <topic>/gps. Inherit from SubSyncableDataclass to make a nested type fully evented without Zenoh overhead; alternatively, use @dataclass(frozen=True) for immutable value objects that are replaced atomically.
Authoritative vs mirror
Sync is bidirectional — every instance both publishes its own changes and receives changes from others. synq_authoritive controls only the queryable side:
- Authoritative (
synq_authoritive=True): registers Zenoh queryables for full-state rehydration on connect,@remote_methodRPCs, and schema/discovery endpoints. Sets the base topic prefix from the hostname. - Mirror (default): publishes and receives field changes just like an authoritative instance, but forwards RPC calls to the authoritative node rather than running them locally.
# Both sides can write — sync is bidirectional
counter = Counter("myapp/counter", synq_authoritive=True)
mirror = Counter.from_topic("myapp/counter")
mirror.value = 99 # received by counter
Remote methods
@remote_method exposes a method as a Zenoh queryable. Mirrors call it transparently — the call is routed to the authoritative node and the return value is sent back.
from SpiriSynq.remote_callables import remote_method
@dataclass
class Robot(SyncableObject):
status: str = "idle"
@remote_method
def arm(self, mode: str = "auto") -> str:
self.status = "armed"
return f"armed in {mode} mode"
# From a mirror — works exactly like a local call
robot = Robot.from_topic("fleet/robot1")
result = robot.arm(mode="manual") # "armed in manual mode"
Generator and async generator methods are supported. The mirror receives a regular Python generator that streams values as each reply arrives.
Custom timeouts: robot.arm.timeout(5.0)(mode="manual").
Discovery
from SpiriSynq.session import current_session
session = current_session.get()
for metadata in session.list_topics():
print(metadata["topic"], metadata["classes"])
# Filter by type
for metadata in session.list_topics(type_filter="Robot"):
robot = Robot.from_topic(metadata["topic"])
Cross-language compatibility
The wire format is plain Zenoh with YAML payloads. Any node that implements the SpiriSynq protocol — four mandatory queryables and per-field puts — is a first-class participant. No library required on the other end.
Key configuration options
| Field | Default | Purpose |
|---|---|---|
synq_authoritive |
False |
Register queryables; answer rehydration and RPC calls |
synq_publish |
True |
Publish local changes to the network |
synq_receive |
True |
Apply incoming changes from the network |
sync_lazy_publish |
False |
Skip publishing when no subscribers are present |
synq_auto_start |
True |
Call sync() automatically on construction |
Docs
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file spirisynq-0.1.0.tar.gz.
File metadata
- Download URL: spirisynq-0.1.0.tar.gz
- Upload date:
- Size: 51.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
76dbc487c62217d8f53bcfd06a6e48d0b8eda4c4cabc7529f1c3839308eb5f8c
|
|
| MD5 |
04fe6a0db3210a171d0bcabbbec4c893
|
|
| BLAKE2b-256 |
de4015eb9144f1602b906f748fba15c3622614728fcc89f3997466f804c029ef
|
Provenance
The following attestation bundles were made for spirisynq-0.1.0.tar.gz:
Publisher:
publish.yml on spiri-robotics/SpiriSynq
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
spirisynq-0.1.0.tar.gz -
Subject digest:
76dbc487c62217d8f53bcfd06a6e48d0b8eda4c4cabc7529f1c3839308eb5f8c - Sigstore transparency entry: 1853468582
- Sigstore integration time:
-
Permalink:
spiri-robotics/SpiriSynq@b6c6e4fc1af587c652cc04f0335c884b0576d41d -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/spiri-robotics
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@b6c6e4fc1af587c652cc04f0335c884b0576d41d -
Trigger Event:
push
-
Statement type:
File details
Details for the file spirisynq-0.1.0-py3-none-any.whl.
File metadata
- Download URL: spirisynq-0.1.0-py3-none-any.whl
- Upload date:
- Size: 38.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
aaaa8f20ed873f5f022063d10dbbb71c932643722d18c1c4fb09f2df09fa6358
|
|
| MD5 |
04d86c3a790dbb6333b65fe3781d80fa
|
|
| BLAKE2b-256 |
28ebfdc0ee9e446b0f18ebaa0d5204e7f5375f1c989a3ef12085eab556c00e48
|
Provenance
The following attestation bundles were made for spirisynq-0.1.0-py3-none-any.whl:
Publisher:
publish.yml on spiri-robotics/SpiriSynq
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
spirisynq-0.1.0-py3-none-any.whl -
Subject digest:
aaaa8f20ed873f5f022063d10dbbb71c932643722d18c1c4fb09f2df09fa6358 - Sigstore transparency entry: 1853468606
- Sigstore integration time:
-
Permalink:
spiri-robotics/SpiriSynq@b6c6e4fc1af587c652cc04f0335c884b0576d41d -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/spiri-robotics
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@b6c6e4fc1af587c652cc04f0335c884b0576d41d -
Trigger Event:
push
-
Statement type: