Skip to main content

TonIO

TonIO is a multi-threaded async runtime for free-threaded Python, built in Rust on top of the mio crate, and inspired by tinyio, trio and tokio.

Warning: TonIO is currently a work in progress and in alpha state. The APIs are subtle to breaking changes.

Note: TonIO is available on free-threaded Python and Unix systems only.

TonIO supports both using yield and the more canonical async/await notations, with the latter being available as part of the tonio.colored module. Following code snippets show both the usages.

Warning: despite the fact TonIO supports async and await notations, it's not compatible with any asyncio object like futures and tasks. The TonIO-Monkey project provides patches for some popular asyncio packages.

In a nutshell

yield syntax

import tonio

def wait_and_add(x: int) -> int:
    yield tonio.sleep(1)
    return x + 1

def foo():
    four, five = yield tonio.spawn(
        wait_and_add(3), 
        wait_and_add(4)
    )
    return four, five

out = tonio.run(foo())
assert out == (4, 5)

await syntax

import tonio.colored as tonio

async def wait_and_add(x: int) -> int:
    await tonio.sleep(1)
    return x + 1

async def foo():
    four, five = await tonio.spawn(
        wait_and_add(3), 
        wait_and_add(4)
    )
    return four, five

out = tonio.run(foo())
assert out == (4, 5)

Usage

Entrypoint

Every TonIO program consist of an entrypoint, which should be passed to the run method:

yield syntax

import tonio

def main():
    yield
    print("Hello world")

tonio.run(main())

await syntax

import tonio.colored as tonio

async def main():
    await tonio.yield_now()
    print("Hellow world")

tonio.run(main())

TonIO also provides a main decorator, thus we can rewrite the previous example as:

yield syntax

import tonio

@tonio.main
def main():
    yield
    print("Hello world")

main()

await syntax

import tonio.colored as tonio

@tonio.main
async def main():
    await tonio.yield_now()
    print("Hello world")

main()

Note: as you can see the colored module provides the additional yield_now coroutine, a quick way to define a suspension point, given you cannot just yield as in the non-colored notation.

Note: both run and main can only be called once per program. To run the runtime multiple times in the same program, follow the section below.

Manually managing the runtime

TonIO also provides the runtime function, to manually manage the runtime lifecycle:

import tonio

def _run1():
    ...

async def _run2():
    ...

def main():
    runtime = tonio.runtime()
    runtime.run_until_complete(_run1())
    runtime.run_until_complete(_run2())

Runtime options

The run, main and runtime methods accept options, specifically:

option name description default
context enable contextvars usage in coroutines False
signals list of signals to listen to
threads Number of runtime threads # of CPU cores
blocking_threadpool_size Maximum number of blocking threads 128
blocking_threadpool_idle_ttl Idle timeout for blocking threads (in seconds) 30

Events

The core object in TonIO is Event. It's basically a wrapper around an atomic boolean flag, initialised with False. Event provides the following methods:

  • is_set(): return the value of the flag
  • set(): set the flag to True
  • clear(): set the flag to False
  • wait(timeout=None): returns a coroutine you can yield on that unblocks when the flag is set to True or the timeout expires. Timeout is in seconds.

yield syntax

import tonio

@tonio.main
def main():
    event = tonio.Event()

    def setter():
        yield tonio.sleep(1)
        event.set()

    tonio.spawn(setter())
    yield event.wait()

await syntax

import tonio.colored as tonio

@tonio.main
async def main():
    event = tonio.Event()

    async def setter():
        await tonio.sleep(1)
        event.set()

    tonio.spawn(setter())
    await event.wait()

Spawning tasks

TonIO provides the spawn method to schedule new coroutines onto the runtime:

yield syntax

import tonio

def doubv(v):
    yield
    return v * 2

@tonio.main
def main():
    parallel = tonio.spawn(doubv(2), doubv(3))
    v3 = yield doubv(4)
    v1, v2 = yield parallel
    print([v1, v2, v3])

await syntax

import tonio.colored as tonio

async def doubv(v):
    await tonio.yield_now()
    return v * 2

@tonio.main
async def main():
    parallel = tonio.spawn(doubv(2), doubv(3))
    v3 = await doubv(4)
    v1, v2 = await parallel
    print([v1, v2, v3])

Coroutines passed to spawn get schedule onto the runtime immediately. Using yield or await on the return value of spawn just waits for the coroutines to complete and retreive the results.

Blocking tasks

TonIO provides the spawn_blocking method to schedule blocking operations onto the runtime:

yield syntax

import tonio

def read_file(path):
    with open(file, "r") as f:
        return f.read()

@tonio.main
def main():
    file_data = yield tonio.spawn_blocking(
        read_file, 
        "sometext.txt"
    )

await syntax

import tonio.colored as tonio

def read_file(path):
    with open(file, "r") as f:
        return f.read()

@tonio.main
async def main():
    file_data = await tonio.spawn_blocking(
        read_file, 
        "sometext.txt"
    )

Running tasks from synchronous contexts

TonIO provides the block_on method to spawn coroutines from a synchronous context. It works the same way of spawn, except it accepts a single coroutine and it blocks the current thread until the coroutine is completed.

Warning: using block_on from within a coroutine might produce a runtime deadlock.

Map utilities

TonIO provides the map and map_blocking utilities to spawn the same operation with an iterable of parameters:

yield syntax

import tonio

accum = []

def task(no):
    yield tonio.sleep(0.5)
    accum.append(no * 2)

@tonio.main
def main():
    yield tonio.map(task, range(4))

await syntax

