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
)

Async API

Every I/O surface ships a parallel Async* class. The sync API stays unchanged — pick whichever shape fits the caller; both share the same underlying mesh / adapter / handle and interoperate freely.

Quickstart

import asyncio
from net import NetMesh, AsyncNetMesh, AsyncMeshRpc

async def main():
    mesh = NetMesh("127.0.0.1:9000", "00" * 32)
    mesh.start()

    amesh = AsyncNetMesh(mesh)            # Arc::clone — shares the same MeshNode
    arpc = AsyncMeshRpc(mesh)             # same — shared service registry

    await amesh.connect("127.0.0.1:9001", peer_pub, peer_node_id)
    reply = await arpc.call(peer_node_id, "echo", b"hello")
    print(reply)

asyncio.run(main())

Available Async* classes

Sync class Async sibling What's awaitable
NetMesh AsyncNetMesh connect, accept, push_to, poll, subscribe_channel, unsubscribe_channel, publish, announce_capabilities, shutdown
NetStream AsyncNetStream send, send_with_retry, send_blocking
MeshRpc AsyncMeshRpc call, call_service, call_streaming, call_client_stream, call_duplex, serve / serve_client_stream / serve_duplex (each accepts async def handlers)
RpcStream AsyncRpcStream PEP 525 async for chunk in stream:
ClientStreamCall AsyncClientStreamCall send, finish
DuplexCall / DuplexSink / DuplexStream AsyncDuplexCall / AsyncDuplexSink / AsyncDuplexStream send, finish_sending, async-iter on the read half
TypedMeshRpc AsyncTypedMeshRpc Codec-wrapped variants of every AsyncMeshRpc shape
MemoriesAdapter AsyncMemoriesAdapter wait_for_seq, wait_for_token, watch_memories, snapshot_and_watch_memories
MemoryWatchIter AsyncMemoryWatchIter PEP 525 async iter
TasksAdapter AsyncTasksAdapter wait_for_seq, wait_for_token, watch_tasks, snapshot_and_watch_tasks
TaskWatchIter AsyncTaskWatchIter PEP 525 async iter
RedexFile AsyncRedexFile tail() returns an AsyncRedexTailIter
RedexTailIter AsyncRedexTailIter PEP 525 async iter
DaemonRuntime AsyncDaemonRuntime start, shutdown, spawn, spawn_from_snapshot, stop, snapshot, deliver, start_migration, start_migration_with
MigrationHandle AsyncMigrationHandle wait, wait_with_timeout, cancel
MeshBlobAdapter AsyncMeshBlobAdapter store, fetch, fetch_range, exists, repair_blob
blob_publish / blob_resolve (free fns) async_blob_publish / async_blob_resolve Awaitable versions of the free functions
RegistryClient AsyncRegistryClient list, spawn, unregister
FoldQueryClient AsyncFoldQueryClient query_latest, query_summarize_now
MeshQueryRunner AsyncMeshQueryRunner execute
DeckClient AsyncDeckClient close; getters stay sync; .admin is AsyncAdminCommands; .ice is AsyncIceCommands; .snapshots() / .status_summary_stream() return async iters
AdminCommands AsyncAdminCommands drain, enter_maintenance, exit_maintenance, cordon, uncordon, drop_replicas, invalidate_placement, restart_all_daemons, clear_avoid_list
IceCommands / IceProposal / SimulatedIceProposal AsyncIceCommands / AsyncIceProposal / AsyncSimulatedIceProposal Factories stay sync; proposal.simulate() and simulated.commit() are awaitable
SnapshotStream / StatusSummaryStream AsyncSnapshotStream / AsyncStatusSummaryStream PEP 525 async iter
MeshOsDaemonSdk / MeshOsDaemonHandle AsyncMeshOsDaemonSdk / AsyncMeshOsDaemonHandle shutdown / next_control / graceful_shutdown are awaitable; constructed via from_sync(sync_inst) (consumes the sync sibling)

Mixing sync and async

Async* classes wrap the same Rust Arc<...> as their sync counterparts. A server registered via MeshRpc.serve(...) is callable from AsyncMeshRpc.call(...) and vice versa — same for every adapter. Mix shapes within a single program freely; just pick the one that matches the caller (sync script: sync API; asyncio handler: async API).

