-
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.
finished futures/events/notifcations docs
- Loading branch information
1 parent
139be7f
commit 4d3030e
Showing
38 changed files
with
733 additions
and
316 deletions.
There are no files selected for viewing
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,89 @@ | ||
.. _add_events: | ||
|
||
Creating Custom Events | ||
======================= | ||
|
||
Basic Event Creation | ||
-------------------- | ||
|
||
To create a custom event: | ||
|
||
1. Subclass ``ExecutorEvent`` | ||
2. Implement the ``execute()`` method | ||
|
||
.. code-block:: python | ||
from exengine.base_classes import ExecutorEvent | ||
class MyCustomEvent(ExecutorEvent): | ||
def execute(self): | ||
# Main event logic goes here | ||
result = self.perform_operation() | ||
return result | ||
def perform_operation(self): | ||
# Implement your operation here | ||
pass | ||
Adding Notifications | ||
-------------------- | ||
|
||
To add notifications: | ||
|
||
1. Specify ``notification_types`` | ||
2. Use ``self.publish_notification()`` in ``execute()`` | ||
|
||
.. code-block:: python | ||
from exengine.notifications import MyCustomNotification | ||
class MyEventWithNotification(ExecutorEvent): | ||
notification_types = [MyCustomNotification] | ||
def execute(self): | ||
# Event logic | ||
self.publish_notification(MyCustomNotification(payload="Operation completed")) | ||
Implementing Capabilities | ||
------------------------- | ||
|
||
Data Producing Capability | ||
^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
||
For events that produce data: | ||
|
||
.. code-block:: python | ||
from exengine.base_classes import ExecutorEvent, DataProducing | ||
class MyDataProducingEvent(ExecutorEvent, DataProducing): | ||
def execute(self): | ||
data, metadata = self.generate_data() | ||
self.put_data(data_coordinates, data, metadata) | ||
def generate_data(self): | ||
# Generate your data here | ||
pass | ||
Stoppable Capability | ||
^^^^^^^^^^^^^^^^^^^^ | ||
|
||
For stoppable events: | ||
|
||
.. code-block:: python | ||
from exengine.base_classes import ExecutorEvent, Stoppable | ||
class MyStoppableEvent(ExecutorEvent, Stoppable): | ||
def execute(self): | ||
while not self.is_stop_requested(): | ||
self.do_work() | ||
self.cleanup() | ||
def do_work(self): | ||
# Implement your work here | ||
pass | ||
def cleanup(self): | ||
# Cleanup logic here | ||
pass |
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,30 @@ | ||
.. _add_notifications: | ||
|
||
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") | ||
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 |
---|---|---|
|
@@ -9,4 +9,4 @@ Usage | |
|
||
usage/installation | ||
usage/key_concepts | ||
usage/examples | ||
usage/backends |
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,10 @@ | ||
.. _backends: | ||
|
||
======== | ||
Backends | ||
======== | ||
|
||
.. toctree:: | ||
:maxdepth: 2 | ||
|
||
backends/micro-manager_backend |
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,9 @@ | ||
.. _data: | ||
|
||
|
||
======= | ||
Data | ||
======= | ||
|
||
|
||
Data hand |
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,47 +1,81 @@ | ||
.. _devices: | ||
|
||
|
||
####### | ||
======= | ||
Devices | ||
####### | ||
======= | ||
|
||
Devices in ExEngine are software representations of hardware components in a microscope system. When possible, they provide a consistent way to interact with diverse equipment, abstracting away the complexities of individual hardware implementations. When not possible, devices can additionally expose specialized APIs specific to individual components. | ||
|
||
ExEngine supports multiple **backends** - individual devices or libraries of devices (e.g., Micro-Manager). The method to create devices depends on the specific backend in use. | ||
Devices in ExEngine represent hardware or software components. They provide: | ||
|
||
- Standardized interfaces for common functionalities | ||
- Thread-safe execution of commands | ||
- Support for multiple backend implementations (i.e. physical hardware devices or libraries for the control of multiple devices) | ||
- Flexibility to represent any grouping of related functionality | ||
|
||
Here's a minimal example using the Micro-Manager backend: | ||
|
||
While often used for microscopy hardware, ExEngine's device concept and its benefits are not limited to this domain. A device can represent physical hardware, virtual devices, or software services. | ||
|
||
|
||
|
||
Using Devices | ||
------------- | ||
ExEngine exposes devices through specific backends. | ||
|
||
For example, the Micro-Manager backend enables access to hardware devices controllable through Micro-Manager. (For installation and setup instructions, see :ref:`micro-manager_backend`). | ||
|
||
.. code-block:: python | ||
# (assuming MM backend already installed and initialized) | ||
# load the micro-manager device for an objective lens switcher | ||
objective = MicroManagerDevice("Objective") | ||
# Set the objective in use | ||
objective.Label = "Nikon 10X S Fluor" | ||
Without further specialization, devices are free to have any method and property names. However, certain functionalities are standardized through device types: | ||
|
||
|
||
|
||
Device Types | ||
^^^^^^^^^^^^ | ||
Functionality can be grouped with certain device types: | ||
|
||
For example, the Detector type, which has standardized methods like start, stop, arm, etc. | ||
|
||
Here's a quick example of a Detector: | ||
|
||
.. code-block:: python | ||
from mmpycorex import create_core_instance | ||
from exengine.kernel.executor import ExecutionEngine | ||
from exengine.backends.micromanager.mm_device_implementations import MicroManagerSingleAxisStage | ||
detector = MicroManagerCamera() | ||
camera.arm(10) # this acquires 10 images | ||
camera.start() | ||
# Create the ExecutionEngine | ||
executor = ExecutionEngine() | ||
Events often take specific device types as parameters. This enables the re-use of events across multiple devices | ||
|
||
# Initialize Micro-Manager core | ||
create_core_instance(config_file='MMConfig_demo.cfg') | ||
For example, the ReadoutData event takes a detector: | ||
|
||
# Access Micro-Manager device | ||
z_stage = MicroManagerSingleAxisStage() | ||
.. code-block:: python | ||
readout_event = ReadoutData(detector=camera, ...) | ||
z_stage.set_position(1234.56) | ||
Device Hierarchies | ||
"""""""""""""""""" | ||
Devices in ExEngine exist in hierarchies. All devices must inherit from the exengine.Device base class. Further functionality can be standardized by inheriting from one or more specific device type classes. For example, ``MicroManagerSingleAxisStage`` is a subclass of ``exengine.SingleAxisPositioner``, which is itself a subclass of ``exengine.Device``. | ||
Thread Safety | ||
------------- | ||
By default, all ExEngine devices are made thread-safe. | ||
|
||
The advantage of this hierarchical structure is that it standardizes functionality, allowing code to be written for generic device types (e.g., a single axis positioner) that will work with many different device libraries. This approach enables a common API across different libraries of devices, similar to Micro-Manager's device abstraction layer but on a meta-level - spanning multiple device ecosystems rather than just devices within a single project. However, ExEngine's device system is designed to be adaptable. While adhering to the standardized interfaces offers the most benefits, users can still leverage many advantages of the system without implementing these specialized APIs. | ||
This is done under the hood by intercepting and rerouting all device calls to common threads. | ||
|
||
This can be turned off by setting the `no_executor` parameter to `True` when initializing a device: | ||
|
||
.. code-block:: python | ||
TODO: thread standardization features of devices (and how to turn off) | ||
device = SomeDevice(no_executor=True) | ||
TODO: calling functions on devices directly | ||
TODO: link to guide to adding backends | ||
TODO: transition to more complex with events | ||
Adding New Device Types | ||
----------------------- | ||
For information on adding new device types, see :ref:`add_devices`. |
Oops, something went wrong.