import tonio.colored as tonio

accum = []

async def task(no):
    await tonio.sleep(0.5)
    accum.append(no * 2)

@tonio.main
async def main():
    await tonio.map(task, range(4))

Completion-based iterators

TonIO provides the as_completed utility to iterate over task results based on completion order:

yield syntax

import tonio

def _sleep(v):
    yield tonio.sleep(v)
    return v

@tonio.main
def main():
    vals = []
    for task in tonio.as_completed(
        _sleep(0.5),
        _sleep(0.1),
        _sleep(0.3),
    ):
        vals.append(yield task)

await syntax

import tonio.colored as tonio

async def _sleep(v):
    await tonio.sleep(v)
    return v

@tonio.main
async def main():
    vals = []
    async for val in tonio.as_completed(
        _sleep(0.5),
        _sleep(0.1),
        _sleep(0.3),
    ):
        vals.append(val)

Scopes and cancellations

TonIO provides a scope context, that lets you cancel work spawned within it:

yield syntax

import tonio

def slow_push(target, sleep):
    yield tonio.sleep(sleep)
    target.append(True)

@tonio.main
def main():
    values = []
    with tonio.scope() as scope:
        scope.spawn(_slow_push(values, 0.1))
        scope.spawn(_slow_push(values, 2))
        yield tonio.sleep(0.2)
        scope.cancel()
    yield scope()
    assert len(values) == 1

await syntax

import tonio.colored as tonio

async def slow_push(target, sleep):
    await tonio.sleep(sleep)
    target.append(True)

@tonio.main
async def main():
    values = []
    async with tonio.scope() as scope:
        scope.spawn(_slow_push(values, 0.1))
        scope.spawn(_slow_push(values, 2))
        await tonio.sleep(0.2)
        scope.cancel()
    assert len(values) == 1

When you yield on the scope, it will wait for all the spawned coroutines to end. If the scope was canceled, then all the pending coroutines will be canceled.

Note: as you can see, the colored version of scope doesn't require to be awaited, as it will yield when exiting the context.

Select first completing task

TonIO also provides a select utility to cancel remaining work on the first completing task:

yield syntax

import tonio

def slow_push(target, sleep):
    yield tonio.sleep(sleep)
    target.append(True)

@tonio.main
def main():
    values = []
    yield tonio.select(
        _slow_push(values, 0.1),
        _slow_push(values, 2)
    )
    assert len(values) == 1

await syntax

import tonio.colored as tonio

async def slow_push(target, sleep):
    await tonio.sleep(sleep)
    target.append(True)

@tonio.main
async def main():
    values = []
    await tonio.select(
        _slow_push(values, 0.1),
        _slow_push(values, 2)
    )
    assert len(values) == 1

Time-related functions

  • tonio.time.time(): a function returning the runtime's clock (in seconds, microsecond resolution)
  • tonio.time.sleep(delay): a coroutine you can yield on to sleep (delay is in seconds)
  • tonio.time.timeout(coro, timeout): a coroutine you can yield on returning a tuple (output, success). If the coroutine succeeds in the given time then the pair (output, True) is returned. Otherwise this will return (None, False).

Note: time.sleep is also exported to the main tonio module.

Note: all of the above functions are also present in tonio.colored.time module.

Scheduling work

TonIO provides the time.interval function to create interval objects you can yield on a scheduled basis:

yield syntax

import tonio
from tonio import time

def some_task():
    ...

def scheduler():
    interval = time.interval(1)
    while True:
        yield interval.tick()
        tonio.spawn(some_task())

@tonio.main
def main():
    tonio.spawn(scheduler())
    # do some other work

await syntax

import tonio.colored as tonio
from tonio.colored import time

async def some_task():
    ...

async def scheduler():
    interval = time.interval(1)
    while True:
        await interval.tick()
        tonio.spawn(some_task())

@tonio.main
async def main():
    tonio.spawn(scheduler())
    # do some other work

