Skip to main content

High-performance, schema-agnostic event bus for AI runtime workloads

Project description

Net Python

High-performance, schema-agnostic event bus for AI runtime workloads.

Installation

pip install net-mesh

The package publishes as net-mesh on PyPI but imports as from net import ... (the in-source module name is preserved). For the higher-level Pythonic surface (generators, typed channels, dataclass/Pydantic support), install net-mesh-sdk instead — it depends on this package.

Cargo features

The PyO3 binding wraps a feature-gated Rust crate. Wheels published to PyPI ship with every feature enabled, but anyone building from source with maturin develop / maturin build needs to ask for the features they want — symbols from a disabled feature are silently absent from net._net and the matching from net import ... block in net/__init__.py quietly skips them.

Cargo feature Surface (Python classes) Notes
cortex Redex, RedexFile, RedexEvent, TasksAdapter, MemoriesAdapter, Task, Memory, NetDb, CortexError, RedexError, NetDbError Required by meshos and dataforts.
meshdb MeshQuery, MeshQueryRunner, QueryBuilder, Predicate, ResultRow, AggregateResult, JoinedRow, LineageEntry, CachePolicy, ExecuteOptions, GroupKey, WindowBoundary, InMemoryChainReader, MeshDbError Independent.
meshos MeshOsDaemonSdk, MeshOsDaemonHandle, MeshOsSdkError Pulls in compute + cortex.
dataforts BlobRef, BlobError, MeshBlobAdapter, blob_publish, blob_resolve, adapter registry Pulls in cortex + net.
compute DaemonRuntime, DaemonHandle, CausalEvent, DaemonError, MigrationHandle, MigrationError Required by meshos and groups.
groups ReplicaGroup, ForkGroup, StandbyGroup, GroupError Pulls in compute.
deck DeckClient, OperatorIdentity, AdminCommands, SnapshotStream, StatusSummaryStream, IceCommands, OperatorRegistry, AdminVerifier, DeckSdkError Pulls in meshos.
net NetMesh, NetStream, NetKeypair, Identity, token / channel-auth helpers Encrypted mesh transport + per-peer streams.
redis RedisStreamDedup Redis Streams adapter dedup helper.
jetstream (no Python surface yet) NATS JetStream adapter — Rust-only.

All are enabled by default in Cargo.toml. Disable with maturin develop --no-default-features --features "<list>" if you need a thinner wheel.

The net.__init__ module try-imports each family conditionally, so a wheel built without (say) meshos won't surface MeshOsDaemonSdk and the corresponding from net import MeshOsDaemonSdk raises ImportError cleanly.

Quick Start

from net import Net

# Create event bus (defaults to CPU core count shards)
bus = Net()

# Ingest events - fast path with raw JSON strings (23M+ ops/sec)
bus.ingest_raw('{"token": "hello", "index": 0}')

# Or use dict for convenience (4M+ ops/sec)
bus.ingest({"token": "world", "index": 1})

# Batch ingestion for maximum throughput
events = [f'{{"token": "tok_{i}"}}' for i in range(10000)]
count = bus.ingest_raw_batch(events)

# Poll events
response = bus.poll(limit=100)
for event in response:
    print(event.raw)
    # Or parse to dict
    data = event.parse()

# Check stats
stats = bus.stats()
print(f"Ingested: {stats.events_ingested}, Dropped: {stats.events_dropped}")

# Shutdown
bus.shutdown()

Context Manager

with Net(num_shards=4) as bus:
    bus.ingest_raw('{"data": "value"}')
# Automatically shuts down

Configuration

bus = Net(
    num_shards=8,                    # Number of parallel shards
    ring_buffer_capacity=1_048_576,  # Events per shard (must be power of 2)
    backpressure_mode="drop_oldest", # What to do when full
)

Net Encrypted UDP Transport

Net provides encrypted point-to-point UDP transport for high-performance scenarios:

from net import Net, generate_net_keypair
import os

# Generate keypair for responder
keypair = generate_net_keypair()
psk = os.urandom(32).hex()

# Responder side
responder = Net(
    num_shards=2,
    net_bind_addr='127.0.0.1:9001',
    net_peer_addr='127.0.0.1:9000',
    net_psk=psk,
    net_role='responder',
    net_secret_key=keypair.secret_key,
    net_public_key=keypair.public_key,
    net_reliability='light',  # 'none', 'light', or 'full'
)

# Initiator side (knows responder's public key)
initiator = Net(
    num_shards=2,
    net_bind_addr='127.0.0.1:9000',
    net_peer_addr='127.0.0.1:9001',
    net_psk=psk,
    net_role='initiator',
    net_peer_public_key=keypair.public_key,
)

# Use as normal
initiator.ingest_raw('{"event": "data"}')

Backpressure Modes

  • "drop_newest" - Reject new events when buffer is full
  • "drop_oldest" - Evict oldest events to make room
  • "fail_producer" - Raise an error

NAT traversal (optimization, not correctness)

Two NATed peers already reach each other through the mesh's routed-handshake path. NAT traversal opens a shorter direct path when the NAT shape allows it; it's never required for connectivity. Every method below is safe to call regardless of NAT type — a failed punch or a traversal: * RuntimeError is not a connectivity failure, traffic keeps riding the relay. The whole surface is a no-op when the native module was built without --features nat-traversal: every call raises RuntimeError("traversal: unsupported").

from net import NetMesh

mesh = NetMesh(bind_addr="0.0.0.0:9000", psk="00" * 32)

mesh.reclassify_nat()

klass  = mesh.nat_type()            # "open" | "cone" | "symmetric" | "unknown"
reflex = mesh.reflex_addr()         # "203.0.113.5:9001" or None

observed = mesh.probe_reflex(peer_node_id)   # "ip:port"

# Attempt a direct connection via the pair-type matrix.
# `coordinator` mediates the punch when the matrix picks one.
# Always returns — inspect stats to learn which path won.
mesh.connect_direct(peer_node_id, peer_pubkey_hex, coordinator_node_id)

# Cumulative counters — all int, monotonic.
s = mesh.traversal_stats()
s.punches_attempted   # coordinator mediated a PunchRequest + Introduce
s.punches_succeeded   # ack arrived AND direct handshake landed
s.relay_fallbacks     # landed on the routed path after skip/fail

Operators with a known-public address skip the classifier sweep entirely. The override pins "open" + the supplied address on every capability announcement; call announce_capabilities() after to propagate (the setter resets the rate-limit floor so the next announce is guaranteed to broadcast).

mesh.set_reflex_override('203.0.113.5:9001')
mesh.announce_capabilities(caps)
# later:
mesh.clear_reflex_override()
mesh.announce_capabilities(caps)

Traversal failures surface as RuntimeError with a stable traversal: <kind>[: <detail>] message prefix. The <kind> discriminator is one of reflex-timeout | peer-not-reachable | transport | rendezvous-no-relay | rendezvous-rejected | punch-failed | port-map-unavailable | unsupported. Match on the prefix for machine-readable branching:

try:
    mesh.connect_direct(peer_node_id, peer_pubkey_hex, coord_id)
except RuntimeError as e:
    msg = str(e)
    if msg.startswith("traversal: unsupported"):
        ...   # native module built without --features nat-traversal
    elif msg.startswith("traversal: peer-not-reachable"):
        ...

"unsupported" is the signal that the bindings are linked unconditionally and the native module doesn't have the feature — callers can branch cleanly without probing for symbol presence.

Channels (distributed pub/sub)

Named pub/sub over the encrypted mesh. Publishers register channels with access policy; subscribers ask to join via a membership subprotocol; publish fans payloads out to every current subscriber.

from net import NetMesh, ChannelAuthError, ChannelError

pub = NetMesh('127.0.0.1:9001', '42' * 32)
try:
    pub.register_channel(
        'sensors/temp',
        visibility='global',      # or 'subnet-local' | 'parent-visible' | 'exported'
        reliable=True,
        priority=2,
        max_rate_pps=1000,
    )

    # Subscriber side (after handshake with pub):
    # sub.subscribe_channel(pub.node_id, 'sensors/temp')

    # Fan a payload out to all subscribers.
    report = pub.publish(
        'sensors/temp',
        b'{"celsius": 22.5}',
        reliability='reliable',
        on_failure='best_effort',
        max_inflight=32,
    )
    print(f"{report['delivered']}/{report['attempted']} subscribers received")
finally:
    pub.shutdown()

# Typed errors for ACL outcomes:
# try: sub.subscribe_channel(peer_id, 'restricted')
# except ChannelAuthError: ...   # publisher denied
# except ChannelError: ...       # unknown channel / other rejection

Channel names always cross the binding as strings (not the u16 hash) to avoid ACL bypass via collision. The Python binding does not yet expose a dedicated per-channel receive API; that is a follow-up.

