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 orangewidget.utils.widgetpreview.WidgetPreview(widget_cls)[source]

A helper class for widget previews.

widget

an instance of the widget or None

Type:

OWBaseWidget

widget_cls

the widget class

Type:

type

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 calls sys.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.

Parameters:
  • input_data – data used for the default input signal of matching type

  • no_exec (bool) – if set to True, the widget is not shown and the event loop is not started

  • no_exit (bool) – if set to True, the widget is not torn down

  • **kwargs – data for input signals

create_widget()[source]

Initialize QApplication and construct the widget.

send_signals(input_data=None, **kwargs)[source]

Send signals to the widget

exec_widget()[source]

Show the widget and start the QApplication’s main loop.

tear_down()[source]

Save settings and delete the widget.

Unit-testing Widgets

Orange provides a base class WidgetTest with helper methods for unit testing.

class orangewidget.tests.base.WidgetTest(methodName='runTest')[source]

Base class for widget tests

Contains helper methods widget creation and working with signals.

All widgets should be created by the create_widget method, as this will ensure they are created correctly.

classmethod setUpClass()[source]

Prepare environment for test execution

Construct a dummy signal manager and monkey patch OWReport.get_instance to return a manually created instance.

classmethod tearDownClass() None[source]

Hook method for deconstructing the class fixture after running all tests in the class.

tearDown()[source]

Process any pending events before the next test is executed.

create_widget(cls: Type[T], stored_settings: dict | None = None, reset_default_settings=True, **kwargs) T[source]

Create a widget instance using mock signal_manager.

When used with default parameters, it also overrides settings stored on disk with default defined in class.

After widget is created, QApplication.process_events is called to allow any singleShot timers defined in __init__ to execute.

Parameters:
  • cls (WidgetMetaClass) – Widget class to instantiate

  • stored_settings (dict) – Default values for settings

  • reset_default_settings (bool) – If set, widget will start with default values for settings, if not, values accumulated through the session will be used

Returns:

Widget instance

Return type:

cls

static reset_default_settings(widget)[source]

Reset default setting values for widget

Discards settings read from disk and changes stored by fast_save

Parameters:

widget (OWBaseWidget) – widget to reset settings for

process_events(until: callable | None = None, timeout=5000)[source]

Process Qt events, optionally until until returns something True-ish.

Needs to be called manually as QApplication.exec is never called.

Parameters:
  • until (callable or None) – If callable, the events are processed until the function returns something True-ish.

  • timeout (int) – If until condition is not satisfied within timeout milliseconds, a TimeoutError is raised.

Return type:

If until is not None, the True-ish result of its call.

show(widget=None)[source]

Show widget in interactive mode.

Useful for debugging tests, as widget can be inspected manually.

send_signal(input, value=<object object>, *args, widget=None, wait=-1)[source]

Send signal to widget by calling appropriate triggers.

Parameters:
  • input (str)

  • value (Object)

  • id (int) – channel id, used for inputs with flag Multiple

  • widget (Optional[OWBaseWidget]) – widget to send signal to. If not set, self.widget is used

  • wait (int) – The amount of time to wait for the widget to complete.

send_signals(signals, *args, widget=None, wait=-1)[source]

Send signals to widget by calling appropriate triggers. After all the signals are send, widget’s handleNewSignals() in invoked.

Parameters:
  • signals (list of (str, Object))

  • widget (Optional[OWBaseWidget]) – widget to send signals to. If not set, self.widget is used

  • wait (int) – The amount of time to wait for the widget to complete.

wait_until_stop_blocking(widget=None, wait=5000)[source]

Wait until the widget stops blocking i.e. finishes computation.

Parameters:
  • widget (Optional[OWBaseWidget]) – widget to send signal to. If not set, self.widget is used

  • wait (int) – The amount of time to wait for the widget to complete.

wait_until_finished(widget: OWBaseWidget | None = None, timeout=5000) None[source]

Wait until the widget finishes computation.

The widget is considered finished once all its outputs are valid.

Parameters:
  • widget (Optional[OWBaseWidget]) – widget to send signal to. If not set, self.widget is used

  • timeout (int) – The amount of time to wait for the widget to complete.

commit_and_wait(widget=None, wait=5000)[source]

Unconditional commit and wait until finished.

Parameters:
  • widget (Optional[OWBaseWidget]) – widget to send signal to. If not set, self.widget is used

  • wait (int) – The amount of time to wait for the widget to complete.

get_output(output=None, widget=None, wait=5000)[source]

Return the last output that has been sent from the widget.

Parameters:
  • output_name (str)

  • widget (Optional[OWBaseWidget]) – widget whose output is returned. If not set, self.widget is used

  • wait (int) – The amount of time (in milliseconds) to wait for widget to complete.

Return type:

The last sent value of given output or None if nothing has been sent.

modifiers(modifiers)[source]

Context that simulates pressed modifiers

Since QTest.keypress requries pressing some key, we simulate pressing “BassBoost” that looks exotic enough to not meddle with anything.

check_msg_base_class(widget)[source]

Test whether widget error, warning and info messages are derived from its (direct) parent message classes.