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()

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.

Download files

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

Source Distribution

tonio-0.9.2.tar.gz (89.0 kB view details)

Uploaded Source

Built Distributions

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

tonio-0.9.2-cp315-cp315t-musllinux_1_1_x86_64.whl (630.5 kB view details)

Uploaded CPython 3.15tmusllinux: musl 1.1+ x86-64

tonio-0.9.2-cp315-cp315t-musllinux_1_1_armv7l.whl (693.7 kB view details)

Uploaded CPython 3.15tmusllinux: musl 1.1+ ARMv7l

tonio-0.9.2-cp315-cp315t-musllinux_1_1_aarch64.whl (580.1 kB view details)

Uploaded CPython 3.15tmusllinux: musl 1.1+ ARM64

tonio-0.9.2-cp315-cp315t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (416.8 kB view details)

Uploaded CPython 3.15tmanylinux: glibc 2.17+ x86-64

tonio-0.9.2-cp315-cp315t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl (417.4 kB view details)

Uploaded CPython 3.15tmanylinux: glibc 2.17+ ARMv7l

tonio-0.9.2-cp315-cp315t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (402.6 kB view details)

Uploaded CPython 3.15tmanylinux: glibc 2.17+ ARM64

tonio-0.9.2-cp315-cp315t-manylinux_2_12_i686.manylinux2010_i686.whl (444.7 kB view details)

Uploaded CPython 3.15tmanylinux: glibc 2.12+ i686

tonio-0.9.2-cp315-cp315t-macosx_11_0_arm64.whl (364.0 kB view details)

Uploaded CPython 3.15tmacOS 11.0+ ARM64

tonio-0.9.2-cp315-cp315t-macosx_10_12_x86_64.whl (384.4 kB view details)

Uploaded CPython 3.15tmacOS 10.12+ x86-64

tonio-0.9.2-cp314-cp314t-musllinux_1_1_x86_64.whl (630.7 kB view details)

Uploaded CPython 3.14tmusllinux: musl 1.1+ x86-64

tonio-0.9.2-cp314-cp314t-musllinux_1_1_armv7l.whl (693.5 kB view details)

Uploaded CPython 3.14tmusllinux: musl 1.1+ ARMv7l

tonio-0.9.2-cp314-cp314t-musllinux_1_1_aarch64.whl (580.3 kB view details)

Uploaded CPython 3.14tmusllinux: musl 1.1+ ARM64

tonio-0.9.2-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (416.8 kB view details)

Uploaded CPython 3.14tmanylinux: glibc 2.17+ x86-64

tonio-0.9.2-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl (417.1 kB view details)

Uploaded CPython 3.14tmanylinux: glibc 2.17+ ARMv7l

tonio-0.9.2-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (402.8 kB view details)

Uploaded CPython 3.14tmanylinux: glibc 2.17+ ARM64

tonio-0.9.2-cp314-cp314t-manylinux_2_12_i686.manylinux2010_i686.whl (444.5 kB view details)

Uploaded CPython 3.14tmanylinux: glibc 2.12+ i686

tonio-0.9.2-cp314-cp314t-macosx_11_0_arm64.whl (364.1 kB view details)

Uploaded CPython 3.14tmacOS 11.0+ ARM64

tonio-0.9.2-cp314-cp314t-macosx_10_12_x86_64.whl (384.5 kB view details)

Uploaded CPython 3.14tmacOS 10.12+ x86-64

File details

Details for the file tonio-0.9.2.tar.gz.

File metadata

  • Download URL: tonio-0.9.2.tar.gz
  • Upload date:
  • Size: 89.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for tonio-0.9.2.tar.gz
Algorithm Hash digest
SHA256 b1e004929104828ceb4c1e96ee4b8e8b29e34e3d0aede6377f82c0be625b69da
MD5 feb9352111d2d1a9ad1265789510cfdb
BLAKE2b-256 13f6045eb7ae9f164ed3fe2a8aa9180fc6dd8bac4c684a0ab3af4c89f2a05a39

See more details on using hashes here.

Provenance

The following attestation bundles were made for tonio-0.9.2.tar.gz:

Publisher: release.yml on gi0baro/tonio

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

File details

Details for the file tonio-0.9.2-cp315-cp315t-musllinux_1_1_x86_64.whl.