from net import NetMesh, MeshRpc, AsyncMeshRpc, MemoriesAdapter, AsyncMemoriesAdapter

mesh = NetMesh("127.0.0.1:9000", "00" * 32)
# A server, registered from sync code
def echo(req: bytes) -> bytes:
    return req
MeshRpc(mesh).serve("echo", echo)

# An async caller against the same mesh — sees the same server
async def caller():
    arpc = AsyncMeshRpc(mesh)
    return await arpc.call_service("echo", b"hi")

Cancellation

asyncio.wait_for(...) cancellation propagates to the substrate's cancel registry on every nRPC call. The wrapped task drops, the substrate's Mesh::cancel(token) fires, and the in-flight call returns RpcCancelledError:

import asyncio
from net import AsyncMeshRpc, RpcCancelledError

async def with_timeout(arpc):
    try:
        return await asyncio.wait_for(
            arpc.call(target, "slow", b"..."),
            timeout=0.5,
        )
    except (asyncio.TimeoutError, RpcCancelledError):
        # Either is fine — the underlying call is cancelled either way.
        return None

Streaming shapes propagate cancellation per construction — cancelling mid-async for terminates the entire stream, not just one pull. Non-mesh subsystems (channel publish, capability announce, mesh handshake) don't have substrate cancel tokens yet; asyncio cancellation still drops the awaiting tokio task, but the in-flight network round-trip may complete in the background.

async def server handlers

AsyncMeshRpc.serve (and the typed AsyncTypedMeshRpc.serve) detect inspect.iscoroutinefunction(handler) at register time and route the coroutine through a dedicated dispatch path. Sync handlers keep the spawn_blocking shape; async handlers run as native coroutines:

async def handler(req: bytes) -> bytes:
    chunk = await fetch_from_upstream(req)
    return chunk

AsyncMeshRpc(mesh).serve("upstream", handler)

Cancellation propagates end-to-end. When a caller's asyncio.wait_for(rpc.call(...), timeout=...) expires, the substrate fires a CANCEL frame to the server; the dispatched coroutine sees asyncio.CancelledError raised inside its await. Wrap critical sections in try/except asyncio.CancelledError if you need cleanup before re-raising.

Single dispatcher loop — keep handlers cooperative. All async def handlers in the process share one event loop. A handler that does blocking Python I/O (time.sleep, requests.get, raw socket.recv, etc.) stalls every other in-flight handler. Always await async equivalents:

# ✗ Bad — blocks the dispatcher loop for 5 seconds.
async def handler(req: bytes) -> bytes:
    time.sleep(5.0)
    return req

# ✓ Good — yields back to the loop.
async def handler(req: bytes) -> bytes:
    await asyncio.sleep(5.0)
    return req

# ✓ Good — push blocking work to a thread-pool slot.
async def handler(req: bytes) -> bytes:
    loop = asyncio.get_running_loop()
    return await loop.run_in_executor(None, blocking_call, req)

Migration cookbook

The mechanical translation:

# Before — sync
def listener(mesh):
    rpc = MeshRpc(mesh)
    reply = rpc.call(target, "svc", b"...")
    return reply

# After — async
async def listener(mesh):
    rpc = AsyncMeshRpc(mesh)
    reply = await rpc.call(target, "svc", b"...")
    return reply

For loops over streams:

# Before — sync
for chunk in rpc.call_streaming(...):
    consume(chunk)

# After — async
async for chunk in arpc.call_streaming(...):
    await consume(chunk)

For server-pushed watches (watch_tasks, watch_memories, tail, subscribe_logs, etc.):

# Before — sync
it = adapter.watch_memories(source="bot")
for batch in it:
    render(batch)

# After — async
async_adapter = AsyncMemoriesAdapter(adapter)
it = await async_adapter.watch_memories(source="bot")
async for batch in it:
    await render(batch)

