Simple event system working seamlessly across sockets
Project description
MrEventLoop
Simple event system for Python building on asyncio and working seamlessly across sockets.
Installation
pip install mreventloop
Emitting Events
from mreventloop import emits
@emits('events', [ 'produced' ])
class Producer:
def requestProduct(self):
self.events.produced('some product')
You can now connect a callback to the event:
from mreventloop import connect
producer = Producer()
connect(producer, 'produced', lambda product: print(f'{product}'))
You can disconnect all listeners from an event:
from mreventloop import disconnect
disconnect(producer, 'produced')
Event Loop and Slots
Objects can have an event loop building on asyncio:
from mreventloop import has_event_loop, slot
@has_event_loop('event_loop')
class Consumer:
@slot
def onProduced(self, product):
print(f'{product}')
Calling a @slot will not run the corresponding method directly,
but queue its execution on the object's event loop.
The event loop will run them strictly sequentially in FIFO order.
Thus, slots do not need to be reentrant.
The event loop has to be started:
consumer = Consumer()
connect(producer, 'produced', consumer, 'onProduced')
async with consumer.event_loop:
producer.requestProduct()
After exiting, the event loop will still process all queued events.
When creating an object that has_event_loop,
an event loop will automatically be created.
But you can also share event loops between objects:
producer1 = Producer()
producer2 = Producer()
consumer1 = Consumer()
consumer2 = Consumer()
consumer2.event_loop = consumer1.event_loop
connect(producer1, 'produced', consumer1, 'onProduced')
connect(producer2, 'produced', consumer2, 'onProduced')
async with consumer1.event_loop:
producer1.requestProduct()
producer2.requestProduct()
All calls to slots in both consumer1 and consumer2 will be run sequentially.
Async Slots
Slots can also be coroutines:
import asyncio
@has_event_loop('event_loop')
class ConsumerAsync:
@slot
async def onProduced(self, product):
await asyncio.sleep(0.1)
print(f'{product}')
The coroutine will be awaited inside the event loop.
Awaiting Events
Events can be awaited:
from mreventloop import SyncEvent
producer = Producer()
sync_event = SyncEvent(producer.events.produced)
async def emit():
producer.requestProduct()
asyncio.create_task(emit())
result = await sync_event
print(f'{result}')
Events of the Event Loop
The event loop itself emits the following events:
[ 'started', 'stopped', 'active', 'idle', 'exception' ]
Exceptions on the Event Loop
If an exception ocurrs executing a slot, the app will exit. This can be prevented by creating the loop manually with:
from mreventloop import EventLoop
consumer.event_loop = EventLoop(exit_on_exception = False)
In this case, any exception will be emitted through the exception event.
(The general idea here is to just not use exceptions.)
Crossing Sockets
Events and slots across multiple applications can be connected via sockets.
This requires one instance of a Broker and any number of Peers.
A Peer subscribes to a number of events.
If any other Peer publishes such events,
they will be emitted by the subscribing Peer.
from mreventloop import Broker, Peer
in_socket_path = 'ipc:///tmp/mreventloop_test_in.sock'
out_socket_path = 'ipc:///tmp/mreventloop_test_out.sock'
producer_peer = Peer(in_socket_path, out_socket_path, [ 'request_product' ], [ 'produced' ])
consumer_peer = Peer(in_socket_path, out_socket_path, [ 'produced' ], [ 'request_product' ])
async with Broker(in_socket_path, out_socket_path), producer_peer, consumer_peer:
consumer = Consumer()
connect(consumer, 'request_product', consumer_peer.publish, 'request_product')
connect(consumer_peer, 'product', consumer, 'onProduct')
producer = Producer()
connect(producer, 'produce', producer_peer.publish, 'produce')
connect(producer_peer, 'request_product', producer, 'onRequestProduct')
async with producer.event_loop, consumer.event_loop:
consumer.events.request_product()
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file MrEventLoop-0.7.1.tar.gz.
File metadata
- Download URL: MrEventLoop-0.7.1.tar.gz
- Upload date:
- Size: 15.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/4.0.2 CPython/3.11.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ba29f4848676e4d20a0196f1db241fd2c6665c8fc4b1d028d16801ed8a1688ab
|
|
| MD5 |
0d8a67f14b975f22279ee99d7c70bc17
|
|
| BLAKE2b-256 |
7aad4b4368923296ee68c524e1e9fac46022421b200a9c684bb734275517a6d9
|
File details
Details for the file MrEventLoop-0.7.1-py3-none-any.whl.
File metadata
- Download URL: MrEventLoop-0.7.1-py3-none-any.whl
- Upload date:
- Size: 18.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/4.0.2 CPython/3.11.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4048f76b36776a657911c8d78d3fd660d6abc12fa2d54126998125ddaf855be3
|
|
| MD5 |
00f60593069537d0155899659782f9ef
|
|
| BLAKE2b-256 |
32420bbd4932f001ee05d336603489fe0af6124559a8468f6b0d6c679960b8af
|