Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FIX] Fix asynchronous widget tests #2520

Merged
merged 5 commits into from
Aug 9, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 15 additions & 8 deletions Orange/widgets/evaluate/tests/test_owtestlearners.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,24 +26,28 @@ def setUp(self):
super().setUp()
self.widget = self.create_widget(OWTestLearners) # type: OWTestLearners

def tearDown(self):
self.widget.onDeleteWidget()
super().tearDown()

def test_basic(self):
data = Table("iris")[::3]
data = Table("iris")[::15]
self.send_signal(self.widget.Inputs.train_data, data)
self.send_signal(self.widget.Inputs.learner, MajorityLearner(), 0, wait=5000)
res = self.get_output(self.widget.Outputs.evaluations_results)
self.send_signal(self.widget.Inputs.learner, MajorityLearner(), 0)
res = self.get_output(self.widget.Outputs.evaluations_results, wait=5000)
self.assertIsInstance(res, Results)
self.assertIsNotNone(res.domain)
self.assertIsNotNone(res.data)
self.assertIsNotNone(res.probabilities)

self.send_signal(self.widget.Inputs.learner, None, 0, wait=5000)
res = self.get_output(self.widget.Outputs.evaluations_results)
self.send_signal(self.widget.Inputs.learner, None, 0)
res = self.get_output(self.widget.Outputs.evaluations_results, wait=5000)
self.assertIsNone(res)

data = Table("housing")[::10]
self.send_signal(self.widget.Inputs.train_data, data)
self.send_signal(self.widget.Inputs.learner, MeanLearner(), 0, wait=5000)
res = self.get_output(self.widget.Outputs.evaluations_results)
self.send_signal(self.widget.Inputs.learner, MeanLearner(), 0)
res = self.get_output(self.widget.Outputs.evaluations_results, wait=5000)
self.assertIsInstance(res, Results)
self.assertIsNotNone(res.domain)
self.assertIsNotNone(res.data)
Expand All @@ -65,6 +69,7 @@ def test_CrossValidationByFeature(self):
self.send_signal(self.widget.Inputs.train_data, data)
self.assertFalse(rb.isEnabled())
self.assertFalse(self.widget.features_combo.isEnabled())
self.get_output(self.widget.Outputs.evaluations_results, wait=5000)

self.send_signal(self.widget.Inputs.train_data, data_with_disc_metas)
self.assertTrue(rb.isEnabled())
Expand All @@ -73,6 +78,7 @@ def test_CrossValidationByFeature(self):
self.assertTrue(self.widget.features_combo.isEnabled())
self.assertEqual(self.widget.features_combo.currentText(), "iris")
self.assertEqual(len(self.widget.features_combo.model()), 1)
self.get_output(self.widget.Outputs.evaluations_results, wait=5000)

self.send_signal(self.widget.Inputs.train_data, None)
self.assertFalse(rb.isEnabled())
Expand Down Expand Up @@ -148,7 +154,7 @@ def test_memory_error(self):
Handling memory error.
GH-2316
"""
data = Table("iris")[::3]
data = Table("iris")[::15]
self.send_signal(self.widget.Inputs.train_data, data)
self.assertFalse(self.widget.Error.memory_error.is_shown())

Expand Down Expand Up @@ -217,6 +223,7 @@ class NewRegressionScore(RegressionScore):
del Score.registry["NewClassificationScore"]
del Score.registry["NewRegressionScore"]


class TestHelpers(unittest.TestCase):
def test_results_one_vs_rest(self):
data = Table("lenses")
Expand Down
23 changes: 20 additions & 3 deletions Orange/widgets/tests/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import time
import unittest
from unittest.mock import Mock
# pylint: disable=unused-import
from typing import List, Optional, Type, TypeVar

import numpy as np
import sip
Expand All @@ -28,6 +30,7 @@
from Orange.widgets.utils.annotated_data import (
ANNOTATED_DATA_FEATURE_NAME, ANNOTATED_DATA_SIGNAL_NAME
)
from Orange.widgets.widget import OWWidget
from Orange.widgets.utils.owlearnerwidget import OWBaseLearner

sip.setdestroyonexit(False)
Expand All @@ -36,6 +39,9 @@

DEFAULT_TIMEOUT = 5000

# pylint: disable=invalid-name
T = TypeVar("T")


class DummySignalManager:
def __init__(self):
Expand Down Expand Up @@ -70,8 +76,7 @@ class WidgetTest(GuiTest):
will ensure they are created correctly.
"""

