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.

Unit-testing Widgets

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

class Orange.widgets.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.

tearDown()[source]

Process any pending events before the next test is executed.

create_widget(cls, stored_settings=None, reset_default_settings=True)[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 (OWWidget) – widget to reset settings for
process_events(until: callable = 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.
Returns:

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, *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[OWWidget]) – 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_stop_blocking(widget=None, wait=5000)[source]

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

Parameters:
  • widget (Optional[OWWidget]) – 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.
commit_and_wait(widget=None, wait=5000)[source]

Unconditinal commit and wait to stop blocking if needed.

Parameters:
  • widget (Optional[OWWidget]) – 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, widget=None, wait=5000)[source]

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

Parameters:
  • output_name (str) –
  • widget (Optional[OWWidget]) – 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.
Returns:

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.