File metadata

File hashes

Hashes for tonio-0.9.2-cp315-cp315t-musllinux_1_1_x86_64.whl
Algorithm Hash digest
SHA256 aca55ecc4486a8584752e941ee762dcd1a296e6f061b69d4206403bafcd3eaf5
MD5 e49eea9fd9fa1e15ea29962a73ea29e0
BLAKE2b-256 743822c5bf1b4ae22c2ca18aaa473bcbff02a82bc5634d4ba166d879f30001a3

See more details on using hashes here.

Provenance

The following attestation bundles were made for tonio-0.9.2-cp315-cp315t-musllinux_1_1_x86_64.whl:

Publisher: release.yml on gi0baro/tonio

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

File details

Details for the file tonio-0.9.2-cp315-cp315t-musllinux_1_1_armv7l.whl.

File metadata

File hashes

Hashes for tonio-0.9.2-cp315-cp315t-musllinux_1_1_armv7l.whl
Algorithm Hash digest
SHA256 7662a9900a54488f6e9bc6ea01a90b650e3a444c83d6e8baf64b149431a3032f
MD5 a52fd85fd0513394149a8e37fc5ceb84
BLAKE2b-256 8bd05bf48f34a21d9896b8e3e568a2acace97851744fedf27addacce45687956

See more details on using hashes here.

Provenance

The following attestation bundles were made for tonio-0.9.2-cp315-cp315t-musllinux_1_1_armv7l.whl:

Publisher: release.yml on gi0baro/tonio

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

File details

Details for the file tonio-0.9.2-cp315-cp315t-musllinux_1_1_aarch64.whl.

File metadata

File hashes

Hashes for tonio-0.9.2-cp315-cp315t-musllinux_1_1_aarch64.whl
Algorithm Hash digest
SHA256 3e777ac85730d9c691ae2ae5369cbefe4350a4cd0b97e93b17c6386d81e52b8f
MD5 f69c5be54854e6cf3df6559c769934e1
BLAKE2b-256 46752e0bf9c016f20d3a4a3e33e563b1d07b0e5381d1ba38e571acb6138e9b59

See more details on using hashes here.

Provenance

The following attestation bundles were made for tonio-0.9.2-cp315-cp315t-musllinux_1_1_aarch64.whl:

Publisher: release.yml on gi0baro/tonio

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

File details

Details for the file tonio-0.9.2-cp315-cp315t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for tonio-0.9.2-cp315-cp315t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 64b5ac46f82a95524bdcd4eb2235ba558ee6be0ef0882cd08d1dfa8fc76506fa
MD5 58a5a733744940586232a3c384ecd528
BLAKE2b-256 02a2c88da9c5a5bf92190cbc1d6bce3f413d16513f35c7d2b68d093e7a8e2133

See more details on using hashes here.

Provenance

The following attestation bundles were made for tonio-0.9.2-cp315-cp315t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:

Publisher: release.yml on gi0baro/tonio

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

File details

Details for the file tonio-0.9.2-cp315-cp315t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl.

File metadata

File hashes

Hashes for tonio-0.9.2-cp315-cp315t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl
Algorithm Hash digest
SHA256 e73d519f7ad79f1eafb06e837c6b54c4f7281449af32c2792546210c839067a7
MD5 f45e3d6a186944627b5651cc36241f6d
BLAKE2b-256 69090a9a2b23d2f35e66b93801add8f0e2932baa03b0581d5d91c969b85c27b1

See more details on using hashes here.

Provenance

The following attestation bundles were made for tonio-0.9.2-cp315-cp315t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl:

Publisher: release.yml on gi0baro/tonio

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

File details

Details for the file tonio-0.9.2-cp315-cp315t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for tonio-0.9.2-cp315-cp315t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 06c78a70a31ad346740b0ee6335cdb3f41af8789505815cc7a65ac5419adb04a
MD5 a98f695fd3039427aac21092f0637833
BLAKE2b-256 d13745793492ded4d86a78c9ad102f413eac49fed94f5615252a1e50daddb042

See more details on using hashes here.

Provenance

The following attestation bundles were made for tonio-0.9.2-cp315-cp315t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl:

Publisher: release.yml on gi0baro/tonio

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

File details