The interval method first argument is the interval in seconds resolution, and the method also accepts an optional at argument, to delay the first execution at a specific time (from the runtime's clock perspective):

from tonio import time

# tick every 500ms, with the first tick happening in 5 seconds from now
interval = time.interval(0.5, time.time() + 5)

Synchronization primitives

Synchronization primitives are exposed in the tonio.sync module.

Lock

Implements a classic mutex, or a non-reentrant, single-owner lock for coroutines:

yield syntax

import tonio
from tonio import sync

@tonio.main
def main():
    # counter can't go above 1
    counter = 0

    def _count(lock):
        nonlocal counter
        with (yield lock()):
            counter += 1
            yield
            counter -= 1
    
    lock = sync.Lock()
    yield tonio.spawn(*[
        _count(lock)
        for _ in range(10)
    ])

await syntax

import tonio.colored as tonio
from tonio.colored import sync

@tonio.main
async def main():
    # counter can't go above 1
    counter = 0

    async def _count(lock):
        nonlocal counter
        async with lock:
            counter += 1
            await tonio.yield_now()
            counter -= 1
    
    lock = sync.Lock()
    await tonio.spawn(*[
        _count(lock)
        for _ in range(10)
    ])

The Lock object also implements an or_raise method, that will immediately fail when the lock cannot be acquired:

from tonio.exceptions import WouldBlock

try:
    with lock.or_raise():
        ...
except WouldBlock:
    ...

Semaphore

A semaphore for coroutines:

yield syntax

import tonio
from tonio import sync

@tonio.main
def main():
    # counter can't go above 2
    counter = 0

    def _count(semaphore):
        nonlocal counter
        with (yield semaphore()):
            counter += 1
            yield
            counter -= 1
    
    semaphore = sync.Semaphore(2)
    yield tonio.spawn(*[
        _count(semaphore)
        for _ in range(10)
    ])

await syntax

import tonio.colored as tonio
from tonio.colored import sync

@tonio.main
async def main():
    # counter can't go above 2
    counter = 0

    async def _count(semaphore):
        nonlocal counter
        async with semaphore:
            counter += 1
            await tonio.yield_now()
            counter -= 1
    
    semaphore = sync.Semaphore(2)
    await tonio.spawn(*[
        _count(semaphore)
        for _ in range(10)
    ])

As for locks, the Semaphore object also implements an or_raise method, that will immediately fail when the lock cannot be acquired:

from tonio.exceptions import WouldBlock

try:
    with semaphore.or_raise():
        ...
except WouldBlock:
    ...

The Semaphore object also implements a tokens method, that returns the number of available tokens.

Barrier

A barrier for coroutines:

yield syntax

import tonio
from tonio import sync

@tonio.main
def main():
    barrier = sync.Barrier(3)
    count = 0

    def _start_at_3():
        nonlocal count
        count += 1
        i = yield barrier.wait()
        assert count == 3
        return i

    yield tonio.spawn(*[
        _start_at_3()
        for _ in range(3)
    ])

await syntax

import tonio.colored as tonio
from tonio.colored import sync

@tonio.main
async def main():
    barrier = sync.Barrier(3)
    count = 0

    async def _start_at_3():
        nonlocal count
        count += 1
        i = await barrier.wait()
        assert count == 3
        return i

    await tonio.spawn(*[
        _start_at_3()
        for _ in range(3)
    ])

The Barrier object also implements a value method, which returns the current value of the barrier.

Channels

Multi-producer multi-consumer channels for inter-coroutine communication.

The tonio.sync.channel module provides both a channel and an unbounded constructors.
The main difference between bounded and unbounded channels, as the names suggest, is that while the first will suspend sending messages once the specified length is reached, and it will resume accepting messages once the existing buffer is consumed, the latter will always accept new messages. That's also why, the sender part of a bounded channel is async, while in the unbounded is not.

Bounded channel

yield syntax

import tonio
from tonio import sync
from tonio.sync import channel

def producer(sender, barrier, offset):
    for i in range(20):
        message = offset + 1
        yield sender.send(message)
    yield barrier.wait()

def consumer(receiver):
    while True:
        try:
            message = yield receiver.receive()
            print(message)
        except Exception:
            break

@tonio.main
def main():
    def close(sender, barrier):
        yield barrier.wait()
        sender.close()

    sender, receiver = channel.channel(2)
    barrier = sync.Barrier(3)
    yield tonio.spawn(*[
        producer(sender, barrier, 100),
        producer(sender, barrier, 200),
        consumer(receiver),
        consumer(receiver),
        consumer(receiver),
        consumer(receiver),
        close(sender, barrier),
    ])

await syntax

import tonio.colored as tonio
from tonio.colored import sync
from tonio.colored.sync import channel

async def producer(sender, barrier, offset):
    for i in range(20):
        message = offset + 1
        await sender.send(message)
    await barrier.wait()

async def consumer(receiver):
    while True:
        try:
            message = await receiver.receive()
            print(message)
        except Exception:
            break

@tonio.main
async def main():
    async def close(sender, barrier):
        await barrier.wait()
        sender.close()

    sender, receiver = channel.channel(2)
    barrier = sync.Barrier(3)
    await tonio.spawn(*[
        producer(sender, barrier, 100),
        producer(sender, barrier, 200),
        consumer(receiver),
        consumer(receiver),
        consumer(receiver),
        consumer(receiver),
        close(sender, barrier),
    ])
Unbounded channel

yield syntax

import tonio
from tonio import sync
from tonio.sync import channel

def producer(sender, barrier, offset):
    for i in range(20):
        message = offset + 1
        sender.send(message)
    yield barrier.wait()

def consumer(receiver):
    while True:
        try:
            message = yield receiver.receive()
            print(message)
        except Exception:
            break

@tonio.main
def main():
    def close(sender, barrier):
        yield barrier.wait()
        sender.close()

    sender, receiver = channel.unbounded()
    barrier = sync.Barrier(3)
    yield tonio.spawn(*[
        producer(sender, barrier, 100),
        producer(sender, barrier, 200),
        consumer(receiver),
        consumer(receiver),
        consumer(receiver),
        consumer(receiver),
        close(sender, barrier),
    ])

await syntax

import tonio.colored as tonio
from tonio.colored import sync
from tonio.colored.sync import channel

async def producer(sender, barrier, offset):
    for i in range(20):
        message = offset + 1
        sender.send(message)
    await barrier.wait()

async def consumer(receiver):
    while True:
        try:
            message = await receiver.receive()
            print(message)
        except Exception:
            break

@tonio.main
async def main():
    async def close(sender, barrier):
        await barrier.wait()
        sender.close()

    sender, receiver = channel.unbounded()
    barrier = sync.Barrier(3)
    await tonio.spawn(*[
        producer(sender, barrier, 100),
        producer(sender, barrier, 200),
        consumer(receiver),
        consumer(receiver),
        consumer(receiver),
        consumer(receiver),
        close(sender, barrier),
    ])

Network module

Network primitives are exposed under the tonio.net module.

Streams

The high-level network primitives in TonIO are centered aroud the SocketStream and SocketListener objects.

The SocketListener object implements an accept coroutine which returns a SocketStream object.
The SocketStream object implements the send_all and receive_some coroutines to send and receive data.
Both objects implement a close method to shutdown the underlying socket.

You can create and interact with the above objects using some high-level helpers in the net module, specifically:

  • open_tcp_stream: a coroutine to open a SocketStream connected to a TCP endpoint
  • open_unix_socket: a coroutine to open a SocketStream connected to a Unix socket
  • open_tcp_listeners: a coroutine to initialise SocketListener objects
  • open_unix_listener: a coroutine to initialise a SocketListener on a Unix socket path
  • serve_listeners: a coroutine to spawn SocketListener accept loops targeting a handler
  • serve_tcp: a coroutine that joins open_tcp_listeners and serve_listeners in one call
  • serve_unix: a coroutine that joins open_unix_listener and serve_listeners in one call

yield syntax

from tonio.net import open_tcp_stream, serve_tcp

def server():
    yield serve_tcp(
        server_handle, 
        host='127.0.0.1', 
        port=8000
    )

def server_handle(stream):
    # receive some data
    data = yield stream.receive_some()

def client():
    stream = yield open_tcp_stream(
        host='127.0.0.1', 
        port=8000
    )
    # send some data
    yield stream.send_all("message")

await syntax

from tonio.colored.net import open_tcp_stream, serve_tcp

async def server():
    await serve_tcp(
        server_handle, 
        host='127.0.0.1', 
        port=8000
    )

async def server_handle(stream):
    # receive some data
    data = await stream.receive_some()

async def client():
    stream = await open_tcp_stream(
        host='127.0.0.1', 
        port=8000
    )
    # send some data
    await stream.send_all("message")

Unix domain sockets use the same objects, with serve_unix and open_unix_socket:

yield syntax

from tonio.net import open_unix_socket, serve_unix

def server():
    yield serve_unix(
        server_handle, 
        '/tmp/app.sock', 
        mode=0o600
    )

def client():
    stream = yield open_unix_socket(
        '/tmp/app.sock'
    )
    yield stream.send_all("message")

await syntax

from tonio.colored.net import open_unix_socket, serve_unix

async def server():
    await serve_unix(
        server_handle, 
        '/tmp/app.sock', 
        mode=0o600
    )

async def client():
    stream = await open_unix_socket(
        '/tmp/app.sock'
    )
    await stream.send_all("message")

TLS streams

TonIO implement TLS wrappers around the streaming APIs through primitives in the tonio.net.tls module.

TonIO provides the TLSStream and TLSListener object wrappers and the following high-level helpers:

  • open_tls_over_tcp_stream: a coroutine to open a TLSStream wrapping a TCP SocketStream
  • open_tls_over_tcp_listeners: a coroutine to initialise TLSListener objects
  • serve_tls_over_tcp: a coroutine that joins open_tls_over_tcp_listeners and serve_listeners in one call

Low-level sockets

The tonio.net.socket module provides TonIO's basic low-level networking API.
Generally, the API exposed by this module mirrors the standard library socket module.

TonIO socket objects are overall very similar to the standard library socket objects, with the main difference being that blocking methods become coroutines.

yield syntax

import tonio
from tonio.net import socket

def server():
    sock = socket.socket()
    with sock:
        yield sock.bind(('127.0.0.1', 8000))
        sock.listen()

        while True:
            client, _ = yield sock.accept()
            tonio.spawn(server_handle(client))

def server_handle(connection):
    with connection:
        # receive some data
        data = yield connection.recv(4096)

def client():
    sock = socket.socket()
    with sock:
        yield sock.connect(('127.0.0.1', 8000))
        yield sock.send("message")

await syntax

import tonio.colored as tonio
from tonio.colored.net import socket

async def server():
    sock = socket.socket()
    with sock:
        await sock.bind(('127.0.0.1', 8000))
        sock.listen()

        while True:
            client, _ = await sock.accept()
            tonio.spawn(server_handle(client))

async def server_handle(connection):
    with connection:
        # receive some data
        data = await connection.recv(4096)

async def client():
    sock = socket.socket()
    with sock:
        await sock.connect(('127.0.0.1', 8000))
        await sock.send("message")

Filesystem module

TonIO's fs module exposes async API for filesystem operations (that are run in the blocking thread-pool). It provides open, a Path class mirroring pathlib.Path, and wrap_file to adopt an already-open file object.

yield syntax

import tonio
import tonio.fs as fs

def main():
    f = yield fs.open('data.txt', 'w')
    yield f.write('hello')
    yield f.close()

    path = fs.Path('data.txt')
    if (yield path.exists()):
        print((yield path.read_text()))

    for entry in (yield fs.Path('.').iterdir()):
        print(entry.name)

await syntax

import tonio.colored as tonio
import tonio.colored.fs as fs

async def main():
    async with await fs.open('data.txt', 'w') as f:
        await f.write('hello')

    path = fs.Path('data.txt')
    if await path.exists():
        print(await path.read_text())

    for entry in await fs.Path('.').iterdir():
        print(entry.name)

Operations that touch the filesystem are asynchronous; everything else stays synchronous.

Note: methods returning several paths (iterdir, glob, rglob, walk) are resolved in a single hop and give back a list. Since walk is fully materialised, mutating its dirnames does not prune the traversal, unlike pathlib.Path.walk.

Reading a file line by line differs between the two flavours. The await syntax supports async for and async with, neither of which the yield syntax can express:

yield syntax

def read_lines(path):
    f = yield fs.open(path, 'r')
    try:
        while True:
            line = yield f.readline()
            if not line:
                break
            print(line)
    finally:
        yield f.close()

await syntax

async def read_lines(path):
    async with await fs.open(path, 'r') as f:
        async for line in f:
            print(line)

Subprocesses

TonIO exposes two coroutines to run child processes: run_process for the common "run it and collect the outcome" case, and open_process for interacting with a process while it runs. Both spawn the process on the blocking thread-pool.

run_process returns a subprocess.CompletedProcess and accepts:

  • stdin: bytes to feed to the child (defaults to b'', meaning "close stdin immediately"), or a file descriptor/subprocess constant
  • capture_stdout / capture_stderr: when true, the relevant stream is collected and available on the result
  • check: when true (the default), a non-zero exit code raises subprocess.CalledProcessError

Any other keyword argument is forwarded to subprocess.Popen.

yield syntax

import tonio

def main():
    result = yield tonio.run_process(
        ['echo', 'hello'],
        capture_stdout=True
    )
    print(result.returncode)
    print(result.stdout)

await syntax

import tonio.colored as tonio

async def main():
    result = await tonio.run_process(
        ['echo', 'hello'],
        capture_stdout=True
    )
    print(result.returncode)
    print(result.stdout)

open_process returns a Process object instead, giving access to the running child. Passing subprocess.PIPE for stdin, stdout or stderr exposes the corresponding pipe as a stream on the process object, implementing the same send_all and receive_some coroutines of network streams:

yield syntax

import subprocess
import tonio

def main():
    proc = yield tonio.open_process(
        ['cat'],
        stdin=subprocess.PIPE,
        stdout=subprocess.PIPE
    )
    yield proc.stdin.send_all(b'hello')
    proc.stdin.close()
    data = yield proc.stdout.receive_some()
    code = yield proc.wait()

await syntax

import subprocess
import tonio.colored as tonio

async def main():
    proc = await tonio.open_process(
        ['cat'],
        stdin=subprocess.PIPE,
        stdout=subprocess.PIPE
    )
    await proc.stdin.send_all(b'hello')
    proc.stdin.close()
    data = await proc.stdout.receive_some()
    code = await proc.wait()

The Process object exposes:

  • args and pid: the command and the process identifier
  • stdin, stdout, stderr: the piped streams, or None when not piped
  • stdio: a (stdin, stdout) tuple, when both are piped
  • returncode and poll(): the exit code, or None while the process is still running
  • wait: a coroutine waiting for the process to exit, returning its exit code
  • send_signal, terminate, kill: synchronous methods to signal the process

Note: unlike run_process, open_process does not reap the child for you: remember to wait on it — possibly after a kill — otherwise the child outlives your task.

Note: processes in TonIO only communicate over unbuffered byte streams: the universal_newlines, text, encoding, errors and bufsize options of subprocess are not supported.

Signals

TonIO provides a context manager to catch signals.

The usage of such context manager requires to first configure the runtime to listen for such signals:

yield syntax

import signal
import tonio
from tonio.time import interval

def sig_handle():
    with tonio.signal_receiver(
        signal.SIGHUP, 
        signal.SIGUSR1
    ) as sigs:
        for ev in sigs:
            sig = yield ev
            if sig == signal.SIGHUP:
                ...

@tonio.main(
    signals=[signal.SIGHUP, signal.SIGUSR1]
)
def main():
    tonio.spawn(sig_handle())
    ticker = interval(1)
    while True:
        yield ticker.tick()

await syntax

import signal
import tonio.colored as tonio
from tonio.colored.time import interval

async def sig_handle():
    with tonio.signal_receiver(
        signal.SIGHUP, 
        signal.SIGUSR1
    ) as sigs:
        async for sig in sigs:
            if sig == signal.SIGHUP:
                ...

@tonio.main(
    signals=[signal.SIGHUP, signal.SIGUSR1]
)
async def main():
    tonio.spawn(sig_handle())
    ticker = interval(1)
    while True:
        await ticker.tick()

Testing

TonIO ships with a pytest plugin, which runs tests marked with the tonio marker on the runtime:

yield syntax

import pytest
import tonio

@pytest.mark.tonio
def test_sleep():
    yield tonio.sleep(0.1)

await syntax

import pytest
import tonio.colored as tonio

@pytest.mark.tonio
async def test_sleep():
    await tonio.sleep(0.1)

The marker can also be applied at module level with pytestmark = pytest.mark.tonio, or at class level.

To avoid marking tests entirely, the plugin also provides an auto mode, in which every async test gets run on the TonIO runtime. Auto mode can be enabled with the tonio_mode option in the pytest configuration:

[tool.pytest.ini_options]
tonio_mode = 'auto'

Async fixtures

For asynchronous fixtures where setup and teardown are required, the two syntaxes differ.

await syntax

Async fixtures involved in TonIO tests run on the runtime. Coroutine fixtures simply return their value, while async generator fixtures can yield it and run teardown code after the yield:

import pytest
from tonio.colored.net import open_tcp_stream

@pytest.fixture
async def connection():
    stream = await open_tcp_stream(host='127.0.0.1', port=8000)
    yield stream
    stream.close()
yield syntax

Given non-colored TonIO coroutines are indistinguishable from standard pytest generator fixtures, the plugin never runs generator fixtures on the runtime. This is usually not a limitation: since yield syntax tests already run as coroutines, simple setup can just happen within the test itself:

import pytest
from tonio.net import open_tcp_stream

def _connect():
    stream = yield open_tcp_stream(host='127.0.0.1', port=8000)
    return stream

@pytest.mark.tonio
def test_conn():
    stream = yield _connect()
    yield stream.send_all(b'ping')

When an actual teardown is required, the plugin provides the tonio_run fixture, which runs the given coroutine on the runtime:

@pytest.fixture
def connection(tonio_run):
    stream = tonio_run(_connect())

    def _disconnect():
        yield stream.send_all(b'bye')
        stream.close()

    yield stream
    tonio_run(_disconnect())

Runtime configuration in pytest

The TonIO runtime is always initialised once per test session, with context enabled and 2 threads. Runtime options can be customized overriding the session-scoped tonio_runtime_options fixture, for example in conftest.py:

import pytest

@pytest.fixture(scope='session')
def tonio_runtime_options():
    return {'threads': 4}

The runtime object itself is available to tests and fixtures via the session-scoped tonio_runtime fixture.

Libraries built on TonIO

In addition to the patches provided by the TonIO-Monkey project, the following libraries target TonIO natively:

License

TonIO is released under the BSD License.

Metadata

Release files for tonio 0.9.15

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for tonio 0.9.15
File Size Uploaded
tonio-0.9.15.tar.gz 94.4 kB Details

Built distributions (wheels)

Table of built distributions (wheels) for tonio 0.9.15
File
tonio-0.9.15-cp315-cp315t-musllinux_1_1_x86_64.whl CPython 3.15 CPython 3.15 free-threading Linux musl 1.1+ x86-64 Details
tonio-0.9.15-cp315-cp315t-musllinux_1_1_armv7l.whl CPython 3.15 CPython 3.15 free-threading Linux musl 1.1+ ARMv7l Details
tonio-0.9.15-cp315-cp315t-musllinux_1_1_aarch64.whl CPython 3.15 CPython 3.15 free-threading Linux musl 1.1+ ARM64 Details
tonio-0.9.15-cp315-cp315t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl CPython 3.15 CPython 3.15 free-threading Linux glibc 2.17+ x86-64 Details
tonio-0.9.15-cp315-cp315t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl CPython 3.15 CPython 3.15 free-threading Linux glibc 2.17+ ARMv7l Details
tonio-0.9.15-cp315-cp315t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl CPython 3.15 CPython 3.15 free-threading Linux glibc 2.17+ ARM64 Details
tonio-0.9.15-cp315-cp315t-manylinux_2_12_i686.manylinux2010_i686.whl CPython 3.15 CPython 3.15 free-threading Linux glibc 2.12+ x86-32 Details
tonio-0.9.15-cp315-cp315t-macosx_11_0_arm64.whl CPython 3.15 CPython 3.15 free-threading macOS 11.0+ ARM64 Details
tonio-0.9.15-cp315-cp315t-macosx_10_12_x86_64.whl CPython 3.15 CPython 3.15 free-threading macOS 10.12+ x86-64 Details
tonio-0.9.15-cp314-cp314t-musllinux_1_1_x86_64.whl CPython 3.14 CPython 3.14 free-threading Linux musl 1.1+ x86-64 Details
tonio-0.9.15-cp314-cp314t-musllinux_1_1_armv7l.whl CPython 3.14 CPython 3.14 free-threading Linux musl 1.1+ ARMv7l Details
tonio-0.9.15-cp314-cp314t-musllinux_1_1_aarch64.whl CPython 3.14 CPython 3.14 free-threading Linux musl 1.1+ ARM64 Details
tonio-0.9.15-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl CPython 3.14 CPython 3.14 free-threading Linux glibc 2.17+ x86-64 Details
tonio-0.9.15-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl CPython 3.14 CPython 3.14 free-threading Linux glibc 2.17+ ARMv7l Details
tonio-0.9.15-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl CPython 3.14 CPython 3.14 free-threading Linux glibc 2.17+ ARM64 Details
tonio-0.9.15-cp314-cp314t-manylinux_2_12_i686.manylinux2010_i686.whl CPython 3.14 CPython 3.14 free-threading Linux glibc 2.12+ x86-32 Details
tonio-0.9.15-cp314-cp314t-macosx_11_0_arm64.whl CPython 3.14 CPython 3.14 free-threading macOS 11.0+ ARM64 Details
tonio-0.9.15-cp314-cp314t-macosx_10_12_x86_64.whl CPython 3.14 CPython 3.14 free-threading macOS 10.12+ x86-64 Details

Total release size: 8.9 MB

Release files / tonio-0.9.15.tar.gz

Download URL tonio-0.9.15.tar.gz
Size 94.4 kB
Tags Source
SHA-256 checksum
How to use checksums
d97291b745df02333925e2949d1f8fd0222c9de6de090e3ea4c18e21b3b1369c
BLAKE2b-256 checksum
How to use checksums
80f71adf29183af10a8e9527f0fa73975b31bfa269b4f9117697ca577f646c1a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 5, 2026.

Transparency log

Release files / tonio-0.9.15-cp315-cp315t-musllinux_1_1_x86_64.whl

Download URL tonio-0.9.15-cp315-cp315t-musllinux_1_1_x86_64.whl
Size 639.9 kB
Tags CPython 3.15 CPython 3.15 free-threading Linux musl 1.1+ x86-64
SHA-256 checksum
How to use checksums
651e37185b9cf67d3baa29f092ba6a1a2cef630384238142f26e867e34b03449
BLAKE2b-256 checksum
How to use checksums
38328c1322f0586bcd8f8d4fe3fd1907dc7b18b368c507d98cfc242393f72189
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 5, 2026.

Transparency log

Release files / tonio-0.9.15-cp315-cp315t-musllinux_1_1_armv7l.whl

Download URL tonio-0.9.15-cp315-cp315t-musllinux_1_1_armv7l.whl
Size 699.2 kB
Tags CPython 3.15 CPython 3.15 free-threading Linux musl 1.1+ ARMv7l
SHA-256 checksum
How to use checksums
5faca4068b50c720b31532883705581a6eace8d56d530c4ccf7f8d494ed7111c
BLAKE2b-256 checksum
How to use checksums
89a9771c8aa1a321ca08ca3840542c61b59ebb864fe287e00110f91fdaca265c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 5, 2026.

Transparency log

Release files / tonio-0.9.15-cp315-cp315t-musllinux_1_1_aarch64.whl

Download URL tonio-0.9.15-cp315-cp315t-musllinux_1_1_aarch64.whl
Size 589.2 kB
Tags CPython 3.15 CPython 3.15 free-threading Linux musl 1.1+ ARM64
SHA-256 checksum
How to use checksums
f8a4b9ecf7196c19cb40a61b1e12e3e2a48593db49b4cade047709dfa7f9181b
BLAKE2b-256 checksum
How to use checksums
265f3524c725846589e6e1a76f5193f2a01c78a16df71d75501f13f4ce9ed9c1
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 5, 2026.

Transparency log

Release files / tonio-0.9.15-cp315-cp315t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl

Download URL tonio-0.9.15-cp315-cp315t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Size 426.0 kB
Tags CPython 3.15 CPython 3.15 free-threading Linux glibc 2.17+ x86-64
SHA-256 checksum
How to use checksums
d68b2ae29267616f3014ea257144e44ab8edb61087ea60f669eab30c755cd979
BLAKE2b-256 checksum
How to use checksums
6ec69c808af3b93349687ab86a8fed0a76f5e6697d26e464c67a7677955b0ede
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 5, 2026.

Transparency log

Release files / tonio-0.9.15-cp315-cp315t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl

Download URL tonio-0.9.15-cp315-cp315t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl
Size 421.3 kB
Tags CPython 3.15 CPython 3.15 free-threading Linux glibc 2.17+ ARMv7l
SHA-256 checksum
How to use checksums
1c4cbf3b77df509d4b2769e9c910ef5ac962d0390c4f32db90feef6930b3919f
BLAKE2b-256 checksum
How to use checksums
48d238d727e9c0a222b873a11ae3cbe22cc3b6cc421ded03c4a61b9074b5ca06
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 5, 2026.

Transparency log

Release files / tonio-0.9.15-cp315-cp315t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl

Download URL tonio-0.9.15-cp315-cp315t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Size 410.2 kB
Tags CPython 3.15 CPython 3.15 free-threading Linux glibc 2.17+ ARM64
SHA-256 checksum
How to use checksums
30910e461794c31e24d8f00b4df4936c65a3b394820bb2afa460e7f42c9db370
BLAKE2b-256 checksum
How to use checksums
f0cfe8dc8bf85c733442f7b6fc7a710794bdc0295b4e7a47efe29edfdb7df078
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 5, 2026.

Transparency log

Release files / tonio-0.9.15-cp315-cp315t-manylinux_2_12_i686.manylinux2010_i686.whl

Download URL tonio-0.9.15-cp315-cp315t-manylinux_2_12_i686.manylinux2010_i686.whl
Size 449.6 kB
Tags CPython 3.15 CPython 3.15 free-threading Linux glibc 2.12+ x86-32
SHA-256 checksum
How to use checksums
af65c2c139c99779e1ecaeeab371b63c5eedb6fd386c14652578fd270a8fd394
BLAKE2b-256 checksum
How to use checksums
ca6805fa6cd9c710deff0a1c65d5bf1d44f48241785fa7a085a20383f88958cf
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 5, 2026.

Transparency log

Release files / tonio-0.9.15-cp315-cp315t-macosx_11_0_arm64.whl

Download URL tonio-0.9.15-cp315-cp315t-macosx_11_0_arm64.whl
Size 367.6 kB
Tags CPython 3.15 CPython 3.15 free-threading macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
65103293e19733199f1be7786833c24016ba5acf07ecf2eaa66a6519cfd757bd
BLAKE2b-256 checksum
How to use checksums
988455c9892fee100555f063473d0d71c0dd2113939b11942ce744eadf2327c1
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 5, 2026.

Transparency log

Release files / tonio-0.9.15-cp315-cp315t-macosx_10_12_x86_64.whl

Download URL tonio-0.9.15-cp315-cp315t-macosx_10_12_x86_64.whl
Size 387.7 kB
Tags CPython 3.15 CPython 3.15 free-threading macOS 10.12+ x86-64
SHA-256 checksum
How to use checksums
09953fd098b26001bc5530db1c5cbcaf554e13b34c21dc7de31cbdfd303747d6
BLAKE2b-256 checksum
How to use checksums
93961058764013103e1f1521f2f9c7370cabae878c877d7646d5507729313537
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 5, 2026.

Transparency log

Release files / tonio-0.9.15-cp314-cp314t-musllinux_1_1_x86_64.whl

Download URL tonio-0.9.15-cp314-cp314t-musllinux_1_1_x86_64.whl
Size 640.1 kB
Tags CPython 3.14 CPython 3.14 free-threading Linux musl 1.1+ x86-64
SHA-256 checksum
How to use checksums
2a34e4c2c078d124972ba410a56768fa51eaf9786e48786c0b06ed315c50fab8
BLAKE2b-256 checksum
How to use checksums
eaef4a0ac5ec0638652d5a04f5db95573665849a4c1da1f25cb23e20ecdf346b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 5, 2026.

Transparency log

Release files / tonio-0.9.15-cp314-cp314t-musllinux_1_1_armv7l.whl

Download URL tonio-0.9.15-cp314-cp314t-musllinux_1_1_armv7l.whl
Size 699.0 kB
Tags CPython 3.14 CPython 3.14 free-threading Linux musl 1.1+ ARMv7l
SHA-256 checksum
How to use checksums
96393bf5b85b631a4d9300c184bc5cc5c8b36861253d5d3d5a1bba3042e7a1f7
BLAKE2b-256 checksum
How to use checksums
9c1094c3554e7d9843d323d85f0342e3def1b93b93d4b9aefb5113142d15b461
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 5, 2026.

Transparency log

Release files / tonio-0.9.15-cp314-cp314t-musllinux_1_1_aarch64.whl

Download URL tonio-0.9.15-cp314-cp314t-musllinux_1_1_aarch64.whl
Size 589.2 kB
Tags CPython 3.14 CPython 3.14 free-threading Linux musl 1.1+ ARM64
SHA-256 checksum
How to use checksums
2a9a2f001dfc555fce63b1c89b5b66b8ba2f12bb4f8a555e6acbe0b606f7a678
BLAKE2b-256 checksum
How to use checksums
14038880aaebfdffca7af69bb1dc1ad634b44093d2c7b0791eb9d257488dd935
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 5, 2026.

Transparency log

Release files / tonio-0.9.15-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl

Download URL tonio-0.9.15-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Size 426.1 kB
Tags CPython 3.14 CPython 3.14 free-threading Linux glibc 2.17+ x86-64
SHA-256 checksum
How to use checksums
9ace88c61852a7f97b40daa90b87a7473f36ca7e8d490ab9fbc001a77b1d4461
BLAKE2b-256 checksum
How to use checksums
c2506e8978a0d3aa30ef9df05f26005ef9934d37bf25cd8f1e8e303a887b5acf
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 5, 2026.

Transparency log

Release files / tonio-0.9.15-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl

Download URL tonio-0.9.15-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl
Size 421.1 kB
Tags CPython 3.14 CPython 3.14 free-threading Linux glibc 2.17+ ARMv7l
SHA-256 checksum
How to use checksums
6348f48ff0bcf787cf64384a50f4ad90ab387ce3b39b9f51cfb4e8453f1e4280
BLAKE2b-256 checksum
How to use checksums
0ea488120f606ab0f990e433af442a3d6689e84046550c828b76a0a144ab06cf
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 5, 2026.

Transparency log

Release files / tonio-0.9.15-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl

Download URL tonio-0.9.15-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Size 410.3 kB
Tags CPython 3.14 CPython 3.14 free-threading Linux glibc 2.17+ ARM64
SHA-256 checksum
How to use checksums
f159b13c2c080ad8d90a235cf3f9ad44eff3eb7790a1a87ed8479651d9e9c64e
BLAKE2b-256 checksum
How to use checksums
a3770e87ff72a887ac2e39a236e02fe1976c851f6f4fc823964296dd9657d795
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 5, 2026.

Transparency log

Release files / tonio-0.9.15-cp314-cp314t-manylinux_2_12_i686.manylinux2010_i686.whl

Download URL tonio-0.9.15-cp314-cp314t-manylinux_2_12_i686.manylinux2010_i686.whl
Size 449.4 kB
Tags CPython 3.14 CPython 3.14 free-threading Linux glibc 2.12+ x86-32
SHA-256 checksum
How to use checksums
0d9d0e542f1d0c4bddaafb5524961afb18c1f3aa2c80a6a82595eb716f621af8
BLAKE2b-256 checksum
How to use checksums
ba81514c73abc7d1779a31e8084cefde54a80a0ffdc4d8ce24515d530b134ceb
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 5, 2026.

Transparency log

Release files / tonio-0.9.15-cp314-cp314t-macosx_11_0_arm64.whl

Download URL tonio-0.9.15-cp314-cp314t-macosx_11_0_arm64.whl
Size 367.6 kB
Tags CPython 3.14 CPython 3.14 free-threading macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
6af181c0874c8382e343d710ba8dbf819b8a3c9c25314edf30de42bde2f20ad9
BLAKE2b-256 checksum
How to use checksums
5f8bf30b35da455eb8bdb90e2f1adbd706801c6497cae29a66bc03e2e22fda69
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 5, 2026.

Transparency log

Release files / tonio-0.9.15-cp314-cp314t-macosx_10_12_x86_64.whl

Download URL tonio-0.9.15-cp314-cp314t-macosx_10_12_x86_64.whl
Size 387.9 kB
Tags CPython 3.14 CPython 3.14 free-threading macOS 10.12+ x86-64
SHA-256 checksum
How to use checksums
63d97638e14acd139f6f6a3b367e0ab0a4f3086b73df5dc6f84910bce177c4c3
BLAKE2b-256 checksum
How to use checksums
e1a10388a25813fbeeeaee47fd84903837ee78c690aeba62b3d7f6502b23c563
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 5, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.9.15 This release

19 release files

0.9.9

19 release files

0.9.8

19 release files

0.9.7

19 release files

0.9.2

19 release files

0.9.1

19 release files

0.9.0

19 release files

0.8.3

19 release files

0.8.2

19 release files

0.8.1

19 release files

0.8.0

19 release files

0.7.2

19 release files

0.7.0

19 release files

0.3.0

19 release files

0.2.1

19 release files

0.1.0

19 release files

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