The sync Adapter.watch_memories(...) returns an iterator directly; the async equivalent is an awaitable yielding an async iterator (one extra await), because the underlying stream construction itself may run on the bridge runtime.

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.25.0.tar.gz (6.1 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.25.0-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl (4.8 MB view details)

Uploaded PyPymanylinux: glibc 2.28+ x86-64

net_mesh-0.25.0-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl (4.5 MB view details)

Uploaded PyPymanylinux: glibc 2.28+ ARM64

net_mesh-0.25.0-cp315-cp315-manylinux_2_28_x86_64.whl (4.8 MB view details)

Uploaded CPython 3.15manylinux: glibc 2.28+ x86-64

net_mesh-0.25.0-cp314-cp314t-manylinux_2_28_aarch64.whl (4.5 MB view details)

Uploaded CPython 3.14tmanylinux: glibc 2.28+ ARM64

net_mesh-0.25.0-cp314-cp314-win_arm64.whl (3.9 MB view details)

Uploaded CPython 3.14Windows ARM64

net_mesh-0.25.0-cp314-cp314-win_amd64.whl (4.1 MB view details)

Uploaded CPython 3.14Windows x86-64

net_mesh-0.25.0-cp314-cp314-manylinux_2_28_x86_64.whl (4.8 MB view details)

Uploaded CPython 3.14manylinux: glibc 2.28+ x86-64

net_mesh-0.25.0-cp314-cp314-manylinux_2_28_aarch64.whl (4.6 MB view details)

Uploaded CPython 3.14manylinux: glibc 2.28+ ARM64

net_mesh-0.25.0-cp314-cp314-macosx_11_0_arm64.whl (4.2 MB view details)

Uploaded CPython 3.14macOS 11.0+ ARM64

net_mesh-0.25.0-cp314-cp314-macosx_10_12_x86_64.whl (4.6 MB view details)

Uploaded CPython 3.14macOS 10.12+ x86-64

net_mesh-0.25.0-cp313-cp313t-manylinux_2_28_aarch64.whl (4.6 MB view details)

Uploaded CPython 3.13tmanylinux: glibc 2.28+ ARM64

net_mesh-0.25.0-cp313-cp313-win_arm64.whl (3.9 MB view details)

Uploaded CPython 3.13Windows ARM64

net_mesh-0.25.0-cp313-cp313-win_amd64.whl (4.1 MB view details)

Uploaded CPython 3.13Windows x86-64

net_mesh-0.25.0-cp313-cp313-manylinux_2_28_x86_64.whl (4.8 MB view details)

Uploaded CPython 3.13manylinux: glibc 2.28+ x86-64

net_mesh-0.25.0-cp313-cp313-manylinux_2_28_aarch64.whl (4.6 MB view details)

Uploaded CPython 3.13manylinux: glibc 2.28+ ARM64

net_mesh-0.25.0-cp313-cp313-macosx_11_0_arm64.whl (4.1 MB view details)

Uploaded CPython 3.13macOS 11.0+ ARM64

net_mesh-0.25.0-cp313-cp313-macosx_10_12_x86_64.whl (4.6 MB view details)

Uploaded CPython 3.13macOS 10.12+ x86-64

net_mesh-0.25.0-cp312-cp312-win_arm64.whl (3.9 MB view details)

Uploaded CPython 3.12Windows ARM64

net_mesh-0.25.0-cp312-cp312-win_amd64.whl (4.1 MB view details)

Uploaded CPython 3.12Windows x86-64

net_mesh-0.25.0-cp312-cp312-manylinux_2_28_x86_64.whl (4.8 MB view details)

Uploaded CPython 3.12manylinux: glibc 2.28+ x86-64

net_mesh-0.25.0-cp312-cp312-manylinux_2_28_aarch64.whl (4.5 MB view details)

Uploaded CPython 3.12manylinux: glibc 2.28+ ARM64

net_mesh-0.25.0-cp312-cp312-macosx_11_0_arm64.whl (4.1 MB view details)

Uploaded CPython 3.12macOS 11.0+ ARM64

net_mesh-0.25.0-cp312-cp312-macosx_10_12_x86_64.whl (4.6 MB view details)

Uploaded CPython 3.12macOS 10.12+ x86-64

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

Uploaded CPython 3.11Windows ARM64

net_mesh-0.25.0-cp311-cp311-win_amd64.whl (4.1 MB view details)

Uploaded CPython 3.11Windows x86-64

net_mesh-0.25.0-cp311-cp311-manylinux_2_28_x86_64.whl (4.8 MB view details)

Uploaded CPython 3.11manylinux: glibc 2.28+ x86-64

net_mesh-0.25.0-cp311-cp311-manylinux_2_28_aarch64.whl (4.5 MB view details)

Uploaded CPython 3.11manylinux: glibc 2.28+ ARM64

net_mesh-0.25.0-cp311-cp311-macosx_11_0_arm64.whl (4.2 MB view details)

Uploaded CPython 3.11macOS 11.0+ ARM64

net_mesh-0.25.0-cp311-cp311-macosx_10_12_x86_64.whl (4.6 MB view details)

Uploaded CPython 3.11macOS 10.12+ x86-64

net_mesh-0.25.0-cp310-cp310-win_amd64.whl (4.1 MB view details)

Uploaded CPython 3.10Windows x86-64

net_mesh-0.25.0-cp310-cp310-manylinux_2_28_x86_64.whl (4.8 MB view details)

Uploaded CPython 3.10manylinux: glibc 2.28+ x86-64

net_mesh-0.25.0-cp310-cp310-manylinux_2_28_aarch64.whl (4.5 MB view details)

Uploaded CPython 3.10manylinux: glibc 2.28+ ARM64

File details

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

File metadata

  • Download URL: net_mesh-0.25.0.tar.gz
  • Upload date:
  • Size: 6.1 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.25.0.tar.gz
Algorithm Hash digest
SHA256 07dda72b4ef937671159c6f12870200abf95a012e72e2f72e7158b657bc7ff5d
MD5 25e7cff2b4241c09dabd05a420bb3d0e
BLAKE2b-256 27367f6de06141323722dc7cc2f48426e76ec63b4631890bbeb63cdc0e3c76cc

See more details on using hashes here.

Provenance

The following attestation bundles were made for net_mesh-0.25.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.25.0-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for net_mesh-0.25.0-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 22b6dc5ece87c4d14ff940d1279af5df7008ffbedab7d001f47e21defc302f0e
MD5 5810c8fda55ff2fc48281f6ef7e15e31
BLAKE2b-256 56917259dd0b0b9a6a8cb2a2074089ebeadec9e3a428498b0f34cd448e849ef8

See more details on using hashes here.

Provenance

The following attestation bundles were made for net_mesh-0.25.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.25.0-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl.

File metadata

File hashes

Hashes for net_mesh-0.25.0-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl
Algorithm Hash digest
SHA256 a5287f2edf31f032682077207a2267217effde9388803c14bc8559e1c80aa797
MD5 7607c913ed8065ea1305bcec0abe2267
BLAKE2b-256 e229171af9cb33ba5bb137719d86710efd6cabf1449f6ac78fd2dc1e9d32ac36

See more details on using hashes here.

Provenance

The following attestation bundles were made for net_mesh-0.25.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.25.0-cp315-cp315-manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for net_mesh-0.25.0-cp315-cp315-manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 8bea46e3f9f2330cc477ee29f872ee66430ea6fc3099933badb1703c353f1979
MD5 a73b80d99bab891daa4691e7db68e58b
BLAKE2b-256 3fe4d18e11e32b4a24b19b90f9dc0ce40500565bc15664f82a2474b6b275ad05

See more details on using hashes here.

Provenance

The following attestation bundles were made for net_mesh-0.25.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.25.0-cp314-cp314t-manylinux_2_28_aarch64.whl.

File metadata

File hashes

Hashes for net_mesh-0.25.0-cp314-cp314t-manylinux_2_28_aarch64.whl
Algorithm Hash digest
SHA256 6b01739133a3235f18541d9dfbc8d96e3982a54324e7807b706c020326e860a6
MD5 beaed4e5abf0ae390f3941223e4f72be
BLAKE2b-256 c0f44235629fdb9214297808166b7efa4f4db2f1c83dee691c0bbb0e6f89cb4e

See more details on using hashes here.

Provenance

The following attestation bundles were made for net_mesh-0.25.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.25.0-cp314-cp314-win_arm64.whl.

File metadata

  • Download URL: net_mesh-0.25.0-cp314-cp314-win_arm64.whl
  • Upload date:
  • Size: 3.9 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.25.0-cp314-cp314-win_arm64.whl
Algorithm Hash digest
SHA256 fc78b01ad0d021067b8821c65ea7b5a12560ae158dff52969a6a2a56a7720c77
MD5 70f02fd5569944456ba7bfc233280f87
BLAKE2b-256 4963718599be8b1d4729ae4929c1a7cc7c6ba6719916282575c4da07808108b8

See more details on using hashes here.

Provenance

The following attestation bundles were made for net_mesh-0.25.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.25.0-cp314-cp314-win_amd64.whl.

File metadata

  • Download URL: net_mesh-0.25.0-cp314-cp314-win_amd64.whl
  • Upload date:
  • Size: 4.1 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.25.0-cp314-cp314-win_amd64.whl
Algorithm Hash digest
SHA256 736edfb8bdb0a54bf20e343cf78f92d82254abab9f63480d357868f1d71b395c
MD5 fcab01d90e896b373b419304845b9b62
BLAKE2b-256 fa84223c4fb7ae9624da8992f3306d1dec43981f73dc52958f051a6e2e3b0c7a

See more details on using hashes here.

Provenance

The following attestation bundles were made for net_mesh-0.25.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.25.0-cp314-cp314-manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for net_mesh-0.25.0-cp314-cp314-manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 0530fbd479315bbdbe20b11fc6632f4a2eb2de3d65553317d0f758aa736f9fec
MD5 25eeefd255a965c0ce35aad014ae6a4c
BLAKE2b-256 8dd0bb24782ac8609a3c69c27ba7c667e8abc2a9ce90a3c323a28c713e143870

See more details on using hashes here.

Provenance

The following attestation bundles were made for net_mesh-0.25.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.25.0-cp314-cp314-manylinux_2_28_aarch64.whl.

File metadata

File hashes

Hashes for net_mesh-0.25.0-cp314-cp314-manylinux_2_28_aarch64.whl
Algorithm Hash digest
SHA256 1a9e80c6917f7fed85ec7b0d4efa67a8f8583f1d2d762596ce438c7471592426
MD5 5d17d455b672da75ae048a6ca3d51366
BLAKE2b-256 f5e4cb204b3ca07a3a78f5c37f9b3bd1cc0d6898fe7f31e7f7cb81d00183f764

See more details on using hashes here.

Provenance

The following attestation bundles were made for net_mesh-0.25.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.25.0-cp314-cp314-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for net_mesh-0.25.0-cp314-cp314-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 c46552b74d403aa54505a132e1a6bbd01e46570a28a4b7d07fe7131b202358e2
MD5 919b3f2a0a913ac58147f55c59453aa3
BLAKE2b-256 88bd739f395f64c4a43f00c1533080155cb52fc8a304f385aadc9f87bebb6a63

See more details on using hashes here.

Provenance

The following attestation bundles were made for net_mesh-0.25.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.25.0-cp314-cp314-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for net_mesh-0.25.0-cp314-cp314-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 1a839148529e26f265b2f4ff0c6736e4d701539b8dc5ae532c980361c7bcde05
MD5 aef9efaa0623719430d1f34e42700b90
BLAKE2b-256 a6d890377784d5e7fe48f59a577307a72b07960cbc1b269ac3e18abc8752b73f

See more details on using hashes here.

Provenance

The following attestation bundles were made for net_mesh-0.25.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.25.0-cp313-cp313t-manylinux_2_28_aarch64.whl.

File metadata

File hashes

Hashes for net_mesh-0.25.0-cp313-cp313t-manylinux_2_28_aarch64.whl
Algorithm Hash digest
SHA256 44559fd5970d2b99d6220beb544a91a5f4ec1c03c34fce7d333e9cf1b05f366b
MD5 2b6faef6d25bf46bd9fecc7a390c3382
BLAKE2b-256 3ae23e81ff45f5cb19497ee3c509e3d204cc515693333e90b414229c210597ef

See more details on using hashes here.

Provenance

The following attestation bundles were made for net_mesh-0.25.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.25.0-cp313-cp313-win_arm64.whl.

File metadata

  • Download URL: net_mesh-0.25.0-cp313-cp313-win_arm64.whl
  • Upload date:
  • Size: 3.9 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.25.0-cp313-cp313-win_arm64.whl
Algorithm Hash digest
SHA256 f1531c292adf6d658d0b704240fe1db286ba54ee0b1653871e69724645d5952c
MD5 5030a0502404a0733b417dddd4dd2953
BLAKE2b-256 906f834ee6dd1ff7764d204bd0aa04d8d5dcb4343ffe974dfb13f0bdf1303e1c

See more details on using hashes here.

Provenance

The following attestation bundles were made for net_mesh-0.25.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.25.0-cp313-cp313-win_amd64.whl.

File metadata

  • Download URL: net_mesh-0.25.0-cp313-cp313-win_amd64.whl
  • Upload date:
  • Size: 4.1 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.25.0-cp313-cp313-win_amd64.whl
Algorithm Hash digest
SHA256 d2c447615b372cc902335b523c8c0a7f514608dd7d4d373473028e3659a3470e
MD5 59dd906c55d1ab426d141c07016bf5fc
BLAKE2b-256 24c959e8aae4a395b77206d659af4925df8f83b21719b14b1899a067e8890ba6

See more details on using hashes here.

Provenance

The following attestation bundles were made for net_mesh-0.25.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.25.0-cp313-cp313-manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for net_mesh-0.25.0-cp313-cp313-manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 d8b7d3b0a2e323d9ed9fad2617bdd559c31a70d1a46bad2ce5c339e433d78a5b
MD5 9cc44817201aca14437282f940468b30
BLAKE2b-256 f5e04657f461557a20cf36f4a9182aa6ae1368099290027394bb9bc95a417443

See more details on using hashes here.

Provenance

The following attestation bundles were made for net_mesh-0.25.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.25.0-cp313-cp313-manylinux_2_28_aarch64.whl.

File metadata

File hashes

Hashes for net_mesh-0.25.0-cp313-cp313-manylinux_2_28_aarch64.whl
Algorithm Hash digest
SHA256 e456ac5e86aec523265409b72baa9854c7ec44ab71474e1d5c65317c190bd82f
MD5 c97684ff95da368fa9d77ba6d0600808
BLAKE2b-256 cfc410f5852384dae8218f6c06e292e7bb94be4bf8987349f5c668c391d3de76

See more details on using hashes here.

Provenance

The following attestation bundles were made for net_mesh-0.25.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.25.0-cp313-cp313-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for net_mesh-0.25.0-cp313-cp313-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 6b28525f69adaf7e070b5650b45a269d388c25059d00199925bf599d98bfab87
MD5 4270dd005c9177b58f2f817f3185ab35
BLAKE2b-256 d1db30962783dc0cdca9134e463c395d1ec170c7d8695ea1bbaedd2047cff058

See more details on using hashes here.

Provenance

The following attestation bundles were made for net_mesh-0.25.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.25.0-cp313-cp313-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for net_mesh-0.25.0-cp313-cp313-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 25e44f67d46e5353324b2de053f91572e38fd6c08df93080dbe2c4ef89a7ad2e
MD5 0c6cdfdec894507504e8705ca0613c61
BLAKE2b-256 fcb96b55fb9bde6f43a31495149bdbd6bc4adfd11eb59b67946708f6aba3e9da

See more details on using hashes here.

Provenance

The following attestation bundles were made for net_mesh-0.25.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.25.0-cp312-cp312-win_arm64.whl.

File metadata

  • Download URL: net_mesh-0.25.0-cp312-cp312-win_arm64.whl
  • Upload date:
  • Size: 3.9 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.25.0-cp312-cp312-win_arm64.whl
Algorithm Hash digest
SHA256 087477603761d94898a3bab490a00130f11566d8d23035af61a6b77d22a6f063
MD5 173d552b23c754657c6ff19f0e346f6f
BLAKE2b-256 935d98011337b7bdafc02fb91f90d5efa95e739c51797854f41f53a8e22a7bd7

See more details on using hashes here.

Provenance

The following attestation bundles were made for net_mesh-0.25.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.25.0-cp312-cp312-win_amd64.whl.

File metadata

  • Download URL: net_mesh-0.25.0-cp312-cp312-win_amd64.whl
  • Upload date:
  • Size: 4.1 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.25.0-cp312-cp312-win_amd64.whl
Algorithm Hash digest
SHA256 eae7897ded6cc23fc7ad831b79d51b82f8f2d8ae24c3907fedb9f69dc80193ff
MD5 5cf80493f8eb34c6b89ec17900fcd222
BLAKE2b-256 49e04df8bacda2bfd8a8e6ad73b300359c3109eedf414674de6472a33e05f4b5

See more details on using hashes here.

Provenance

The following attestation bundles were made for net_mesh-0.25.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.25.0-cp312-cp312-manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for net_mesh-0.25.0-cp312-cp312-manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 5f27f19c2d6749828034f2a3feff612d2a737bea2757add72320fe5791e8a1dc
MD5 ae237ec67055f49ae6d5451215a05bca
BLAKE2b-256 4db2632026bc677315b6475ff87ba53730536a5c0425ef44d48de08662a28124

See more details on using hashes here.

Provenance

The following attestation bundles were made for net_mesh-0.25.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.25.0-cp312-cp312-manylinux_2_28_aarch64.whl.

File metadata

File hashes

Hashes for net_mesh-0.25.0-cp312-cp312-manylinux_2_28_aarch64.whl
Algorithm Hash digest
SHA256 6be9debaa1ad56d8102ad86f1c153b431596883ece80393a92641f19dc059163
MD5 1711ef2727b437cecd4f096f75875b25
BLAKE2b-256 471a58b640380f869fed33a46c7dd807b38f8a3a30c66bea11fde4a8d0e2e7a9

See more details on using hashes here.

Provenance

The following attestation bundles were made for net_mesh-0.25.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.25.0-cp312-cp312-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for net_mesh-0.25.0-cp312-cp312-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 152597e0112d30c926a2dd2d9ee3b83d3c9179ab1a359c764891da0d753397b0
MD5 99a27fc3fc64117929b23602b9fc825a
BLAKE2b-256 25099d8619e6633d706f463e2e3634fe79c49801cf18468b4e21724f6f1e7680

See more details on using hashes here.

Provenance

The following attestation bundles were made for net_mesh-0.25.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.25.0-cp312-cp312-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for net_mesh-0.25.0-cp312-cp312-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 0c0bc08e357a23b2a5f68a1f396014b6b797c05415b8df03b82532d05b8c2873
MD5 0923dd45ed9fe09051692611bdbc0cd6
BLAKE2b-256 fe18450ea1be82b0d8427ec272714d7f5034e016faf3bb310a8d524bc5f520b4

See more details on using hashes here.

Provenance

The following attestation bundles were made for net_mesh-0.25.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.25.0-cp311-cp311-win_arm64.whl.

File metadata

  • Download URL: net_mesh-0.25.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.25.0-cp311-cp311-win_arm64.whl
Algorithm Hash digest
SHA256 d9c0ecea5962a15ce4f9a8acf05f962ff84e7fed22f60db6ecd325587d8b9fd9
MD5 71af564f9f049fae8f8e9a00b7ab4c6a
BLAKE2b-256 639d6dcca47e0432d3e244b22885ff066e1dc3c86021dbbefa48a88d7674546f

See more details on using hashes here.

Provenance

The following attestation bundles were made for net_mesh-0.25.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.25.0-cp311-cp311-win_amd64.whl.

File metadata

  • Download URL: net_mesh-0.25.0-cp311-cp311-win_amd64.whl
  • Upload date:
  • Size: 4.1 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.25.0-cp311-cp311-win_amd64.whl
Algorithm Hash digest
SHA256 3544da01e973a2cac6f001a7144c6d87ed5f24c941ac3de26e19030f3d7e8755
MD5 aea01785f08f9d36731ac9f87c5ca872
BLAKE2b-256 f12682abd12589dbc40afd7a4b0c8af8b4c7851fa07498298b5dc8e7695154b9

See more details on using hashes here.

Provenance

The following attestation bundles were made for net_mesh-0.25.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.25.0-cp311-cp311-manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for net_mesh-0.25.0-cp311-cp311-manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 1e7c4fc756e7fe0aa45cca95fcc97d4a66a840275c644dfffd09cb2f64b60d8d
MD5 3cdf918dfc2206a995ed63092610c2ff
BLAKE2b-256 a523147c98ebb3df6af8b1767af7863fc0602d83f99b8f7abe178dbd48015b7f

See more details on using hashes here.

Provenance

The following attestation bundles were made for net_mesh-0.25.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.25.0-cp311-cp311-manylinux_2_28_aarch64.whl.

File metadata

File hashes

Hashes for net_mesh-0.25.0-cp311-cp311-manylinux_2_28_aarch64.whl
Algorithm Hash digest
SHA256 b05dcf1ef6f73540621863dc68a65df7172b6ceea25cc5eec433804ac58c39e8
MD5 4f841fa8cf9874614e08089e53e85268
BLAKE2b-256 b4a7003abf0888f0e1bc5dc506ea721bca8e5e1c912d187dde7e543e56d65181

See more details on using hashes here.

Provenance

The following attestation bundles were made for net_mesh-0.25.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.25.0-cp311-cp311-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for net_mesh-0.25.0-cp311-cp311-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 7f446b4d0237d35b45600daa24931921a1c0cd7a1d27ec01870c5ee9af8c816a
MD5 3ccbcbfd5948ccf7b441285de12870bc
BLAKE2b-256 06d2ecb73b6ae5c453d7d8211eb7e6c0b6b2d9a16d98ada4fd9f09d4c1fa6744

See more details on using hashes here.

Provenance

The following attestation bundles were made for net_mesh-0.25.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.25.0-cp311-cp311-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for net_mesh-0.25.0-cp311-cp311-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 187e4776df03be863b9aaded835a38595b1ad821e606057a25aea8992328360c
MD5 a5e7cbdb053313bfa9f236825b8c5b45
BLAKE2b-256 9b0d96408c6d781bd60527bb8bac3fe5aa52be5ad24fbddbc1b72aff58d944d4

See more details on using hashes here.

Provenance

The following attestation bundles were made for net_mesh-0.25.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.25.0-cp310-cp310-win_amd64.whl.

File metadata

  • Download URL: net_mesh-0.25.0-cp310-cp310-win_amd64.whl
  • Upload date:
  • Size: 4.1 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.25.0-cp310-cp310-win_amd64.whl
Algorithm Hash digest
SHA256 1d129c183407754114c3f9ec8f06c77a6da1149fb08d8a4d8fc1a2b8b7803086
MD5 656e4ab19da77e2d65f5b01a2cd4e71b
BLAKE2b-256 76ec16e0c0e7b4b7f99ab79b6a14e6d338238129d5a176949e108617dbb2ac5b

See more details on using hashes here.

Provenance

The following attestation bundles were made for net_mesh-0.25.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.25.0-cp310-cp310-manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for net_mesh-0.25.0-cp310-cp310-manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 fef09b5caf580c2f7a62190662c1b90b2becdbb4a3c950f96e04cf1aca57345e
MD5 3abe0c92582c785fd739c4f29646f57b
BLAKE2b-256 aeee51d0ff90f998babf94e9a2e600e539c74ce4a70b9960ef771dbc3d0624d9

See more details on using hashes here.

Provenance

The following attestation bundles were made for net_mesh-0.25.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.25.0-cp310-cp310-manylinux_2_28_aarch64.whl.

File metadata

File hashes

Hashes for net_mesh-0.25.0-cp310-cp310-manylinux_2_28_aarch64.whl
Algorithm Hash digest
SHA256 bee88b5d0123b095aecf6405910517608ae800ad38e1aa3df9d54e9ddcde1b5c
MD5 316f3e6552596f4cdb8dfb401d867f62
BLAKE2b-256 40c324b1a23bb60795c4d8def811c4d9e8941a1e020166db02fe61d5b56cf938

See more details on using hashes here.

Provenance

The following attestation bundles were made for net_mesh-0.25.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