CortEX & NetDb (event-sourced state)

Typed, event-sourced state on top of RedEX — tasks and memories with filterable queries and sync watch iterators. Includes the snapshot_and_watch primitive whose race fix landed on v2, so you can safely "paint what's there now, then react to changes" without losing updates that race during construction.

from net import NetDb, CortexError

db = NetDb.open(origin_hash=0xABCDEF01, with_tasks=True, with_memories=True)
tasks = db.tasks

try:
    seq = tasks.create(1, 'write docs', 100)
    tasks.wait_for_seq(seq)   # block until the fold has applied
except CortexError as e:
    # adapter-level failure (RedEX I/O, fold halted, etc.)
    ...

# Snapshot + watch, one atomic call — no race.
snap, it = tasks.snapshot_and_watch_tasks(status='pending')
print('initial:', len(snap), 'pending tasks')
for batch in it:
    print('update:', len(batch), 'pending tasks')
    if len(batch) == 0:
        it.close()    # idempotent; ends the iterator
        break

db.close()

Standalone adapters

If you only need one model, skip the NetDb facade:

from net import Redex, TasksAdapter

redex = Redex(persistent_dir='/var/lib/net/redex')
tasks = TasksAdapter.open(redex, origin_hash=0xABCDEF01, persistent=True)

MemoriesAdapter exposes the same shape with store / retag / pin / unpin / delete / list_memories / watch_memories / snapshot_and_watch_memories.

Raw RedEX file (no CortEX fold)

For domain-agnostic persistent logs — your own event schema, no fold, no typed adapter — open a RedexFile directly from a Redex. The tail is a sync Python iterator; call close() or let StopIteration fire when the file closes.

from net import Redex, RedexError

redex = Redex(persistent_dir='/var/lib/net/events')
file = redex.open_file(
    'analytics/clicks',
    persistent=True,
    fsync_interval_ms=100,           # or fsync_every_n=1000
    retention_max_events=1_000_000,
)

# Append (or batch-append).
seq = file.append(b'{"url": "/home"}')
# `append_batch` returns the first-seq int of the batch, or `None`
# for an empty input. The `None` return is the explicit "I
# appended nothing" signal — pre-`bugfixes-8` it returned `0`,
# which collided with the legitimate "first event of a non-empty
# batch landed at seq 0" return.
first = file.append_batch([b'{"a": 1}', b'{"a": 2}'])

# Tail — backfills the retained range, then streams live appends.
try:
    for event in file.tail(from_seq=0):
        print(event.seq, bytes(event.payload))
        if should_stop:
            break           # idempotent; ends the iterator via close()
except RedexError as e:
    ...

file.close()

Errors from the RedEX surface raise RedexError (invalid channel name, bad config, append / tail / sync / close failures).

Cross-node RedEX replication

RedEX channels can replicate across the mesh. Opt in per channel by passing replication=True plus tunables on the open_file call. The default (no replication kwarg) keeps the channel single-node and adds zero wire traffic. Replicated channels carry N copies of the log; the leader is the single writer, replicas catch up via pull-based sync. Failover uses a deterministic nearest-RTT election with NodeId tie-break.

from net import NetMesh, Redex

mesh = NetMesh(bind_addr='127.0.0.1:0', psk='...')
redex = Redex(persistent_dir='/var/lib/net/events')

# Install the per-Redex replication router on the mesh.
# Idempotent — safe to call from multiple paths.
redex.enable_replication(mesh)

file = redex.open_file(
    'orders/audit',
    persistent=True,
    replication=True,
    replication_factor=3,                 # 1..16; default 3
    replication_heartbeat_ms=500,         # min 100; default 500
    replication_placement='standard',     # 'standard' | 'pinned' | 'colocation_strict'
    # replication_pinned_nodes=[node_a, node_b, node_c],   # required when placement='pinned'
    # replication_leader_pinned=some_node_id,
    replication_on_under_capacity='withdraw',   # 'withdraw' (default) | 'evict_oldest'
    replication_budget_fraction=0.5,
)
file.append(b'event payload')

The leader handles every append locally; replicas observe the leader's heartbeat tail_seq, issue SYNC_REQUEST on lag, apply chunks via SYNC_RESPONSE. When the leader closes (or the replica's believed leader goes silent past 3 × replication_heartbeat_ms), the surviving replicas run the deterministic election and one becomes the new leader within microseconds.

Operator surface on Redex:

  • enable_replication(mesh) — install replication wiring. Required before open_file(..., replication=True).
  • replication_runtime_count() -> int — registered per-channel runtimes.
  • replication_prometheus_text() -> str — Prometheus-text render of the seven per-channel metric shapes (*_lag_seconds, *_sync_bytes_total, *_leader_changes_total, *_under_capacity_total, *_skip_ahead_total, *_election_thrash_total, *_witness_withdrawals_total). Returns the empty string when replication isn't enabled; pipe straight into an HTTP scrape body without branching.
# HTTP scrape handler (Flask example)
@app.route('/metrics')
def metrics():
    return redex.replication_prometheus_text(), 200, {'Content-Type': 'text/plain'}

Disk-pressure handling: when a replica's local file rejects an append (heap-segment cap or disk write-fail), the configured replication_on_under_capacity policy fires — 'withdraw' drops the replica role (capability tag withdrawn; peers re-route to a healthy holder); 'evict_oldest' runs retention sweep + retries (requires retention_max_* kwargs to be set on the same call).

Validation surfaces RedexError before the call reaches the underlying coordinator, so misconfigured replication_factor (out of [1, 16]), replication_placement='pinned' without replication_pinned_nodes, or unknown enum strings fail fast.

Why snapshot_and_watch_*?

Calling list_tasks() then watch_tasks() takes two independent state reads. A mutation landing between them would be silently lost under the old skip(1) implementation. The atomic primitive returns the snapshot and an iterator seeded so that any divergent initial emission is forwarded through instead of dropped — see docs/STORAGE_AND_CORTEX.md.

Dataforts (greedy cache, gravity, blob refs, read-your-writes)

Dataforts is the compositional data plane on top of RedEX / CortEX / capability-index / proximity-graph. The PyO3 module surfaces it as Redex methods, top-level blob helpers, and a WriteToken + wait_for_token pair on Tasks / Memories. Built behind the dataforts Cargo feature; pre-built wheels on PyPI ship with the feature enabled. A build without it raises RedexError from enable_greedy_dataforts(...) with "requires the 'dataforts' feature; rebuild with --features dataforts" rather than failing silently.