#: list[OwWidget]
widgets = []
widgets = [] # type: List[OWWidget]

@classmethod
def setUpClass(cls):
Expand All @@ -95,6 +100,7 @@ def tearDown(self):
self.process_events()

def create_widget(self, cls, stored_settings=None, reset_default_settings=True):
# type: (Type[T], Optional[dict], bool) -> T
"""Create a widget instance using mock signal_manager.

When used with default parameters, it also overrides settings stored
Expand Down Expand Up @@ -215,31 +221,42 @@ def send_signal(self, input, value, *args, widget=None, wait=-1):
else:
raise ValueError("'{}' is not an input name for widget {}"
.format(input, type(widget).__name__))
if widget.isBlocking():
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Of the widget is blocking the code will not get past this check and therefore the "wait" parameter is not used. Was this intended?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. The (existing) wait is done after the inputs are set and handleNewSignals is called. It is somewhat misplaced , but I do not want to change it.

raise RuntimeError("'send_signal' called but the widget is in "
"blocking state and does not accept inputs.")
getattr(widget, input.handler)(value, *args)
widget.handleNewSignals()
if wait >= 0 and widget.isBlocking():
spy = QSignalSpy(widget.blockingStateChanged)
self.assertTrue(spy.wait(timeout=wait))

def get_output(self, output, widget=None):
def get_output(self, output, widget=None, wait=5000):
"""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
-------
The last sent value of given output or None if nothing has been sent.
"""
if widget is None:
widget = self.widget

if widget.isBlocking() and wait >= 0:
spy = QSignalSpy(widget.blockingStateChanged)
self.assertTrue(spy.wait(wait),
"Failed to get output in the specified timeout")
if not isinstance(output, str):
output = output.name
return self.signal_manager.outputs.get((widget, output), None)


@contextmanager
def modifiers(self, modifiers):
"""
Expand Down
12 changes: 8 additions & 4 deletions Orange/widgets/unsupervised/tests/test_owmds.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ def setUp(self):
}
) # type: OWMDS

def tearDown(self):
self.widget.onDeleteWidget()
super().tearDown()

def _select_data(self):
random.seed(42)
points = random.sample(range(0, len(self.data)), 20)
Expand All @@ -37,8 +41,8 @@ def _select_data(self):
return sorted(points)

def test_pca_init(self):
self.send_signal(self.signal_name, self.signal_data, wait=1000)
output = self.get_output(self.widget.Outputs.annotated_data)
self.send_signal(self.signal_name, self.signal_data)
output = self.get_output(self.widget.Outputs.annotated_data, wait=1000)
expected = np.array(
[[-2.69304803, 0.32676458],
[-2.7246721, -0.20921726],
Expand All @@ -49,7 +53,7 @@ def test_pca_init(self):

def test_nan_plot(self):
data = datasets.missing_data_1()
self.send_signal(self.widget.Inputs.data, data)
self.send_signal(self.widget.Inputs.data, data, wait=1000)

simulate.combobox_run_through_all(self.widget.cb_color_value)
simulate.combobox_run_through_all(self.widget.cb_color_value)
Expand All @@ -63,7 +67,7 @@ def test_nan_plot(self):
data.Y[:] = np.nan
data.metas[:, 1] = np.nan

self.send_signal("Data", data)
self.send_signal("Data", data, wait=1000)

simulate.combobox_run_through_all(self.widget.cb_color_value)
simulate.combobox_run_through_all(self.widget.cb_shape_value)
Expand Down