-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
finishing notifcation docs and restrucutre imports a but
- Loading branch information
1 parent
f85d9e8
commit c0652a8
Showing
11 changed files
with
217 additions
and
9 deletions.
There are no files selected for viewing
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -30,7 +30,7 @@ Key Features: | |
|
||
|
||
.. toctree:: | ||
:maxdepth: 2 | ||
:maxdepth: 3 | ||
:caption: Contents: | ||
|
||
design | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,179 @@ | ||
.. _notifications: | ||
|
||
|
||
############## | ||
============= | ||
Notifications | ||
############## | ||
============= | ||
|
||
|
||
Overview | ||
--------- | ||
|
||
Notifications in ExEngine provide a powerful mechanism for asynchronous communication between the Execution and user code. They allow devices, events, and other components to broadcast updates about their status or important occurrences. This enables reactive programming patterns, allowing your software to respond dynamically to changes in the system state or experimental conditions. | ||
|
||
Notifications can serve several purposes: | ||
|
||
- Inform about the completion of asynchronous operations (i.e. those occuring on a different thread) | ||
- Alert about changes in device states | ||
- Communicate errors or warnings | ||
- Provide updates on the progress of long-running tasks | ||
|
||
|
||
|
||
Anatomy of a Notification | ||
^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
||
Notifications in ExEngine are instances of classes derived from the base ``Notification`` class. Each notification has several components: | ||
|
||
1. **Category**: Defined by the ``NotificationCategory`` enum, this indicates the broad type of the notification (``Event``, ``Data``, ``Storage``, or ``Device``). | ||
|
||
2. **Description**: A string providing a explanation of what the notification represents. | ||
|
||
3. **Payload**: An optional piece of data associated with the notification, whose type depends on the particular notification. | ||
|
||
4. **Timestamp**: Automatically set to the time the notification was created. | ||
|
||
|
||
Built-in Notification Types | ||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
||
ExEngine provides built-in notification types, such as: | ||
|
||
1. ``EventExecutedNotification``: Posted when an ExecutionEvent completes. Its payload is None, or an Exception if the event didn't complete successfully | ||
|
||
2. ``DataStoredNotification``: Posted when data is stored by a Storage object. Its payload is the ``DataCoordinates`` of the stored data. | ||
|
||
|
||
|
||
Subscribing to Notifications | ||
---------------------------- | ||
|
||
To subscribe to notifications from ExEngine, you can use the ``subscribe_to_notifications`` method of the ``ExecutionEngine`` instance: | ||
|
||
.. code-block:: python | ||
from exengine import ExecutionEngine | ||
def notification_handler(notification): | ||
print(f'Got Notification: time {notification.timestamp} and payload {notification.payload}') | ||
engine = ExecutionEngine.get_instance() | ||
engine.subscribe_to_notifications(notification_handler) | ||
# When finished, unsubscribe | ||
engine.unsubscribe_from_notifications(notification_handler) | ||
Your ``notification_handler`` function will be called each time a new notification is posted. Since there may be many notifications produced by the ``ExecutionEngine``, these handler functions should not contain code that takes a long time to run. | ||
|
||
|
||
Filtering Subscriptions | ||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
||
You can filter notifications by type (i.e. a specific notification subclass) or category when subscribing, so that the handler function only gets called for a subset of notifications | ||
|
||
.. code-block:: python | ||
# Subscribe to a specific notification type | ||
# SpecificNotificationClass should be a subclass of exengine.base_classes.Notification | ||
engine.subscribe_to_notifications(handler, SpecificNotificationClass) | ||
# Subscribe to notifications of a specific category | ||
from exengine.kernel.notification_base import NotificationCategory | ||
engine.subscribe_to_notifications(handler, NotificationCategory.Data) | ||
Multiple subscriptions with different filters can be set up: | ||
|
||
.. code-block:: python | ||
engine.subscribe_to_notifications(handler1, NotificationA) | ||
engine.subscribe_to_notifications(handler2, NotificationCategory.Device) | ||
engine.subscribe_to_notifications(handler3) # No filter, receives all notifications | ||
Determining Available Notifications | ||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
||
``ExecutorEvents`` declare the types of notifications they might emit through the ``notification_types`` class attribute. This attribute is a list of Notification types that the event may produce during its execution. | ||
|
||
To discover which notification types are supported by a particular event: | ||
|
||
.. code-block:: python | ||
print(MyEvent.notification_types) | ||
All ExecutorEvents include the ``EventExecutedNotification`` by default. Subclasses can add their additional custom types of notifications. | ||
|
||
|
||
|
||
Awaiting Notifications from a Future | ||
------------------------------------ | ||
|
||
Notifications can be awaited on an :ref:`ExecutionFuture <futures>` in addition to subscribing to ExEngine notifications. This is useful for waiting on specific conditions related to a particular ``ExecutorEvent``: | ||
|
||
.. code-block:: python | ||
future = engine.submit(some_event) | ||
notification = future.await_notification(SomeSpecificNotification) | ||
The Future tracks all notifications for its event. If called after a notification occurs, it returns immediately. | ||
|
||
|
||
|
||
Publishing Notifications | ||
------------------------- | ||
|
||
Events can emit notifications using the ``publish_notification`` method: | ||
|
||
.. code-block:: python | ||
class MyEvent(ExecutorEvent): | ||
notification_types = [MyCustomNotification] | ||
def execute(self): | ||
# ... do something ... | ||
self.publish_notification(MyCustomNotification(payload="Something happened")) | ||
Creating Custom Notifications | ||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
||
To create a custom notification: | ||
|
||
1. Subclass ``exengine.base_classes.Notification`` | ||
2. Use Python's ``@dataclass`` decorator | ||
3. Define ``category`` (from ``exengine.notifications.NotificationCategory`` enum) and ``description`` (string) as class variables | ||
4. Optionally, specify a payload type using a type hint in the class inheritance. For example, ``class MyCustomNotification(Notification[str])`` indicates this notification's payload will be a string. | ||
|
||
Keep payloads lightweight for efficient processing. Example: | ||
|
||
.. code-block:: python | ||
from dataclasses import dataclass | ||
from exengine.base_classes import Notification | ||
from exengine.notifications import NotificationCategory | ||
@dataclass | ||
class MyCustomNotification(Notification[str]): | ||
category = NotificationCategory.Device | ||
description = "A custom device status update" | ||
# Usage | ||
notification = MyCustomNotification(payload="Device XYZ is ready") | ||
Notifications provide a mechanism for asynchronous communication within the system. They allow devices, events, and other components to broadcast updates about their status or important occurrences. This feature enables reactive programming patterns, allowing your software to respond dynamically to changes in the system state or experimental conditions. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
from .kernel.notification_base import Notification | ||
from .kernel.ex_event_base import ExecutorEvent |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
# src/exengine/integration_tests/test_imports.py | ||
|
||
import pytest | ||
|
||
|
||
def test_import_engine(): | ||
try: | ||
from exengine import ExecutionEngine | ||
except ImportError as e: | ||
pytest.fail(f"Import failed for ExecutionEngine: {e}") | ||
|
||
def test_import_base_classes(): | ||
try: | ||
from exengine.base_classes import Notification, ExecutorEvent | ||
except ImportError as e: | ||
pytest.fail(f"Import failed for base_classes: {e}") | ||
|
||
def test_import_notifications(): | ||
try: | ||
from exengine.notifications import NotificationCategory, DataStoredNotification, EventExecutedNotification | ||
except ImportError as e: | ||
pytest.fail(f"Import failed for notifications: {e}") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
from .notification_base import NotificationCategory, Notification | ||
from .ex_event_base import ExecutorEvent, EventExecutedNotification |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
""" | ||
Convenience file for imports | ||
""" | ||
from .kernel.notification_base import NotificationCategory | ||
from .kernel.notification_base import EventExecutedNotification, DataStoredNotification |