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 Adder1( OWEwoksWidgetNoThread, ewokstaskclass=SumTask, ): pass
This will enforce the execution of the
Task.run() when a signal is received.
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
the Input and Output values must be defined in SumTask
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
This is what is done in the ewoks example 2 addon class:
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.
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.
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
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
This is what is on in ewoks example 2 addon /
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.