Details for the file tonio-0.9.2-cp315-cp315t-manylinux_2_12_i686.manylinux2010_i686.whl.

File metadata

File hashes

Hashes for tonio-0.9.2-cp315-cp315t-manylinux_2_12_i686.manylinux2010_i686.whl
Algorithm Hash digest
SHA256 ef68d80be783a609a3f82160e0926c69b9f70934d8b93f49ebe56d1fc5c74b7e
MD5 aff5e3d7f54697bf9afc21d583e3f85a
BLAKE2b-256 90500f7b29bda5bca6e97db1ebce20997182744290d0a95e9369cf0a28c0f998

See more details on using hashes here.

Provenance

The following attestation bundles were made for tonio-0.9.2-cp315-cp315t-manylinux_2_12_i686.manylinux2010_i686.whl:

Publisher: release.yml on gi0baro/tonio

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

File details

Details for the file tonio-0.9.2-cp315-cp315t-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for tonio-0.9.2-cp315-cp315t-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 627f5005976b0edf7d88098c86096686492b8a70b38d5ab19f5582d538d053cd
MD5 a80c7e58d17015c62e2bc2879ae634ab
BLAKE2b-256 266c900f99303cd8190c5473ac2da50d7cd535ed6deef7f0ef7c8334cd0de94f

See more details on using hashes here.

Provenance

The following attestation bundles were made for tonio-0.9.2-cp315-cp315t-macosx_11_0_arm64.whl:

Publisher: release.yml on gi0baro/tonio

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

File details

Details for the file tonio-0.9.2-cp315-cp315t-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for tonio-0.9.2-cp315-cp315t-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 412da64ab73b6b115c1ae446b8ed95b2003f7832e152bc94078d333a80ba515f
MD5 f71a05592f68dac4f7a3cd50f01fa095
BLAKE2b-256 e92613023af8c2100d2da6288e9c8bf2cef57709daca1c1fdc8adff142b37924

See more details on using hashes here.

Provenance

The following attestation bundles were made for tonio-0.9.2-cp315-cp315t-macosx_10_12_x86_64.whl:

Publisher: release.yml on gi0baro/tonio

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

File details

Details for the file tonio-0.9.2-cp314-cp314t-musllinux_1_1_x86_64.whl.

File metadata

File hashes

Hashes for tonio-0.9.2-cp314-cp314t-musllinux_1_1_x86_64.whl
Algorithm Hash digest
SHA256 e85999a529dbd2d98f81aef163b561df59fc48061592507b85956ea477634b2a
MD5 71fd85dadf26280e18e4bb7d18037d4c
BLAKE2b-256 e9cf6bd8a5f87c842fed3192fab10b798f3440f7d6f18548be6a44ba242323a4

See more details on using hashes here.

Provenance

The following attestation bundles were made for tonio-0.9.2-cp314-cp314t-musllinux_1_1_x86_64.whl:

Publisher: release.yml on gi0baro/tonio

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

File details

Details for the file tonio-0.9.2-cp314-cp314t-musllinux_1_1_armv7l.whl.

File metadata

File hashes

Hashes for tonio-0.9.2-cp314-cp314t-musllinux_1_1_armv7l.whl
Algorithm Hash digest
SHA256 6348b233ef9f2a40c90a27a6fe43481fceec25e3771cfd3e15366e92573017e5
MD5 0fcfd76832dfebf6e2a5ed8210d375c7
BLAKE2b-256 5a6dd33c9775273ce47fdf58f23a69fe444cdfb01a62cf2889336094b69edee0

See more details on using hashes here.

Provenance

The following attestation bundles were made for tonio-0.9.2-cp314-cp314t-musllinux_1_1_armv7l.whl:

Publisher: release.yml on gi0baro/tonio

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

File details

Details for the file tonio-0.9.2-cp314-cp314t-musllinux_1_1_aarch64.whl.

File metadata

File hashes

Hashes for tonio-0.9.2-cp314-cp314t-musllinux_1_1_aarch64.whl
Algorithm Hash digest
SHA256 e0b6190cc5045251cb6344cd1b8ffaf4dbe83ddaece9f462ccd1a9cc8c93651b
MD5 3f6450d4d3b9714466b6c1f8f7951b36
BLAKE2b-256 7c9abc72e31e3a33e9368d9614a2557bba75108f2eff33b4ea2d3b4451483173

