Debugging and testing¶
Running widgets as scripts¶
To run a widget without canvas - for debugging and for nitpicking about the GUI
- the widget module must be executable as a script. This is handled by
WidgetPreview
. It is typically
used as follows
if __name__ == "__main__":
WidgetPreview(OWMyWidgetName).run()
where OWMyWidgetName
is the widget's class.
We can also pass the data to the widget. For instance,
if __name__ == "__main__":
WidgetPreview(OWMyWidgetName).run(Orange.data.Table("iris"))
passes the Iris data set to the widget. Passing data in this way requires that there is a single or default signal for the argument's data type. Multiple signals can be passed as keyword arguments in which the names correspond to signal handlers:
if __name__ == "__main__":
data = Orange.data.Table("iris")
WidgetPreview(OWScatterPlot).run(
set_data=data,
set_subset_data=data[:30]
)
If the signal handler accepts multiple inputs, they can be passed as a list, like in the following method in the Table widget.
if __name__ == "__main__":
WidgetPreview(OWDataTable).run(
[(Table("iris"), "iris"),
(Table("brown-selected"), "brown-selected"),
(Table("housing"), "housing")
]
)
Preview ends by tearing down the widget and calling sys.exit
with the
widget's exit code. This can be prevented by adding a no_exit=True argument.
We can also prevent showing the widget and starting the event loop by using
no_exec=True. This, together with some previewers method described below,
can be used for debugging the widget. For example, OWRank's preview,
if __name__ == "__main__":
from Orange.classification import RandomForestLearner
WidgetPreview(OWRank).run(
set_learner=(RandomForestLearner(), (3, 'Learner', None)),
set_data=Table("heart_disease.tab"))
can be temporarily modified to
if __name__ == "__main__":
from Orange.classification import RandomForestLearner
previewer = WidgetPreview(OWRank)
previewer.run(Table("heart_disease.tab"), no_exit=True)
previewer.send_signals(
set_learner=(RandomForestLearner(), (3, 'Learner', None)))
previewer.run()
which shows the widget twice, allows us a finer control of signal passing, and offers adding some breakpoints.
- class Orange.widgets.utils.widgetpreview.WidgetPreview(widget_cls)[source]¶
A helper class for widget previews.
- widget¶
an instance of the widget or None
- Type
OWBaseWidget
- run(input_data=None, *, no_exec=False, no_exit=False, **kwargs)[source]¶
Run a preview of the widget;
It first creates a widget, unless it exists from the previous call. This can only happen if no_exit was set to True.
Next, it passes the data signals to the widget. Data given as positional argument must be of a type for which there exist a single or a default handler. Signals can also be given by keyword arguments, where the name of the argument is the name of the handler method. If the data is a list of tuples, the sequence of tuples is sent to the same handler.
Next, the method shows the widget and starts the event loop, unless no_exec argument is set to True.
Finally, unless the argument no_exit is set to True, the method tears down the widget, deletes the reference to the widget and calls Python's garbage collector, as an effort to catch any crashes due to widget members (typically
QGraphicsScene
elements) outliving the widget. It then callssys.exit
with the exit code from the application's main loop.If no_exit is set to True, the run keeps the widget alive. In this case, subsequent calls to run or other methods (send_signals, exec_widget) will use the same widget.
Unit-testing Widgets¶
Orange provides a base class WidgetTest
with helper methods for unit
testing.