Note on designs¶
There is several design possible to define your Orange Widget and insure compatibility with ewoks orange.
Processing ewokstaskclass on the Qt main thread¶
This is the the simplest case and the most robust one. This is the designed used in the ewoks example 1 addon.
On this case we made Orange Widget inherit from OWEwoksWidgetNoThread
and with we define the ewoks :class:Task to be used.
from ewoksorange.bindings import OWEwoksWidgetNoThread
from ewoksorange.gui.parameterform import ParameterForm
from ewokscore.tests.examples.tasks.sumtask import SumTask
class OWSumTask(
OWEwoksWidgetNoThread,
ewokstaskclass=SumTask,
):
pass
This will enforce the execution of the Task
.run() when a signal is received.
The SumTask
is defined as :
class SumTask(
Task, input_names=["a"], optional_input_names=["b"], output_names=["result"]
):
def run(self):
pass
Each input_names, optional_input_names and output_names will be converted to orange InputSignal, OutputSignal by the OWEwoksWidgetNoThread
constructor.
Note
the Input and Output values must be defined in SumTask
Warning
As both processing and display are done in the main thread this will bring gui freeze. If your processing takes time wnd if you want to avoid gui freeze look at other proposed designs.
Processing ewokstaskclass on a single (dedicated) thread without stack¶
If you want to have a single thread that will process the ewoks.task then you can inherite from OWEwoksWidgetOneThread
This is what is done in the ewoks example 2 addon class: SumListOneThread
You just have to provide task description and link to the ewoks task class:
class SumListOneThread(
OWEwoksWidgetOneThread,
ewokstaskclass=SumList,
):
name = "SumList one thread"
description = "Sum all elements of a list using at most one thread"
category = "esrfWidgets"
want_main_area = False
The Orange widget is containing a processing thread (_processingThread) that will execute the ewokstaskclass.
Note
if a request for processing is done when the thread is already processing it will refuse the processing request. See other design for more advance use case.
Note
TODO: speak about progress.
One (dedicated) thread per task no stack¶
You can have an Orange widget that will create a new thread for each new run.
For this you should inherit from the OWEwoksWidgetOneThreadPerRun
widget like this done by the SumListSeveralThread
of ewoks example 2 addon
class SumListSeveralThread(
OWEwoksWidgetOneThreadPerRun,
ewokstaskclass=SumList2,
):
name = "SumList on several thread"
description = "Sum all elements of a list using a new thread for each" "summation"
category = "esrfWidgets"
want_main_area = False
Note
when a new thread is created each time a processing is requested this usually prevent from providing a progress.
One dedicated thread for the task and with a stack¶
Last design for which we propose an automatic binding is an Orange widget containing a Stack. The stack is associated with a processing thread and has a first in first out (FIFO) behavior.
To access it you can create a widget inheriting from OWEwoksWidgetWithTaskStack
widget.
This is what is on in ewoks example 2 addon / SumListWithTaskStack
class SumListWithTaskStack(
OWEwoksWidgetWithTaskStack,
ewokstaskclass=SumList3,
):
name = "SumList with one thread and a stack"
description = "Sum all elements of a list using a thread and a stack"
category = "esrfWidgets"
want_main_area = False
The SumListWithTaskStack also include an instance of QProgress. So you will be able to display the progress of each task.
Handling everything yourself¶
In some cases you might want to execute one Task
with ewoks and another with orange.
Here the simplest way is to inherit directly from OWWidget
and provide the ewokstaskclass pointing to the Task to be executed by ewoks when converted.
from Orange.widgets.widget import OWWidget
import ewokscore.tests.examples.tasks.sumtask import SumTask
class SumListFreeImplementation(
OWWidget,
):
ewokstaskclass=ewokscore.tests.examples.tasks.sumtask.SumTask
Then you can define standard orange Input and Output to connect it to the workflow.
class SumListFreeImplementation(
OWWidget,
):
class Inputs:
list_ = Input("list", list)
class Outputs:
sum_ = Output("sum", float)
As usual Inputs and Outputs have to be connected somehow:
@Inputs.list_
def compute_sum(self, iterable):
...
def _processingFinished(self):
...
self.Outputs.sum_.send(...)
Orange will use the @Inputs.[input] decorator and Outputs.output to insure connection between widget. Ewoks will use the provided ewokstaskclass to know which class to execut and the INPUT_NAMES, OUTPUT_NAMES to insure connection between classes.