Skip to main content

szpont

Typed Python bindings for SzpontNet, the leaderless LAN protocol for self-discovery, resource advertisement and work hand-off.

SzpontNet's reference node is the szpontnet package, and its public surface is the wire format: JSON snapshots, string-keyed dictionaries, lastSeenSecsAgo, and one exception class for every way a control session can fail. That is the right shape for a protocol and an awkward one to program against.

szpont is that surface bound to Python types. It adds nothing to the protocol and reimplements none of it - every call here is the corresponding szpontnet call with its answer parsed and its failure classified.

import szpont

mesh = szpont.Mesh()

for peer in mesh.status().peers:
    print(peer.name, peer.link, peer.quota.surplus, peer.trust)

result = mesh.dispatch("review", prompt, work_key="review:owner/repo#41")
if result.suppressed:
    print("another machine already has this one")

What it gives you over the dictionaries

Types. Snapshot, Node, Peer, Assignment, Dispatch, Slot, Claim, Quota, Device, Tor - with the questions you actually ask as properties: peer.up, peer.personal, assignment.satisfied, result.ok, slot.suppressed.

Parsing never raises. A snapshot can be truncated mid-write, written by a newer protocol version, or hand-edited by someone hostile; the library's own contract is that such a file degrades to "no node" rather than crashing whoever renders it, and these types inherit that. Every object also keeps the dict it was read from as .raw, because the protocol grows by adding fields - onion, stats and sig all arrived that way - and bindings that exposed only what they knew about would hide the next one.

Failures you can branch on. The library raises one CtlError for every control-session failure and puts the difference in the message. This package splits it along the line that decides what a caller should do:

meaning what to do
NodeUnavailable there was no node to talk to, so nothing was attempted start one, or retry
CommandRejected a node was there and the command did not take effect retrying sends the same thing

The split is structural, not textual - it turns on whether a live node with a usable control port was there, and on whether the library chained a socket error - so it does not quietly go wrong the day a message is reworded. Both remain szpontnet.ctl.CtlError, so code already written against the library keeps working.

Hosting without a subclass. A node asks its host the five things it cannot answer alone. The library's way to answer is to subclass szpontnet.host.Host; most hosts answer one or two of them, and a class for that is ceremony:

szpont.register_host(
    duties=["render"],
    run_job=lambda prompt, done_path: my_queue.submit(prompt, done_path),
)

Anything you leave out keeps the library's default, which is a real answer rather than a placeholder: no runner means this machine declines work and the dispatcher fails over to the next candidate.

This registers in-process. A node your application spawns is a separate process and cannot see it - point that one at a module with SZPONTNET_HOST.

Reading is two calls, on purpose

mesh.snapshot()   # state.json: a file read, no socket, no node needed
mesh.status()     # the node itself: fresher, needs a live node

They cost different things. snapshot() is what a UI polls every couple of seconds; it can lag the node slightly and it survives the node's death, so check mesh.running before treating what it says as current. status() is what you call before acting on what you read.

Install

pip install szpont          # the bindings and the node
pip install 'szpont[trust]' # ... with Ed25519 device identity

Without the trust extra a node still runs, keyless: it advertises no public key, can never be verified, and so is foreign to any peer with a trust allowlist.

The command of the same name

The distribution also installs szpont, which fetches, builds and starts Diplomat - the applet this protocol was written for. szpont --plan prints what it would do without doing any of it.

pip install szpont && szpont      # the same thing `npx szpont` does

It is szpont_launcher.py, a top-level module rather than part of this package, and it imports nothing outside the standard library: starting an applet has no use for the protocol library, and import szpont has no use for a launcher. Its twin is packages/szpont-npm, which publishes the same command to npm; the two are held to the same plan by a parity test.

What it does not do

Wrap what already has a good shape. The node itself, its CLI (python -m szpontnet), the placement function and the protocol codec are all reached through szpontnet directly and are not duplicated here.

Its own tests

