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.