See more details on using hashes here.

Provenance

The following attestation bundles were made for tonio-0.9.2-cp314-cp314t-musllinux_1_1_aarch64.whl:

Publisher: release.yml on gi0baro/tonio

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

File details

Details for the file tonio-0.9.2-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for tonio-0.9.2-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 720b3bb2fcd89a3febd3ecda0998935c877985bd6cdebdb3b4191450914f08c7
MD5 3dfa919b4fe3edb67930dd2f70afb5ea
BLAKE2b-256 2dab9066af671048423be881c62e1e18534553bfdccabc844bfcacdf1d1a4974

See more details on using hashes here.

Provenance

The following attestation bundles were made for tonio-0.9.2-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:

Publisher: release.yml on gi0baro/tonio

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

File details

Details for the file tonio-0.9.2-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl.

File metadata

File hashes

Hashes for tonio-0.9.2-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl
Algorithm Hash digest
SHA256 371377bd326f52dfe1fb4420e40ddeafa13d143124250ed0beab0505ccbe0fd7
MD5 d4c160a5fb1e3f6faae7a0506d3ec3d1
BLAKE2b-256 7e7b21e1c46375030109712e4ed667eccc61c767833af4ae2ffc3cb3933f6b68

See more details on using hashes here.

Provenance

The following attestation bundles were made for tonio-0.9.2-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl:

Publisher: release.yml on gi0baro/tonio

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

File details

Details for the file tonio-0.9.2-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for tonio-0.9.2-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 8f3069f384c9e2d9429c8cad93a2988df83a725c1efbec3c4f55689324197fb8
MD5 26b2f5e339b5005caa406053244909a4
BLAKE2b-256 c2b3566274454bd70179d6a3581c6d49148e54e34f269b90c25fddbcdd5729f3

See more details on using hashes here.

Provenance

The following attestation bundles were made for tonio-0.9.2-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl:

Publisher: release.yml on gi0baro/tonio

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

File details

Details for the file tonio-0.9.2-cp314-cp314t-manylinux_2_12_i686.manylinux2010_i686.whl.

File metadata

File hashes

Hashes for tonio-0.9.2-cp314-cp314t-manylinux_2_12_i686.manylinux2010_i686.whl
Algorithm Hash digest
SHA256 febaf9e2a6f655fa97a5a7bfe3c7d2f09d94801c21d062bb6a9153ec6e03311c
MD5 fa38659630b72e735357dad21bd2a89e
BLAKE2b-256 e4fff38eae5fc2e41eb958fc32a156bab252a85c9a3899ed08d390e74b4d6d61

See more details on using hashes here.

Provenance

The following attestation bundles were made for tonio-0.9.2-cp314-cp314t-manylinux_2_12_i686.manylinux2010_i686.whl:

Publisher: release.yml on gi0baro/tonio

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

File details

Details for the file tonio-0.9.2-cp314-cp314t-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for tonio-0.9.2-cp314-cp314t-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 db158160ef884bcc67b81310c677dc1e8125aa1010c121e7bf230ec487881063
MD5 16a9317637524e8bab89b9ef5a3d3ecb
BLAKE2b-256 5cf36d8c3a2e09c1ecc2becf85ceccd307227626b503b2c2500bc6c7b63f24f1

See more details on using hashes here.

Provenance

The following attestation bundles were made for tonio-0.9.2-cp314-cp314t-macosx_11_0_arm64.whl:

Publisher: release.yml on gi0baro/tonio

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

File details

Details for the file tonio-0.9.2-cp314-cp314t-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for tonio-0.9.2-cp314-cp314t-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 71a0b1bf5305ef3d0dd3ee465e17df31a5229e6ccd7fe27e3e02f964be870359
MD5 0e239489c2b0e8e3cf8f68e8cabf822b
BLAKE2b-256 986a7e6cf6fe30191003dda8595a53bd8aabdd3dc48c3ec1a569d351e0b6e914

See more details on using hashes here.

Provenance

The following attestation bundles were made for tonio-0.9.2-cp314-cp314t-macosx_10_12_x86_64.whl:

Publisher: release.yml on gi0baro/tonio

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 Sentry Error logging StatusPage Status page