pip install -e ./packages/szpontnet-core -e ./packages/szpont pytest
pytest packages/szpont/tests -q

The suite refuses to open a socket. That is not tidiness: a test's state directory is isolated but the port inside a snapshot is not, and a fixture naming the protocol's default 40878 is naming exactly the port a developer's own node is listening on. A test that reached the transport would drive that live node - and pass while doing it - so the transport is removed and reaching it is the failure.

Note on the name

szpont names three things, and they share the namespace rather than compete for it: this import package (import szpont), the launcher installed as the szpont command, and the conformance tester, run as python -m szpont from its own directory.

Only the last is precarious. The tester is never installed, and the working directory precedes site-packages on sys.path, so it wins from where it is run - but publishing it under this name is what the three could not share. The console script cannot collide with either: an entry point is a file in bin/, not a name on the import path.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

szpont-0.2.0.tar.gz (38.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

szpont-0.2.0-py3-none-any.whl (25.4 kB view details)

Uploaded Python 3

File details

Details for the file szpont-0.2.0.tar.gz.

File metadata

  • Download URL: szpont-0.2.0.tar.gz
  • Upload date:
  • Size: 38.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.14.6

File hashes

Hashes for szpont-0.2.0.tar.gz
Algorithm Hash digest
SHA256 b576493b0c6a9ca16456bf682ecd985e012e4f18c347d6b67ff1f802ba4ca940
MD5 229cbeca0d53c5d0c5ad665decbcdbd4
BLAKE2b-256 738b4fe22b131612fc4f7f5b222b8e49e855ca8d23a5d6b4aa78762aa61689d8

See more details on using hashes here.

File details

Details for the file szpont-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: szpont-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 25.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.14.6

File hashes

Hashes for szpont-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 906d96d7a98f74e1472ed5ebb01b0e9eed68bf90fc2e225f9cf53a71c76535c0
MD5 40699248bf3113df3e60ae7193e7d198
BLAKE2b-256 bc2b54365883ba1cf0ccdeee259904f0be6ade3742e49e6936d889f9e1e14d49

See more details on using hashes here.

Release history Release notifications | RSS feed

0.74.0

2 files

0.73.0

2 files

0.72.0

2 files

0.71.0

2 files

0.70.0

2 files

0.69.0

2 files

0.68.0

2 files

0.67.0

2 files

0.66.0

2 files

0.65.0

2 files

0.64.0

2 files

0.63.0

2 files

0.62.0

2 files

0.61.0

2 files

0.60.0

2 files

0.59.0

2 files

0.58.0

2 files

0.57.0

2 files

0.56.0

2 files

0.55.0

2 files

0.54.0

2 files

0.53.0

2 files

0.52.0

2 files

0.51.0

2 files

0.50.0

2 files

0.49.0

2 files

0.48.0

2 files

0.47.0

2 files

0.46.0

2 files

0.45.0

2 files

0.44.0

2 files

0.43.0

2 files

0.42.0

2 files

0.41.0

2 files

0.40.0

2 files

0.39.0

2 files

0.38.0

2 files

0.37.0

2 files

0.36.0

2 files

0.35.0

2 files

0.34.0

2 files

0.33.0

2 files

0.32.0

2 files

0.31.0

2 files

0.30.0

2 files

0.29.0

2 files

0.28.0

2 files

0.27.0

2 files

0.26.0

2 files

0.25.0

2 files

0.24.0

2 files

0.23.0

2 files

0.22.0

2 files

0.21.0

2 files

0.20.0

2 files

0.19.0

2 files

0.18.0

2 files

0.17.0

2 files

0.16.0

2 files

0.15.0

2 files

0.14.0

2 files

0.13.0

2 files

0.12.0

2 files

0.11.0

2 files

0.10.0

2 files

0.9.0

2 files

0.8.0

2 files

0.7.0

2 files

0.6.0

2 files

0.5.0

2 files

0.4.0

2 files

0.3.0

2 files

This release

0.2.0 This release

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page