Skip to main content

Asyncraft: Simple event/message passing library with asyncio and threading support

A simple event/message passing library for Python 3.8+ supporting asyncio and threading.
For examples, see the examples directory.

Installation

pip install asyncraft

Messages

Messages are the first major part of the Asyncraft library. They are used to send data between different parts of the program. Keys are used for identifying handlers, which should process the given message. Further, Asyncraft supports messages with multiple keys.

import asyncraft
...
# Create a message
message = asyncraft.Message(key='key', value='value')
# Broadcast the message (threadsafe)
asyncraft.broadcast(message)
...

Handlers

The second major part of the Asyncraft library are handlers. Handlers are used for processing messages. They can be synchronous or asynchronous. Synchronous handlers are executed in a separate thread, while asynchronous handlers are executed in an asyncio event loop.

import asyncraft
from asyncraft.handler import SyncHandler, AsyncHandler
...
# Create a sync handler with decorator.
# All sync handlers will be executed in a separate thread of a thread pool.
@asyncraft.asyncraft_handler(keys=["key"])
def handler_0(message):
    print(message)
    #Handlers can return a message
    return asyncraft.Message(key='key1', value='value1')
...

# Create an async handler with decorator
# All async handlers will be executed in an asyncio event loop.
@asyncraft.asyncraft_handler(keys=["key"])
async def handler_1(message):
    print(message)
...

# Create a sync handler without decorator
# First define the callback function
def handler_2_function(message):
    print(message)
#Then create the handler
handler = SyncHandler(keys=["key"], callback=handler_2_function)
#Register the handler
asyncraft.register_handler(handler)

...

# Create an async handler without decorator
#First again define the callback function
async def handler_3_function(message):
    print(message)
#Then create the handler
handler = AsyncHandler(keys=["key"], callback=handler_3_function)
#Register the handler
asyncraft.register_handler(handler)
...

Queues

Another major part of Asyncraft are queues. Queues listen to keys and store messages before they are processed further.

from asyncraft import MessageQueue
from asyncraft import Message
import asyncraft
...
#Create a queue which listenes to keys 'Key' and 'Key1'.
#All messages with at least one of those keys will be stored in the queue.
queue = MessageQueue(["Key", "Key1"])
#Register the queue
asyncraft.register_queue(queue)
...
#Get the next message from the queue. If the queue is empty, block until a message is available.
message: Message = queue.get(blocking=True)
...
#Get the next message from the queue in an async context. If the queue is empty, block until a message is available.
message: Message = queue.async_get(blocking=True) 
...

Broadcast and wait for response

The broadcast_and_wait function can be used to send a message and wait for a response.

import asyncraft
from asyncraft import Message
...
# Create a message
message = Message(key='key', value='value')
# Broadcast the message and wait for a response.
# The response will be the first message with the key 'key1' that is received.
# If no response is received within 10 seconds, None will be returned.
response: Message = asyncraft.broadcast_and_wait(message,["key1"], timeout=10)

Examples

The following examples demonstrate how to use Asyncraft.

Ping-Pong

This example demonstrates how to use Asyncraft to create a simple ping-pong system.

import asyncio
import time
import asyncraft


@asyncraft.asyncraft_handler(keys=["Ping"])
def ping_handler_function(message):
    """This is a sync handler that will respond to the Pong handler. It will be executed in a separate thread."""
    print(f"Received {message.key} with value {message.value}")
    time.sleep(1)
    return asyncraft.Message("Pong", message.value + 1)


@asyncraft.asyncraft_handler(keys=["Pong"])
async def pong_handler_function(message):
    """This is an async handler that will respond to the Ping handler. It will be executed in the event loop."""
    print(f"Received {message.key} with value {message.value}")
    await asyncio.sleep(1)
    return asyncraft.Message("Ping", message.value + 1)


async def main():
    asyncraft.broadcast(asyncraft.Message("Ping", 0))
    while True:
        #print("Tick...")
        await asyncio.sleep(1)


if __name__ == "__main__":
    asyncraft.start(main())

Queue

This example demonstrates how to use the MessageQueue class and how one can use it to read and write messages.

import asyncio
import time
import asyncraft
from asyncraft.queues import MessageQueue


async def async_reader(queue: MessageQueue):
    """This function will read messages asynchronously."""
    while True:
        message = await queue.async_get(blocking=True)
        print(f"Reading async {message.key} with value {message.value}")
        await asyncio.sleep(0.1)


def reader(queue: MessageQueue):
    """This function will read messages in another thread."""
    while True:
        message = queue.get(blocking=True)
        print(f"Reading threaded {message.key} with value {message.value}")
        time.sleep(0.1)


async def async_producer():
    """This function will produce messages asynchronously."""
    while True:
        print("Async Producing...")
        asyncraft.broadcast(asyncraft.Message("Key1", "From async producer"))
        await asyncio.sleep(1)


def producer():
    """This function will produce messages synchronously."""
    while True:
        print("Threaded Producing...")
        asyncraft.broadcast(asyncraft.Message("Key", "From thread producer"))
        time.sleep(1)


async def main():
    await asyncio.gather(
        async_reader(queue),
        async_producer(),
        asyncio.to_thread(reader, queue),
        asyncio.to_thread(producer)
    )


if __name__ == "__main__":
    queue = MessageQueue(["Key", "Key1"])
    asyncraft.register_queue(queue)
    asyncraft.start(main())

License

This project is licensed under the terms of the MIT license.

Metadata

Release files for asyncraft 0.0.3

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

Source distribution (sdist)

Source distribution for asyncraft 0.0.3
File Size Uploaded Provenance
asyncraft-0.0.3.tar.gz 9.2 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for asyncraft 0.0.3
File Interpreter ABI Platform
asyncraft-0.0.3-py3-none-any.whl Python 3 none any Details

Total release size: 17.6 kB

Release files / asyncraft-0.0.3.tar.gz

Download URL asyncraft-0.0.3.tar.gz
Size 9.2 kB
Tags Source
SHA-256 checksum
How to use checksums
b274e362821959fd95d8316d1dd51ebfe7b3b270ab48faba90e69d6db5de08e4
BLAKE2b-256 checksum
How to use checksums
f9f07c209b55fbf833fa616e259e3253c0d448b5f6e7e1ac607996c31c026ef6
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/5.0.0 CPython/3.12.3

Release files / asyncraft-0.0.3-py3-none-any.whl

Download URL asyncraft-0.0.3-py3-none-any.whl
Size 8.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
5e70c10a1d7fed9b22375143b864767ab8836f3b71ccd3a01d018a6cb837f120
BLAKE2b-256 checksum
How to use checksums
6267e4d8d63152e5dcb91356d8d4ca04e16242b91d23b2efbc65cf44b089e770
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/5.0.0 CPython/3.12.3

Security for asyncraft 0.0.3

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.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

Release history Release notifications | RSS feed

This release

0.0.3 This release

2 release files No provenance

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