Four phases:

  • Phase 1 — Greedy-LRU caching. Five-axis admission (scope + proximity + capability-preference + colocation + storage-cap)
    • bandwidth budget gate per-channel cache files. Cold channels evict under cluster-cap pressure and withdraw their causal:<hex> advertisement.
  • Phase 3 — BlobRef + blob adapters. A 4-byte-magic + version + 32-byte BLAKE3 + size + URI reference whose bytes live in the caller's storage (S3 / Ceph / IPFS / local FS). Adapters implement fetch / store (sync or async def); the filesystem adapter ships in-tree via register_filesystem_blob_adapter. Custom adapters register through register_blob_adapter(adapter_id, instance). Async adapters run on a binding-owned event loop on a dedicated thread — adapter coroutines never share the calling thread's event loop, so an aiobotocore / httpx.AsyncClient / SQLAlchemy async engine inside the adapter is safe.
  • Phase 4 — Data gravity. Per-chain read-rate counters with exponential decay. Threshold-crossing emissions stamp heat:<hex>=<rate> onto the chain's capability announcement; greedy weights cache pulls by heat × scope-match × proximity.
  • Phase 5 — Read-your-writes. Every tasks.create, memories.insert, etc. returns a WriteToken { origin_hash, seq } (frozen, hashable; constructor is #[pyo3(doc_hidden)] — tokens are unforgeable only against the issuing adapter via origin binding). tasks.wait_for_token(token, deadline_ms=…) blocks until the local fold has applied that seq; tracks both applied_through_seq and folded_through_seq so a stalled fold raises CortexError. deadline_ms=0 is a non-blocking poll (no scheduling).
from net import (
    NetMesh, Redex, Tasks,
    register_filesystem_blob_adapter, blob_publish, blob_resolve,
)

mesh = NetMesh(bind_addr='0.0.0.0:7000', psk='...')
redex = Redex(persistent_dir='/var/lib/net/redex')

# Phase 1 — wire greedy into the mesh inbound dispatch.
redex.enable_greedy_dataforts(
    mesh,
    scopes=['region:us'],
    total_cap_bytes=1 << 30,         # 1 GiB cluster-cap
    per_channel_cap_bytes=64 << 20,
)

# Phase 4 — layer gravity on top.
redex.enable_gravity_for_greedy(
    mesh,
    emit_threshold_ratio=1.5,
    decay_half_life_secs=300,
)

# Phase 3 — filesystem adapter (ships in-tree).
register_filesystem_blob_adapter('local', '/var/blobs')
ref = blob_publish('local', 'local://obj/payload', some_bytes)
back = blob_resolve(ref)

# Phase 5 — read-your-writes.
tasks = Tasks.open(redex, origin_hash=mesh.origin_hash)
result = tasks.create(1, 'first', 100)
tasks.wait_for_token(result.token, deadline_ms=250)
# tasks.wait_for_token(token, deadline_ms=0) → non-blocking poll

# Diagnostics.
print(redex.greedy_cached_channel_count())
print(redex.greedy_prometheus_text())

The canonical channel hash is 64-bit (channel_hash(name) returns int in the u64 range). The per-packet wire NetHeader channel_hash stays u16 — fast-path filter hint, may bucket-collide at scale; ACL / config / cache / RYW decisions key on the canonical 64-bit hash via registry disambiguation. The PermissionToken wire form is 169 bytes (PermissionToken::WIRE_SIZE in the Rust core).

Redis Streams consumer-side dedup helper

The Net Redis adapter writes a stable dedup_id field on every XADD entry: {producer_nonce:hex}:{shard_id}:{sequence_start}:{i}. Combined with the bus's persistent producer-nonce path (producer_nonce_path on EventBusConfig), the id is stable across both within-process retries AND cross-process restart — the MULTI/EXEC-timeout race becomes filterable at consume time.

RedisStreamDedup is the consumer-side helper, exposed on the net PyO3 module:

from net import RedisStreamDedup
import redis

# ~10k events/sec * 1 min dedup window → ~600,000.
dedup = RedisStreamDedup(capacity=600_000)

r = redis.Redis(host="localhost", port=6379)
cursor = "0"
while True:
    # XRANGE bounds are INCLUSIVE on both ends. After the first
    # page we must use the exclusive form `(<id>` so we don't
    # re-read the entry the cursor points at — a vanilla
    # `min=cursor` loop spins forever once the cursor reaches the
    # tail and the same entry is returned every iteration.
    start = cursor if cursor == "0" else f"({cursor}"
    entries = r.xrange("net:shard:0", min=start, max="+", count=100)
    for entry_id, fields in entries:
        dedup_id = fields.get(b"dedup_id", b"").decode()
        if not dedup_id:
            # No dedup_id → older entry or non-Net producer; skip
            # dedup and process as-is.
            process(entry_id, fields)
            continue
        if not dedup.is_duplicate(dedup_id):
            process(entry_id, fields)
        cursor = entry_id.decode()
    if not entries:
        break

Surface:

dedup = RedisStreamDedup()                # default capacity 4096
dedup = RedisStreamDedup(capacity=N)      # explicit; 0 → 1
dedup.is_duplicate(id: str) -> bool       # test-and-insert
dedup.len                                 # property — tracked-id count
dedup.capacity                            # property — configured cap
dedup.is_empty                            # property
dedup.clear()                             # reset (e.g. on consumer-group rebalance)

The helper is transport-agnostic — bring your own redis-py / aioredis / equivalent client; it just answers the dedup question against an in-memory LRU. Concurrency: each handle wraps a Rust Mutex<RedisStreamDedup>, so concurrent calls from multiple Python threads are safe but serialize. Production-shape is one helper per consumer thread.

Security Surface (Stage A–E)

The mesh layer surfaces the same identity / capabilities / subnets / channel-auth story that the Rust SDK and the TypeScript / Node SDKs ship. Full staging and rationale: docs/SDK_SECURITY_SURFACE_PLAN.md. Python-binding parity details: docs/SDK_PYTHON_PARITY_PLAN.md.

Identity + permission tokens

Every node has an ed25519 identity; permission tokens are ed25519- signed delegations that authorize a subject to publish / subscribe / delegate / admin on a channel, optionally with further delegation depth.

from net import Identity, parse_token, verify_token, delegate_token

alice = Identity.generate()
bob = Identity.generate()

# Alice issues Bob a subscribe+delegate token good for 5 min, with
# one re-delegation hop remaining. `ttl_seconds=0` raises
# `TokenError` — a zero TTL would mint a born-expired token that
# every receiver would reject as `Expired`, leaving the issuer to
# diagnose the misuse from receiver-side log lines.
token = alice.issue_token(
    subject=bob.entity_id,
    scope=["subscribe", "delegate"],
    channel="sensors/temp",
    ttl_seconds=300,
    delegation_depth=1,
)
assert verify_token(token) is True

# Bob re-delegates to Carol; depth drops to 0 (leaf).
carol = Identity.generate()
child = delegate_token(bob, token, carol.entity_id, ["subscribe"])
assert parse_token(child)["delegation_depth"] == 0

Capability announcements + peer discovery

Announce hardware / software / model / tool / tag fingerprints, then query the local capability index with a filter.

mesh.announce_capabilities({
    "hardware": {
        "cpu_cores": 16,
        "memory_gb": 64,
        "gpu": {"vendor": "nvidia", "model": "h100", "vram_gb": 80},
    },
    "models": [{"model_id": "llama-3.1-70b", "family": "llama",
                "context_length": 128_000}],
    "tags": ["gpu", "prod"],
})

gpu_peers = mesh.find_nodes({
    "require_gpu": True,
    "gpu_vendor": "nvidia",
    "min_vram_gb": 40,
})

Scoped discovery (reserved scope:* tags)

A provider can narrow who its query result reaches by tagging its CapabilitySet with reserved scope:* tags. Queries call mesh.find_nodes_scoped(filter, scope) to filter candidates. The wire format and forwarders are untouched — enforcement is purely query-side.

# GPU pool advertised to one tenant only.
mesh.announce_capabilities({
    "tags": ["model:llama3-70b", "scope:tenant:oem-123"],
})

# Tenant-scoped query — returns this node + any Global (untagged) peers.
oem_nodes = mesh.find_nodes_scoped(
    {"require_tags": ["model:llama3-70b"]},
    {"kind": "tenant", "tenant": "oem-123"},
)

Accepted scope dict shapes: {"kind": "any"} (default), {"kind": "global_only"}, {"kind": "same_subnet"}, {"kind": "tenant", "tenant": "<id>"}, {"kind": "tenants", "tenants": [...]}, {"kind": "region", "region": "<name>"}, {"kind": "regions", "regions": [...]}. Reserved announcement tags: scope:subnet-local (visible only under same_subnet), scope:tenant:<id>, scope:region:<name> — strictest scope wins. Untagged peers resolve to Global and stay visible under permissive queries. Full design: docs/SCOPED_CAPABILITIES_PLAN.md.

Capability propagation is multi-hop, bounded by MAX_CAPABILITY_HOPS = 16 with (origin, version) dedup on every forwarder. capability_gc_interval_ms controls both the index TTL sweep and the dedup cache eviction. See docs/MULTIHOP_CAPABILITY_PLAN.md.

Subnets

Nodes can bind to a hierarchical SubnetId (1–4 levels, each 0–255) directly, or derive one from announced tags via a SubnetPolicy.

# Explicit subnet.
mesh = NetMesh("127.0.0.1:9000", PSK, subnet=[3, 7, 2])

# Or derive from tags.
mesh = NetMesh(
    "127.0.0.1:9001", PSK,
    subnet_policy={
        "rules": [
            {"tag_prefix": "region:", "level": 0,
             "values": {"eu": 1, "us": 2, "apac": 3}},
            {"tag_prefix": "zone:", "level": 1,
             "values": {"a": 1, "b": 2, "c": 3}},
        ]
    },
)

Channel authentication

Publishers set publish_caps / subscribe_caps / require_token on register_channel. Subscribers present a PermissionToken via the optional token=bytes kwarg on subscribe_channel.

mesh.register_channel(
    "gpu/jobs",
    subscribe_caps={"require_gpu": True, "min_vram_gb": 16},
    require_token=True,
)

# Subscriber side, with a token issued by the publisher:
mesh.subscribe_channel(publisher_node_id, "gpu/jobs", token=token_bytes)

Denied subscribes raise ChannelAuthError (a subclass of ChannelError); malformed tokens raise TokenError whose message has the form "token: <kind>" (invalid_signature, expired, delegation_exhausted, …). Successful subscribes populate an AuthGuard bloom filter on the publisher so every subsequent publish admits the subscriber in constant time. An expiry sweep (default 30 s) evicts subscribers whose tokens age out; a per- peer auth-failure rate limiter throttles bad-token storms. Cross- SDK behaviour is fixed by the Rust integration suite; see tests/channel_auth.rs and tests/channel_auth_hardening.rs.

nRPC (request / response over the mesh)

nRPC is the request/response convention layer riding on top of the pub/sub mesh + CortEX folds. Built with the cortex feature (maturin's default picks it up). The native module exposes two layers:

  • Raw bytesnet.MeshRpc (pyclass): serve(service, fn) -> ServeHandle, call(target, service, bytes) -> bytes, call_service(service, bytes) -> bytes, call_streaming(target, service, bytes) -> RpcStream, find_service_nodes(service) -> list[int]. Synchronous calls release the GIL across runtime.block_on(...) so other Python threads run; handler callbacks dispatch under tokio::task::spawn_blocking so GIL acquisition doesn't starve the runtime.
  • Typed wrappernet.mesh_rpc.TypedMeshRpc: JSON encode/decode at the binding boundary so user code works with plain Python objects (dicts, lists, strings, numbers, bools, None). The default codec is json.dumps / json.loads — to send dataclasses, Pydantic models, or numpy arrays, convert to a JSON-serializable shape before calling (e.g. dataclasses.asdict(x) or model.model_dump()); a non- serializable input raises RpcCodecError before the call hits the wire so the diagnostic points at the call site rather than the server. Resilience helpers (RetryPolicy, HedgePolicy, CircuitBreaker) plus the typed exception classes (RpcNoRouteError, RpcTimeoutError, RpcServerError, RpcTransportError, RpcCodecError, RpcAppError, BreakerOpenError) live here too.
from net import NetMesh
from net.mesh_rpc import (
    NRPC_TYPED_BAD_REQUEST,
    RetryPolicy,
    RpcServerError,
    TypedMeshRpc,
)

server = NetMesh("127.0.0.1:9001", "42" * 32)
client = NetMesh("127.0.0.1:9000", "42" * 32)
# (handshake omitted — see "Net Encrypted UDP Transport")

# Server side: register a typed handler. ServeHandle is a context
# manager — `with` ensures unregister on exit.
server_rpc = TypedMeshRpc.from_mesh(server)
def echo_sum(req: dict) -> dict:
    return {"echo": req["text"], "sum": sum(req["numbers"])}

with server_rpc.serve("echo_sum", echo_sum):
    client_rpc = TypedMeshRpc.from_mesh(client)
    reply = client_rpc.call(
        server.node_id(), "echo_sum",
        {"text": "hi", "numbers": [1, 2, 3]},
        opts={"deadline_ms": 200},
    )
    # reply == {"echo": "hi", "sum": 6}

# Streaming responses iterate decoded chunks until EOF or terminal error.
# `stream_window_initial` is the canonical key; `stream_window` is an
# alias accepted for ergonomic parity.
stream = client_rpc.call_streaming(
    target_node_id, "tail", {"tail": "events"},
    opts={"deadline_ms": 5000, "stream_window_initial": 8},
)
for chunk in stream:
    process(chunk)
# stream.close() emits CANCEL to the server (best-effort).
# stream.grant(n) issues an explicit credit publish for batched cadence.

# Resilience helpers: retry / hedge / circuit breaker.
policy = RetryPolicy(max_attempts=4, initial_backoff_ms=50, max_backoff_ms=1000)
client_rpc.call_with_retry(target_node_id, "echo", {"hi": 1}, policy)

Status codes + error model

Every caller-side failure is a typed exception whose message carries the canonical nrpc:<kind>: <detail> prefix. The set of kinds is fixed by the cross-binding contract: no_route, timeout, server_error, transport, codec_encode, codec_decode, breaker_open. The classify_error(e) helper in net.mesh_rpc extracts the kind string from a caught exception's message — useful for fallback paths where discriminating without isinstance is awkward (e.g. when the native module wasn't built and every typed alias collapses to plain Exception):

from net.mesh_rpc import classify_error

try:
    rpc.call(target, "echo", body, opts={"deadline_ms": 200})
except Exception as e:
    kind = classify_error(e)
    if kind == "no_route":
        ...      # capability index didn't surface a target
    elif kind == "timeout":
        ...      # caller-side deadline elapsed
    elif kind == "server_error":
        ...      # str(e) carries `status=0xNNNN message=...`
Constant Hex Meaning
NRPC_TYPED_BAD_REQUEST 0x8000 Typed handler couldn't decode the request body.
NRPC_TYPED_HANDLER_ERROR 0x8001 Typed handler ran but returned an exception.

Cross-binding contract spec — including the canonical cross_lang_echo_sum service used by every binding's wire-format compat test — lives in ../../README.md#nrpc. The Python binding's own compat suite is at tests/test_cross_lang_compat.py.

Compute (daemons + migration)

Run MeshDaemons directly from Python. DaemonRuntime owns the factory table, the per-daemon hosts, and the Registering → Ready → ShuttingDown lifecycle gate that decides when inbound migrations may land. Daemons are any Python object whose process(event) returns a list of bytes/bytearray payloads — the runtime wraps each output in a causal link and forwards it.

Build the native module with the compute feature (maturin picks it up on the default build) and import from net. Full design notes: docs/SDK_COMPUTE_SURFACE_PLAN.md.

from net import DaemonRuntime, NetMesh, Identity, CausalEvent


class EchoDaemon:
    """Stateless echo — ships every event's payload straight back."""

    name = "echo"

    def process(self, event: CausalEvent) -> list[bytes]:
        return [bytes(event.payload)]

    # Optional: snapshot() / restore(state) for migration-capable daemons.


mesh = NetMesh("127.0.0.1:9000", "42" * 32)
rt = DaemonRuntime(mesh)

# 1. Register factories BEFORE flipping the runtime to Ready.
rt.register_factory("echo", lambda: EchoDaemon())

# 2. Ready the runtime — after this point spawn / migration accept.
rt.start()

# 3. Spawn a daemon; Identity pins the ed25519 keypair so
#    origin_hash / entity_id stay stable across migrations.
identity = Identity.generate()
handle = rt.spawn("echo", identity)
print(f"origin = 0x{handle.origin_hash:08x}")

# 4. Manually feed an event for testing; real delivery happens
#    via the mesh's causal chain.
event = CausalEvent(handle.origin_hash, sequence=1, payload=b"hello")
outputs = rt.deliver(handle.origin_hash, event)

# 5. Clean shutdown.
rt.stop(handle.origin_hash)
rt.shutdown()

process must be synchronous — the core's contract is sync, and the PyO3 bridge re-attaches the GIL for the duration of each call. Raising inside process surfaces as DaemonError on the caller.

Migration

start_migration(origin_hash, source_node, target_node) orchestrates the six-phase cutover (Snapshot → Transfer → Restore → Replay → Cutover → Complete). The source seals the daemon's ed25519 seed into the outbound snapshot using the target's X25519 static pubkey; the target rebuilds the daemon via the factory registered under the same kind, replays any events that arrived during transfer, then activates.

from net import MigrationError, migration_error_kind

try:
    mig = rt.start_migration(handle.origin_hash, src_node_id, dst_node_id)
    # mig.phase  — "snapshot" | "transfer" | "restore" | ...
    # mig.source_node / mig.target_node
    mig.wait()                      # blocks to completion
except MigrationError as e:
    kind = migration_error_kind(e)
    if kind == "not-ready":               ...  # target start() didn't run
    elif kind == "factory-not-found":     ...  # target missing this kind
    elif kind == "compute-not-supported": ...  # target has no DaemonRuntime
    elif kind == "state-failed":          ...  # snapshot / restore threw
    elif kind == "identity-transport-failed": ...  # seal / unseal failed
    # ...see SDK_COMPUTE_SURFACE_PLAN.md for the full enum

start_migration_with(origin, src, dst, opts) exposes options such as seal_seed=False for test scenarios. On the target node, call rt.register_migration_target_identity(kind, identity) before any migration of that kind lands; without it the runtime rejects sealed-seed envelopes with migration_error_kind == "identity-transport-failed".

Surface at a glance

Method Description
DaemonRuntime(mesh) Construct against an existing NetMesh
rt.register_factory(kind, fn) Install a factory (before start())
rt.start() / rt.shutdown() Flip the lifecycle gate
rt.spawn(kind, identity, config=None) Spawn a local daemon
rt.spawn_from_snapshot(kind, identity, bytes, config=None) Rehydrate
rt.stop(origin) Stop a local daemon
rt.snapshot(origin) Capture bytes for persistence / migration
rt.deliver(origin, event) Feed an event (returns list[bytes])
rt.start_migration(origin, src, dst) Orchestrate a live migration
rt.register_migration_target_identity(kind, id) Pin unseal keypair on target for kind
handle.origin_hash / entity_id / stats() Per-daemon identity + stats
DaemonError / MigrationError Typed exceptions; migration_error_kind(e) parses e.kind

Compute Groups (Replica / Fork / Standby)

HA / scaling overlays on top of DaemonRuntime. Build the native module with the groups feature (implies compute) to expose ReplicaGroup, ForkGroup, StandbyGroup, and the GroupError exception class.

  • ReplicaGroup — N interchangeable copies of a daemon. Deterministic identity from group_seed + index, so a replacement respawned on another node has a stable origin_hash. Load-balances inbound events across healthy members; auto-replaces on node failure.
  • ForkGroup — N independent daemons forked from a common parent at fork_seq. Unique keypairs, shared ancestry via a verifiable ForkRecord.
  • StandbyGroup — active-passive replication. One member processes events; standbys hold snapshots and catch up via sync_standbys(). On active failure the most-synced standby promotes and replays the events buffered since the last sync.
from net import (
    DaemonRuntime, ForkGroup, GroupError, ReplicaGroup, StandbyGroup,
    group_error_kind,
)

rt = DaemonRuntime(mesh)
rt.register_factory("counter", lambda: CounterDaemon())

# --- ReplicaGroup ----------------------------------------------------
replicas = ReplicaGroup.spawn(
    rt, "counter",
    replica_count=3,
    group_seed=bytes([0x11] * 32),
    lb_strategy="consistent-hash",   # or "round-robin" / "least-load"
                                     #    / "least-connections" / "random"
)
origin = replicas.route_event({"routing_key": "user:42"})
rt.deliver(origin, event)
replicas.scale_to(5)                 # grow
replicas.on_node_failure(failed_node_id)   # respawn elsewhere

# --- ForkGroup -------------------------------------------------------
forks = ForkGroup.fork(
    rt, "counter",
    parent_origin=0xABCDEF01,
    fork_seq=42,
    fork_count=3,
    lb_strategy="round-robin",
)
assert forks.verify_lineage()
for record in forks.fork_records():
    print(record["forked_origin"], record["fork_seq"])

# --- StandbyGroup ----------------------------------------------------
hot = StandbyGroup.spawn(
    rt, "counter",
    member_count=3,                  # 1 active + 2 standbys
    group_seed=bytes([0x77] * 32),
)
rt.deliver(hot.active_origin, event)
hot.sync_standbys()                  # periodic catchup
# On active-node failure:
# new_origin = hot.on_node_failure(failed_node_id)  # auto-promotes

Typed errors

Failures raise GroupError (a subclass of DaemonError). Use group_error_kind(e) to parse the discriminator from the Rust side's daemon: group: <kind>[: detail] message prefix:

from net import GroupError, group_error_kind

try:
    ReplicaGroup.spawn(rt, "never-registered",
                       replica_count=2, group_seed=bytes(32))
except GroupError as e:
    kind = group_error_kind(e)
    if kind == "not-ready":               ...  # runtime.start() didn't run
    elif kind == "factory-not-found":     ...  # kind wasn't registered
    elif kind == "no-healthy-member":     ...  # routed on an all-down group
    elif kind == "invalid-config":        ...  # e.g. replica_count == 0
    elif kind in ("placement-failed",
                  "registry-failed",
                  "daemon"):              ...  # core failure — read e args

Full staging, wire formats, and rationale: docs/SDK_GROUPS_SURFACE_PLAN.md. Core semantics live in the main README.md#daemons.

Performance Tips

  1. Use ingest_raw() for maximum throughput - Pass pre-serialized JSON strings
  2. Use ingest_raw_batch() for bulk operations - Reduces per-call overhead
  3. Increase ring_buffer_capacity - Larger buffers handle bursts better
  4. Match num_shards to CPU cores - Default is optimal for most cases

Cargo features

The five feature flags that gate the storage / query / OS surfaces on this binding. Wheels built without a feature silently omit its symbols — the build never warns. bindings/python/python/net/__init__.py try-imports each block individually, so from net import Redex raises ImportError (not AttributeError) when the underlying _net extension was compiled without cortex.

Feature Surface enabled in the PyO3 module
cortex Redex, RedexFile, TasksAdapter, MemoriesAdapter, NetDb, Task, Memory, watch iterators, RedexError, CortexError, NetDbError
redex-disk Disk-backed persistence for RedEX — the persistent_dir ctor arg and Persistent: true on open_file. Without it the persistent path returns RedexError.
netdb NetDb composition over Tasks + Memories (requires cortex). The net_netdb_* FFI entry points ship with this feature.
meshdb MeshQuery, MeshQueryRunner, QueryBuilder, Predicate, InMemoryChainReader, the rest of the query layer, plus the libnet_meshdb cdylib.
meshos MeshOsDaemonSdk, MeshOsDaemonHandle, plus the libnet_meshos cdylib.

Enable at build time:

# Dev install into the active venv:
maturin develop --features "cortex netdb redex-disk meshdb meshos"

# Or produce a wheel:
maturin build --release --features "cortex netdb redex-disk meshdb meshos"

PyPI wheels published as net-mesh ship with every feature enabled; the flags above only matter for source builds.

License

Apache-2.0

Project details


Download files

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

Source Distribution

net_mesh-0.22.0.tar.gz (5.8 MB view details)

Uploaded Source

Built Distributions

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

net_mesh-0.22.0-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl (4.5 MB view details)

Uploaded PyPymanylinux: glibc 2.28+ x86-64

net_mesh-0.22.0-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl (4.3 MB view details)

Uploaded PyPymanylinux: glibc 2.28+ ARM64

net_mesh-0.22.0-cp315-cp315-manylinux_2_28_x86_64.whl (4.6 MB view details)

Uploaded CPython 3.15manylinux: glibc 2.28+ x86-64

net_mesh-0.22.0-cp314-cp314t-manylinux_2_28_aarch64.whl (4.3 MB view details)

Uploaded CPython 3.14tmanylinux: glibc 2.28+ ARM64

net_mesh-0.22.0-cp314-cp314-win_arm64.whl (3.8 MB view details)

Uploaded CPython 3.14Windows ARM64

net_mesh-0.22.0-cp314-cp314-win_amd64.whl (4.0 MB view details)

Uploaded CPython 3.14Windows x86-64

net_mesh-0.22.0-cp314-cp314-manylinux_2_28_x86_64.whl (4.6 MB view details)

Uploaded CPython 3.14manylinux: glibc 2.28+ x86-64

net_mesh-0.22.0-cp314-cp314-manylinux_2_28_aarch64.whl (4.3 MB view details)

Uploaded CPython 3.14manylinux: glibc 2.28+ ARM64

net_mesh-0.22.0-cp314-cp314-macosx_11_0_arm64.whl (4.0 MB view details)

Uploaded CPython 3.14macOS 11.0+ ARM64

net_mesh-0.22.0-cp314-cp314-macosx_10_12_x86_64.whl (4.4 MB view details)

Uploaded CPython 3.14macOS 10.12+ x86-64

net_mesh-0.22.0-cp313-cp313t-manylinux_2_28_aarch64.whl (4.3 MB view details)

Uploaded CPython 3.13tmanylinux: glibc 2.28+ ARM64

net_mesh-0.22.0-cp313-cp313-win_arm64.whl (3.8 MB view details)

Uploaded CPython 3.13Windows ARM64

net_mesh-0.22.0-cp313-cp313-win_amd64.whl (4.0 MB view details)

Uploaded CPython 3.13Windows x86-64

net_mesh-0.22.0-cp313-cp313-manylinux_2_28_x86_64.whl (4.6 MB view details)

Uploaded CPython 3.13manylinux: glibc 2.28+ x86-64

net_mesh-0.22.0-cp313-cp313-manylinux_2_28_aarch64.whl (4.3 MB view details)

Uploaded CPython 3.13manylinux: glibc 2.28+ ARM64

net_mesh-0.22.0-cp313-cp313-macosx_11_0_arm64.whl (4.0 MB view details)

Uploaded CPython 3.13macOS 11.0+ ARM64

net_mesh-0.22.0-cp313-cp313-macosx_10_12_x86_64.whl (4.4 MB view details)

Uploaded CPython 3.13macOS 10.12+ x86-64

net_mesh-0.22.0-cp312-cp312-win_arm64.whl (3.8 MB view details)

Uploaded CPython 3.12Windows ARM64

net_mesh-0.22.0-cp312-cp312-win_amd64.whl (4.0 MB view details)

Uploaded CPython 3.12Windows x86-64

net_mesh-0.22.0-cp312-cp312-manylinux_2_28_x86_64.whl (4.6 MB view details)

Uploaded CPython 3.12manylinux: glibc 2.28+ x86-64

net_mesh-0.22.0-cp312-cp312-manylinux_2_28_aarch64.whl (4.3 MB view details)

Uploaded CPython 3.12manylinux: glibc 2.28+ ARM64

net_mesh-0.22.0-cp312-cp312-macosx_11_0_arm64.whl (4.0 MB view details)

Uploaded CPython 3.12macOS 11.0+ ARM64

net_mesh-0.22.0-cp312-cp312-macosx_10_12_x86_64.whl (4.4 MB view details)

Uploaded CPython 3.12macOS 10.12+ x86-64

net_mesh-0.22.0-cp311-cp311-win_arm64.whl (3.8 MB view details)

Uploaded CPython 3.11Windows ARM64

net_mesh-0.22.0-cp311-cp311-win_amd64.whl (4.0 MB view details)

Uploaded CPython 3.11Windows x86-64

net_mesh-0.22.0-cp311-cp311-manylinux_2_28_x86_64.whl (4.5 MB view details)

Uploaded CPython 3.11manylinux: glibc 2.28+ x86-64

net_mesh-0.22.0-cp311-cp311-manylinux_2_28_aarch64.whl (4.3 MB view details)

Uploaded CPython 3.11manylinux: glibc 2.28+ ARM64

net_mesh-0.22.0-cp311-cp311-macosx_11_0_arm64.whl (4.0 MB view details)

Uploaded CPython 3.11macOS 11.0+ ARM64

net_mesh-0.22.0-cp311-cp311-macosx_10_12_x86_64.whl (4.4 MB view details)

Uploaded CPython 3.11macOS 10.12+ x86-64

net_mesh-0.22.0-cp310-cp310-win_amd64.whl (4.0 MB view details)

Uploaded CPython 3.10Windows x86-64

net_mesh-0.22.0-cp310-cp310-manylinux_2_28_x86_64.whl (4.5 MB view details)

Uploaded CPython 3.10manylinux: glibc 2.28+ x86-64

net_mesh-0.22.0-cp310-cp310-manylinux_2_28_aarch64.whl (4.3 MB view details)

Uploaded CPython 3.10manylinux: glibc 2.28+ ARM64

File details

Details for the file net_mesh-0.22.0.tar.gz.

File metadata

  • Download URL: net_mesh-0.22.0.tar.gz
  • Upload date:
  • Size: 5.8 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for net_mesh-0.22.0.tar.gz
Algorithm Hash digest
SHA256 a67f06b8df66562d693ddf8d89d0e07081e9e0b17b0b34d4b4d3f700d84b7bcf
MD5 b63be9f3b00749a6cafb7261fdd71903
BLAKE2b-256 18cd4662f1692a4cbc8b8ecc0fe38014409f9fc584695bfc1d53bee157f2580d

See more details on using hashes here.

Provenance

The following attestation bundles were made for net_mesh-0.22.0.tar.gz:

Publisher: release-python.yml on ai-2070/net

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file net_mesh-0.22.0-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for net_mesh-0.22.0-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 00493c9ea8bbe714bdbc03681759d3edd9a2fb94e883e105aff67fa7c95498df
MD5 39439922bee00ef685738317b7601712
BLAKE2b-256 4653708cfa41b49e5a868a65c81827e42733bc805d9d91040e16f261e9c378ed

See more details on using hashes here.

Provenance

The following attestation bundles were made for net_mesh-0.22.0-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl:

Publisher: release-python.yml on ai-2070/net

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file net_mesh-0.22.0-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl.

File metadata

File hashes

Hashes for net_mesh-0.22.0-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl
Algorithm Hash digest
SHA256 d849eab9efc9768e3a1af6dcc71a9c786a257c613c07fe798447d8ec7685087e
MD5 653ee7ec65d4822163cc07a2be401c56
BLAKE2b-256 7ecbbff3abc5924f12130f958b5bd778a6f58a36ec04f1de3d7366730062978c

See more details on using hashes here.

Provenance

The following attestation bundles were made for net_mesh-0.22.0-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl:

Publisher: release-python.yml on ai-2070/net

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file net_mesh-0.22.0-cp315-cp315-manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for net_mesh-0.22.0-cp315-cp315-manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 7e5971111826a8ef65e558238bf7290244be299580ceef0a8dfcc324b510354b
MD5 0968120bceede555e252cdddb34b66f6
BLAKE2b-256 ff4706338f30b606df7e6bfa4f40df5af40cdeafed2a58d92b0be7ad8df23baf

See more details on using hashes here.

Provenance

The following attestation bundles were made for net_mesh-0.22.0-cp315-cp315-manylinux_2_28_x86_64.whl:

Publisher: release-python.yml on ai-2070/net

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file net_mesh-0.22.0-cp314-cp314t-manylinux_2_28_aarch64.whl.

File metadata

File hashes

Hashes for net_mesh-0.22.0-cp314-cp314t-manylinux_2_28_aarch64.whl
Algorithm Hash digest
SHA256 a32f626985eddff5795f0709b6c590a09273ce086bb5d6f26f1c36bb3573c744
MD5 5a237a40cc3dc9f3ba4dcf915844e678
BLAKE2b-256 5817693043f2071441693467a460a5803b15cdd636d9b51ed057bc2c1d159a8b

See more details on using hashes here.

Provenance

The following attestation bundles were made for net_mesh-0.22.0-cp314-cp314t-manylinux_2_28_aarch64.whl:

Publisher: release-python.yml on ai-2070/net

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file net_mesh-0.22.0-cp314-cp314-win_arm64.whl.

File metadata

  • Download URL: net_mesh-0.22.0-cp314-cp314-win_arm64.whl
  • Upload date:
  • Size: 3.8 MB
  • Tags: CPython 3.14, Windows ARM64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for net_mesh-0.22.0-cp314-cp314-win_arm64.whl
Algorithm Hash digest
SHA256 3f87b65184453db8f49581bc1c2f9e0307609f27cf0910d5198a88bcf12eeb06
MD5 ca17bf55912150079f506d2d9d600d2d
BLAKE2b-256 342f384623be9cb172aa50498e307db352337a82687ef005f108bdc13f9df97a

See more details on using hashes here.

Provenance

The following attestation bundles were made for net_mesh-0.22.0-cp314-cp314-win_arm64.whl:

Publisher: release-python.yml on ai-2070/net

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file net_mesh-0.22.0-cp314-cp314-win_amd64.whl.

File metadata

  • Download URL: net_mesh-0.22.0-cp314-cp314-win_amd64.whl
  • Upload date:
  • Size: 4.0 MB
  • Tags: CPython 3.14, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for net_mesh-0.22.0-cp314-cp314-win_amd64.whl
Algorithm Hash digest
SHA256 463721c762f0935d2ef8657c5656d9bda0973c4b2d19a1d36648546bb7901737
MD5 97c2e34895c7755bf3c0389f79eb2495
BLAKE2b-256 52788cfdb198f3aedddba8f8cda4cfea621026bb17ec28182a69486b2e0cc382

See more details on using hashes here.

Provenance

The following attestation bundles were made for net_mesh-0.22.0-cp314-cp314-win_amd64.whl:

Publisher: release-python.yml on ai-2070/net

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file net_mesh-0.22.0-cp314-cp314-manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for net_mesh-0.22.0-cp314-cp314-manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 4f245c3766df417687c7fa2404d75a09fd3c7c04864f8fe849e861060dd9d248
MD5 62efae0b46602f0b90840883f91c2200
BLAKE2b-256 fbaa010e538630a6e1b3a32b6dc9a823c667aa22653580d50d871c2c21c8089e

See more details on using hashes here.

Provenance

The following attestation bundles were made for net_mesh-0.22.0-cp314-cp314-manylinux_2_28_x86_64.whl:

Publisher: release-python.yml on ai-2070/net

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file net_mesh-0.22.0-cp314-cp314-manylinux_2_28_aarch64.whl.

File metadata

File hashes

Hashes for net_mesh-0.22.0-cp314-cp314-manylinux_2_28_aarch64.whl
Algorithm Hash digest
SHA256 198cca5024adcd375e8d745a28b841a2f86907a8a3425ca75f391eeba1d54499
MD5 75ccb00926fc746ff42e237cc58be1d7
BLAKE2b-256 f3528f3debea0a323ef13f14faee2790e7039a32d61d4b6abef88ed6534cdeb0

See more details on using hashes here.

Provenance

The following attestation bundles were made for net_mesh-0.22.0-cp314-cp314-manylinux_2_28_aarch64.whl:

Publisher: release-python.yml on ai-2070/net

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file net_mesh-0.22.0-cp314-cp314-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for net_mesh-0.22.0-cp314-cp314-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 8af79e8c7b913b1ec809e3a4e833a172770dce9af896bac1e9c3bc889866b540
MD5 e9e6b97f9ce8dc8e55f36a766c776f2c
BLAKE2b-256 0cff59f05778b245188f3d1e307381cebf765a75e4696f402c8141453baae3e4

See more details on using hashes here.

Provenance

The following attestation bundles were made for net_mesh-0.22.0-cp314-cp314-macosx_11_0_arm64.whl:

Publisher: release-python.yml on ai-2070/net

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file net_mesh-0.22.0-cp314-cp314-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for net_mesh-0.22.0-cp314-cp314-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 c5b505c0b7582c42f939a1937e757a552a8985a4b30c9a3df03ecf57c0d548a0
MD5 70893f08ff47412a5fda046ef1bf8b48
BLAKE2b-256 93b410d7ae9bb5f466e106185cea6a7482ae2e5f7c216032929c12b0bb581dae

See more details on using hashes here.

Provenance

The following attestation bundles were made for net_mesh-0.22.0-cp314-cp314-macosx_10_12_x86_64.whl:

Publisher: release-python.yml on ai-2070/net

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file net_mesh-0.22.0-cp313-cp313t-manylinux_2_28_aarch64.whl.

File metadata

File hashes

Hashes for net_mesh-0.22.0-cp313-cp313t-manylinux_2_28_aarch64.whl
Algorithm Hash digest
SHA256 9fc8257233b7a2c812cc26cf0329f9f1f7f82296ee5357aa726007f382bdaab7
MD5 a76c60a8976b8425027cf7b1d6e75ddb
BLAKE2b-256 2cfe5f983535a75b78965c0292ca9ab4c69fc9d86c673d3c54bac4cf3cf88120

See more details on using hashes here.

Provenance

The following attestation bundles were made for net_mesh-0.22.0-cp313-cp313t-manylinux_2_28_aarch64.whl:

Publisher: release-python.yml on ai-2070/net

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file net_mesh-0.22.0-cp313-cp313-win_arm64.whl.

File metadata

  • Download URL: net_mesh-0.22.0-cp313-cp313-win_arm64.whl
  • Upload date:
  • Size: 3.8 MB
  • Tags: CPython 3.13, Windows ARM64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for net_mesh-0.22.0-cp313-cp313-win_arm64.whl
Algorithm Hash digest
SHA256 a821e3a75b91b90ad4e192cb2a91878419f57ca3bd17a67a8d72cdaf372d5dd6
MD5 22b5998dd45deb489a146806eb301882
BLAKE2b-256 6d4c664b62167b5d62647628003d2949e53324bcab1ea8eca25f883ac094f225

See more details on using hashes here.

Provenance

The following attestation bundles were made for net_mesh-0.22.0-cp313-cp313-win_arm64.whl:

Publisher: release-python.yml on ai-2070/net

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file net_mesh-0.22.0-cp313-cp313-win_amd64.whl.

File metadata

  • Download URL: net_mesh-0.22.0-cp313-cp313-win_amd64.whl
  • Upload date:
  • Size: 4.0 MB
  • Tags: CPython 3.13, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for net_mesh-0.22.0-cp313-cp313-win_amd64.whl
Algorithm Hash digest
SHA256 49f1ffb9f566fb5390eebfc31b62b4b52fc02301a2c5cda9fdc592f48fdd7474
MD5 b73737c5d292e0d4d25bc1051b3dbbe6
BLAKE2b-256 189c48dc45f0317997c7e9ad331e65e58689087a1f5f310b33138f8ebafdc184

See more details on using hashes here.

Provenance

The following attestation bundles were made for net_mesh-0.22.0-cp313-cp313-win_amd64.whl:

Publisher: release-python.yml on ai-2070/net

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file net_mesh-0.22.0-cp313-cp313-manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for net_mesh-0.22.0-cp313-cp313-manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 ff53ddb9d0830d9876af1825b940d818d77ea6d05bc36d4924fdd89919e64835
MD5 d9988cc5c09ba552ad2b423e5948e1bf
BLAKE2b-256 5927aeec6354bf595ba67513bb38b46e1cd7ec4fe0121a6b7973d4eb557f84d9

See more details on using hashes here.

Provenance

The following attestation bundles were made for net_mesh-0.22.0-cp313-cp313-manylinux_2_28_x86_64.whl:

Publisher: release-python.yml on ai-2070/net

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file net_mesh-0.22.0-cp313-cp313-manylinux_2_28_aarch64.whl.

File metadata

File hashes

Hashes for net_mesh-0.22.0-cp313-cp313-manylinux_2_28_aarch64.whl
Algorithm Hash digest
SHA256 bb512273b7ed5ffc5487cb265f28bf5bb33380362de2a0edd67a736b66db9727
MD5 542037e9ab1033b3067d318203a7cea1
BLAKE2b-256 b74b6b672083490c97a571416484c3bf22e97e51dcbe8225241353722d5f52d1

See more details on using hashes here.

Provenance

The following attestation bundles were made for net_mesh-0.22.0-cp313-cp313-manylinux_2_28_aarch64.whl:

Publisher: release-python.yml on ai-2070/net

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file net_mesh-0.22.0-cp313-cp313-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for net_mesh-0.22.0-cp313-cp313-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 49d449c581a753e89843edf55f4d3198a47c6e3e42d3439508174c1b2640a211
MD5 c08d162a481131462ceb26503a6eb1b6
BLAKE2b-256 dc07c394daf8f8fcc85efaa061e7aea515a8ba4e8ff5e8c97fc747300bed36a7

See more details on using hashes here.

Provenance

The following attestation bundles were made for net_mesh-0.22.0-cp313-cp313-macosx_11_0_arm64.whl:

Publisher: release-python.yml on ai-2070/net

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file net_mesh-0.22.0-cp313-cp313-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for net_mesh-0.22.0-cp313-cp313-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 a67d4bf798eed909e1d50978072a3c14a3997ee1529b10e8d8b6584fec320c6b
MD5 9039893cc1b08683b7f53b193766bd43
BLAKE2b-256 06478b4b2eced0c8d3215bd87fc2072e2a947ec71f6dd8ef92d7bd3d2c293ca6

See more details on using hashes here.

Provenance

The following attestation bundles were made for net_mesh-0.22.0-cp313-cp313-macosx_10_12_x86_64.whl:

Publisher: release-python.yml on ai-2070/net

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file net_mesh-0.22.0-cp312-cp312-win_arm64.whl.

File metadata

  • Download URL: net_mesh-0.22.0-cp312-cp312-win_arm64.whl
  • Upload date:
  • Size: 3.8 MB
  • Tags: CPython 3.12, Windows ARM64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for net_mesh-0.22.0-cp312-cp312-win_arm64.whl
Algorithm Hash digest
SHA256 16cb81723cdf6106a7194e9da0422efc6f0a37759bfa9e759841c8f3c63f29b9
MD5 054270fd393f1e7c0b86afaff5465689
BLAKE2b-256 38dba89520affcc27ce07fd591585debe5cca158802f5af6ef93b5954e399317

See more details on using hashes here.

Provenance

The following attestation bundles were made for net_mesh-0.22.0-cp312-cp312-win_arm64.whl:

Publisher: release-python.yml on ai-2070/net

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file net_mesh-0.22.0-cp312-cp312-win_amd64.whl.

File metadata

  • Download URL: net_mesh-0.22.0-cp312-cp312-win_amd64.whl
  • Upload date:
  • Size: 4.0 MB
  • Tags: CPython 3.12, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for net_mesh-0.22.0-cp312-cp312-win_amd64.whl
Algorithm Hash digest
SHA256 723f1ffcff6e9d4023c5e1c0a73fa88a120e104d14cbc18eea2593252a79de87
MD5 15d811887138de7a7f7b072777d4cb2c
BLAKE2b-256 1175576ca0cf78c77ddcf869cf060df50a6f57a321daa8e902777cdb6ea4f7af

See more details on using hashes here.

Provenance

The following attestation bundles were made for net_mesh-0.22.0-cp312-cp312-win_amd64.whl:

Publisher: release-python.yml on ai-2070/net

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file net_mesh-0.22.0-cp312-cp312-manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for net_mesh-0.22.0-cp312-cp312-manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 80a07d8c9a1e6c63111d1ae6985f288ee2bd4d995a04aca2e5441b14cfceb224
MD5 5d16bfee1aebcedd269b54c949a89131
BLAKE2b-256 ad3129f5950ad74d0df0f66783107f655e7dd891c3efb4528ad022f302214d0d

See more details on using hashes here.

Provenance

The following attestation bundles were made for net_mesh-0.22.0-cp312-cp312-manylinux_2_28_x86_64.whl:

Publisher: release-python.yml on ai-2070/net

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file net_mesh-0.22.0-cp312-cp312-manylinux_2_28_aarch64.whl.

File metadata

File hashes

Hashes for net_mesh-0.22.0-cp312-cp312-manylinux_2_28_aarch64.whl
Algorithm Hash digest
SHA256 ce3bf4d4ee690502b5a035f0863eb5e0cb70779355e4bf0995a6a2f56e83ac74
MD5 2815853d26024cfa751b9c4c13310a22
BLAKE2b-256 43ff1613665c1e583b48653335721cdd15b9f44d445594a13671dc00e4fb6da7

See more details on using hashes here.

Provenance

The following attestation bundles were made for net_mesh-0.22.0-cp312-cp312-manylinux_2_28_aarch64.whl:

Publisher: release-python.yml on ai-2070/net

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file net_mesh-0.22.0-cp312-cp312-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for net_mesh-0.22.0-cp312-cp312-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 c7b428b52a30b16b998175f4740ae9c90d78461c59133f7fc106c5196b75599d
MD5 517f35a6b03a702c5fa0605c5ccee636
BLAKE2b-256 ac62ed6abac6f39380441b79744bbf158a4282a04b8c1e0f779bae2cb3d72f34

See more details on using hashes here.

Provenance

The following attestation bundles were made for net_mesh-0.22.0-cp312-cp312-macosx_11_0_arm64.whl:

Publisher: release-python.yml on ai-2070/net

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file net_mesh-0.22.0-cp312-cp312-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for net_mesh-0.22.0-cp312-cp312-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 4a6b356a199076232000d4e46d1ec1ed52c24d787341bf1dff4c962b2992bd04
MD5 9047221a370710937f2e93663f6d8394
BLAKE2b-256 6bcfb096b82b449bbaa892601a18c2eb5f9bb00e6b3f3643537d02ec5974edd8

See more details on using hashes here.

Provenance

The following attestation bundles were made for net_mesh-0.22.0-cp312-cp312-macosx_10_12_x86_64.whl:

Publisher: release-python.yml on ai-2070/net

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file net_mesh-0.22.0-cp311-cp311-win_arm64.whl.

File metadata

  • Download URL: net_mesh-0.22.0-cp311-cp311-win_arm64.whl
  • Upload date:
  • Size: 3.8 MB
  • Tags: CPython 3.11, Windows ARM64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for net_mesh-0.22.0-cp311-cp311-win_arm64.whl
Algorithm Hash digest
SHA256 b6b844ebe1c90c625ca1b7174eb8d5712a737cc34ac0b83e4918660eebc98763
MD5 a11870cf7f2ab1817d004cb7ea68a9e0
BLAKE2b-256 3d019536194a4988566483a347cbc9e9ddbd46b9f1b56e425c1369cb06f947a6

See more details on using hashes here.

Provenance

The following attestation bundles were made for net_mesh-0.22.0-cp311-cp311-win_arm64.whl:

Publisher: release-python.yml on ai-2070/net

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file net_mesh-0.22.0-cp311-cp311-win_amd64.whl.

File metadata

  • Download URL: net_mesh-0.22.0-cp311-cp311-win_amd64.whl
  • Upload date:
  • Size: 4.0 MB
  • Tags: CPython 3.11, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for net_mesh-0.22.0-cp311-cp311-win_amd64.whl
Algorithm Hash digest
SHA256 fc8f5889667e87f3564d08e4bc0141c52635de43b63aa6f5aff993230589cae7
MD5 261fe8801b659f959cb18cf52d15ca3f
BLAKE2b-256 eb5df2c3fca1db6cc33df7adbb8b8abdcdaa5ce7cf45443ecdd4272f136e64c6

See more details on using hashes here.

Provenance

The following attestation bundles were made for net_mesh-0.22.0-cp311-cp311-win_amd64.whl:

Publisher: release-python.yml on ai-2070/net

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file net_mesh-0.22.0-cp311-cp311-manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for net_mesh-0.22.0-cp311-cp311-manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 2321ab906b34e0c7351e7a55a9b460bcf978887f48003ab9ee560cb036d467b4
MD5 a4f239abf9d57203b655c2a8fecdb637
BLAKE2b-256 62c6f3c1b3ccc735f112881cf2ca64cc0184c4c432b922a6b9c9209b1fb06264

See more details on using hashes here.

Provenance

The following attestation bundles were made for net_mesh-0.22.0-cp311-cp311-manylinux_2_28_x86_64.whl:

Publisher: release-python.yml on ai-2070/net

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file net_mesh-0.22.0-cp311-cp311-manylinux_2_28_aarch64.whl.

File metadata

File hashes

Hashes for net_mesh-0.22.0-cp311-cp311-manylinux_2_28_aarch64.whl
Algorithm Hash digest
SHA256 683f7507e3d0d4c3196a69171f0a52cc8b2e118fc01642d7c72740e5b6413410
MD5 c1ed7b34714aed9b36232760d717e6eb
BLAKE2b-256 d3d1d6949a523778e44804217fb0da06f53a958848e6e191092c284465ab13c4

See more details on using hashes here.

Provenance

The following attestation bundles were made for net_mesh-0.22.0-cp311-cp311-manylinux_2_28_aarch64.whl:

Publisher: release-python.yml on ai-2070/net

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file net_mesh-0.22.0-cp311-cp311-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for net_mesh-0.22.0-cp311-cp311-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 1a81f2a23b46fa8906217cfce3e6c43d80f02937ef9bd169f19e48abca15ad94
MD5 6b941fbcff0d71d7b5c429c97f56d942
BLAKE2b-256 d676198ccc6da9afb0d331716368b2caadfe90114b2923ec0ee0ebb9091847af

See more details on using hashes here.

Provenance

The following attestation bundles were made for net_mesh-0.22.0-cp311-cp311-macosx_11_0_arm64.whl:

Publisher: release-python.yml on ai-2070/net

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file net_mesh-0.22.0-cp311-cp311-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for net_mesh-0.22.0-cp311-cp311-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 355bb2b91f0d3c93510f79414f20f92c58b7e03bd8ef74607d38a497b161994a
MD5 325ef84115d0accbb91c6981b5b9254a
BLAKE2b-256 d40a743549e0e28db13f335f009e974e0481debd39db9b0d2ae704e542680fd8

See more details on using hashes here.

Provenance

The following attestation bundles were made for net_mesh-0.22.0-cp311-cp311-macosx_10_12_x86_64.whl:

Publisher: release-python.yml on ai-2070/net

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file net_mesh-0.22.0-cp310-cp310-win_amd64.whl.

File metadata

  • Download URL: net_mesh-0.22.0-cp310-cp310-win_amd64.whl
  • Upload date:
  • Size: 4.0 MB
  • Tags: CPython 3.10, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for net_mesh-0.22.0-cp310-cp310-win_amd64.whl
Algorithm Hash digest
SHA256 6c37eca12d1ce45ba6918b59a81e7e979567d1c2fe384a48753957c006365169
MD5 a2cd96a86321f5d8adbd2b35ce5f6fb7
BLAKE2b-256 ac6c82c33c4e8fdf73892d9ad8113c40cd295f5af34fb2304a60e5afccd1ccdd

See more details on using hashes here.

Provenance

The following attestation bundles were made for net_mesh-0.22.0-cp310-cp310-win_amd64.whl:

Publisher: release-python.yml on ai-2070/net

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file net_mesh-0.22.0-cp310-cp310-manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for net_mesh-0.22.0-cp310-cp310-manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 8f7e9342ae3f9fc14706359ad855ce14fca7369c7d70616d4c9eb08e7fa325c0
MD5 31ad1d0f9095fe9f20cb0468a3351259
BLAKE2b-256 c851cce3e15a8b0bc54a837958c2146fd7f56baee025def3ae4ddbf77defdc6f

See more details on using hashes here.

Provenance

The following attestation bundles were made for net_mesh-0.22.0-cp310-cp310-manylinux_2_28_x86_64.whl:

Publisher: release-python.yml on ai-2070/net

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file net_mesh-0.22.0-cp310-cp310-manylinux_2_28_aarch64.whl.

File metadata

File hashes

Hashes for net_mesh-0.22.0-cp310-cp310-manylinux_2_28_aarch64.whl
Algorithm Hash digest
SHA256 b2dd8be05ff7087ab6e6dc4c36a443cc41cb1e00ae9f9bf82da48477681156d5
MD5 ec908df6b540e664cb94c5708554da2d
BLAKE2b-256 f52b7827ad53cefba3fe62617bd358e975a058d7596aecdf528b2735f96d339d

See more details on using hashes here.

Provenance

The following attestation bundles were made for net_mesh-0.22.0-cp310-cp310-manylinux_2_28_aarch64.whl:

Publisher: release-python.yml on ai-2070/net

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page