From 060975254ce963e6d281c4c0d2c4ad56815ca10c Mon Sep 17 00:00:00 2001 From: Vesna Tanko Date: Mon, 25 Nov 2019 09:12:27 +0100 Subject: [PATCH 1/2] ConcurrentWidgetMixin: Cancel task on input change --- Orange/widgets/tests/base.py | 37 ++++++++++--------- .../unsupervised/tests/test_owdistances.py | 6 +-- .../widgets/unsupervised/tests/test_owmds.py | 4 +- .../widgets/unsupervised/tests/test_owtsne.py | 14 +++---- Orange/widgets/utils/concurrent.py | 4 +- .../widgets/utils/tests/concurrent_example.py | 3 ++ .../utils/tests/test_concurrent_example.py | 2 +- Orange/widgets/visualize/owfreeviz.py | 1 + .../widgets/visualize/tests/test_owfreeviz.py | 6 ++- 9 files changed, 44 insertions(+), 33 deletions(-) diff --git a/Orange/widgets/tests/base.py b/Orange/widgets/tests/base.py index 295677f71a2..ddd458e472f 100644 --- a/Orange/widgets/tests/base.py +++ b/Orange/widgets/tests/base.py @@ -563,9 +563,10 @@ def test_setup_graph(self, timeout=DEFAULT_TIMEOUT): properly set/updated""" self.send_signal(self.widget.Inputs.data, self.data) - if self.widget.isBlocking(): - spy = QSignalSpy(self.widget.blockingStateChanged) - self.assertTrue(spy.wait(timeout)) + self.assertTrue( + self.signal_manager.wait_for_finished(self.widget, timeout), + f"Did not finish in the specified {timeout}ms timeout" + ) self.assertIsNotNone(self.widget.graph.scatterplot_item) @@ -657,11 +658,10 @@ def test_plot_once(self, timeout=DEFAULT_TIMEOUT): def test_subset_data_color(self, timeout=DEFAULT_TIMEOUT): self.send_signal(self.widget.Inputs.data, self.data) - - if self.widget.isBlocking(): - spy = QSignalSpy(self.widget.blockingStateChanged) - self.assertTrue(spy.wait(timeout)) - + self.assertTrue( + self.signal_manager.wait_for_finished(self.widget, timeout), + f"Did not finish in the specified {timeout}ms timeout" + ) self.send_signal(self.widget.Inputs.data_subset, self.data[:10]) subset = [brush.color().name() == "#46befa" for brush in self.widget.graph.scatterplot_item.data['brush'][:10]] @@ -723,18 +723,20 @@ def test_invalidated_embedding(self, timeout=DEFAULT_TIMEOUT): def test_saved_selection(self, timeout=DEFAULT_TIMEOUT): self.send_signal(self.widget.Inputs.data, self.data) - if self.widget.isBlocking(): - spy = QSignalSpy(self.widget.blockingStateChanged) - self.assertTrue(spy.wait(timeout)) + self.assertTrue( + self.signal_manager.wait_for_finished(self.widget, timeout), + f"Did not finish in the specified {timeout}ms timeout" + ) self.widget.graph.select_by_indices(list(range(0, len(self.data), 10))) settings = self.widget.settingsHandler.pack_data(self.widget) w = self.create_widget(self.widget.__class__, stored_settings=settings) self.send_signal(self.widget.Inputs.data, self.data, widget=w) - if w.isBlocking(): - spy = QSignalSpy(w.blockingStateChanged) - self.assertTrue(spy.wait(timeout)) + self.assertTrue( + self.signal_manager.wait_for_finished(w, timeout), + f"Did not finish in the specified {timeout}ms timeout" + ) self.assertEqual(np.sum(w.graph.selection), 15) np.testing.assert_equal(self.widget.graph.selection, w.graph.selection) @@ -770,9 +772,10 @@ def test_in_out_summary(self, timeout=DEFAULT_TIMEOUT): self.assertEqual(info._StateInfo__output_summary.brief, "") self.send_signal(self.widget.Inputs.data, self.data) - if self.widget.isBlocking(): - spy = QSignalSpy(self.widget.blockingStateChanged) - self.assertTrue(spy.wait(timeout)) + self.assertTrue( + self.signal_manager.wait_for_finished(self.widget, timeout), + f"Did not finish in the specified {timeout}ms timeout" + ) ind = self._select_data() self.assertEqual(info._StateInfo__input_summary.brief, str(len(self.data))) diff --git a/Orange/widgets/unsupervised/tests/test_owdistances.py b/Orange/widgets/unsupervised/tests/test_owdistances.py index d508d74167b..bf1708fd344 100644 --- a/Orange/widgets/unsupervised/tests/test_owdistances.py +++ b/Orange/widgets/unsupervised/tests/test_owdistances.py @@ -157,12 +157,12 @@ def test_too_big_array(self): mock = Mock(side_effect=ValueError) self.widget.compute_distances(mock, self.iris) - self.wait_until_stop_blocking() + self.wait_until_finished() self.assertTrue(self.widget.Error.distances_value_error.is_shown()) mock = Mock(side_effect=MemoryError) self.widget.compute_distances(mock, self.iris) - self.wait_until_stop_blocking() + self.wait_until_finished() self.assertEqual(len(self.widget.Error.active), 1) self.assertTrue(self.widget.Error.distances_memory_error.is_shown()) @@ -176,7 +176,7 @@ def test_negative_values_bhattacharyya(self): if metric == distance.Bhattacharyya: break self.send_signal(self.widget.Inputs.data, self.iris) - self.wait_until_stop_blocking() + self.wait_until_finished() self.assertTrue(self.widget.Error.distances_value_error.is_shown()) self.iris.X[0, 0] *= -1 diff --git a/Orange/widgets/unsupervised/tests/test_owmds.py b/Orange/widgets/unsupervised/tests/test_owmds.py index 0bf67c69bc6..27a3f84d316 100644 --- a/Orange/widgets/unsupervised/tests/test_owmds.py +++ b/Orange/widgets/unsupervised/tests/test_owmds.py @@ -49,14 +49,14 @@ def tearDown(self): self.widget.onDeleteWidget() super().tearDown() - def test_plot_once(self, timeout=5000): + def test_plot_once(self): # pylint: disable=arguments-differ """Test if data is plotted only once but committed on every input change""" table = Table("heart_disease") self.widget.setup_plot = Mock() self.widget.commit = self.widget.unconditional_commit = Mock() self.send_signal(self.widget.Inputs.data, table) self.widget.commit.reset_mock() - self.wait_until_stop_blocking() + self.wait_until_finished() self.widget.setup_plot.assert_called_once() self.widget.commit.assert_called_once() diff --git a/Orange/widgets/unsupervised/tests/test_owtsne.py b/Orange/widgets/unsupervised/tests/test_owtsne.py index 5d02944f660..b268919a4ff 100644 --- a/Orange/widgets/unsupervised/tests/test_owtsne.py +++ b/Orange/widgets/unsupervised/tests/test_owtsne.py @@ -149,7 +149,7 @@ def test_normalize_data(self): with patch("Orange.preprocess.preprocess.Normalize", wraps=Normalize) as normalize: self.send_signal(self.widget.Inputs.data, self.data) self.assertTrue(self.widget.controls.normalize.isEnabled()) - self.wait_until_stop_blocking() + self.wait_until_finished() normalize.assert_called_once() # Disable checkbox @@ -158,7 +158,7 @@ def test_normalize_data(self): with patch("Orange.preprocess.preprocess.Normalize", wraps=Normalize) as normalize: self.send_signal(self.widget.Inputs.data, self.data) self.assertTrue(self.widget.controls.normalize.isEnabled()) - self.wait_until_stop_blocking() + self.wait_until_finished() normalize.assert_not_called() # Normalization shouldn't work on sparse data @@ -169,7 +169,7 @@ def test_normalize_data(self): with patch("Orange.preprocess.preprocess.Normalize", wraps=Normalize) as normalize: self.send_signal(self.widget.Inputs.data, sparse_data) self.assertFalse(self.widget.controls.normalize.isEnabled()) - self.wait_until_stop_blocking() + self.wait_until_finished() normalize.assert_not_called() @patch("Orange.projection.manifold.TSNEModel.optimize") @@ -192,7 +192,7 @@ def _check_exaggeration(call, exaggeration): self.wait_until_stop_blocking() self.widget.controls.exaggeration.setValue(1) self.widget.run_button.clicked.emit() # run with exaggeration 1 - self.wait_until_stop_blocking() + self.wait_until_finished() _check_exaggeration(optimize, 1) # Reset and clear state @@ -205,7 +205,7 @@ def _check_exaggeration(call, exaggeration): self.wait_until_stop_blocking() self.widget.controls.exaggeration.setValue(3) self.widget.run_button.clicked.emit() # run with exaggeration 1 - self.wait_until_stop_blocking() + self.wait_until_finished() _check_exaggeration(optimize, 3) def test_plot_once(self): @@ -221,7 +221,7 @@ def test_plot_once(self): # when the result was available. self.widget.setup_plot.reset_mock() self.widget.commit.reset_mock() - self.wait_until_stop_blocking() + self.wait_until_finished() self.widget.setup_plot.assert_called_once() self.widget.commit.assert_called_once() @@ -295,7 +295,7 @@ def test_invalidation_flow(self): # set global structure "on" (after the embedding is computed) w.controls.multiscale.setChecked(False) self.send_signal(w.Inputs.data, self.data) - self.wait_until_stop_blocking() + self.wait_until_finished() self.assertFalse(self.widget.Information.modified.is_shown()) # All the embedding components should computed self.assertIsNotNone(w.pca_projection) diff --git a/Orange/widgets/utils/concurrent.py b/Orange/widgets/utils/concurrent.py index 5c9f8d2b308..732a5e9377b 100644 --- a/Orange/widgets/utils/concurrent.py +++ b/Orange/widgets/utils/concurrent.py @@ -560,12 +560,12 @@ class ConcurrentWidgetMixin(ConcurrentMixin): """ def __set_state_ready(self): self.progressBarFinished() - self.setBlocking(False) + self.setInvalidated(False) self.setStatusMessage("") def __set_state_busy(self): self.progressBarInit() - self.setBlocking(True) + self.setInvalidated(True) def start(self, task: Callable, *args, **kwargs): self.__set_state_ready() diff --git a/Orange/widgets/utils/tests/concurrent_example.py b/Orange/widgets/utils/tests/concurrent_example.py index c37b067ca6c..3fb8a513455 100644 --- a/Orange/widgets/utils/tests/concurrent_example.py +++ b/Orange/widgets/utils/tests/concurrent_example.py @@ -99,6 +99,9 @@ def on_done(self, result: Result): self.run_button.setText("Start") self.commit() + def on_exception(self, ex: Exception): + raise ex + # OWDataProjectionWidget def set_data(self, data: Table): super().set_data(data) diff --git a/Orange/widgets/utils/tests/test_concurrent_example.py b/Orange/widgets/utils/tests/test_concurrent_example.py index df0a113d0e7..6e67dccb98e 100644 --- a/Orange/widgets/utils/tests/test_concurrent_example.py +++ b/Orange/widgets/utils/tests/test_concurrent_example.py @@ -33,7 +33,7 @@ def test_button_no_data(self): def test_button_with_data(self): self.send_signal(self.widget.Inputs.data, self.data) self.assertEqual(self.widget.run_button.text(), "Stop") - self.wait_until_stop_blocking() + self.wait_until_finished() self.assertEqual(self.widget.run_button.text(), "Start") def test_button_toggle(self): diff --git a/Orange/widgets/visualize/owfreeviz.py b/Orange/widgets/visualize/owfreeviz.py index 25bdb4b1e84..34d583fb803 100644 --- a/Orange/widgets/visualize/owfreeviz.py +++ b/Orange/widgets/visualize/owfreeviz.py @@ -229,6 +229,7 @@ def on_exception(self, ex: Exception): # OWAnchorProjectionWidget def set_data(self, data): super().set_data(data) + self.graph.set_sample_size(None) if self._invalidated: self.init_projection() diff --git a/Orange/widgets/visualize/tests/test_owfreeviz.py b/Orange/widgets/visualize/tests/test_owfreeviz.py index eb60ceb4a1e..408eade9493 100644 --- a/Orange/widgets/visualize/tests/test_owfreeviz.py +++ b/Orange/widgets/visualize/tests/test_owfreeviz.py @@ -71,7 +71,7 @@ def test_optimization_finish(self): output1 = self.get_output(self.widget.Outputs.components) self.widget.run_button.click() self.assertEqual(self.widget.run_button.text(), "Stop") - self.wait_until_stop_blocking() + self.wait_until_finished() self.assertEqual(self.widget.run_button.text(), "Start") output2 = self.get_output(self.widget.Outputs.components) self.assertTrue((output1.X != output2.X).any()) @@ -163,3 +163,7 @@ def test_run_do_not_modify_model_inplace(self): self.assertIsNot(self.projection.proj, result.projection.proj) self.assertTrue((self.projection.components_.T != result.projection.components_.T).any()) + + +if __name__ == "__main__": + unittest.main() From 50b7f9678e5d3b9f896b5878c005ffcf623287e0 Mon Sep 17 00:00:00 2001 From: Vesna Tanko Date: Thu, 5 Dec 2019 11:20:51 +0100 Subject: [PATCH 2/2] t-SNE: Fix assert The data instance could have changed, but the task was not canceled due to self._invalidated = False. --- Orange/widgets/unsupervised/owtsne.py | 1 - 1 file changed, 1 deletion(-) diff --git a/Orange/widgets/unsupervised/owtsne.py b/Orange/widgets/unsupervised/owtsne.py index f3f5e003b03..472f6f4fc2a 100644 --- a/Orange/widgets/unsupervised/owtsne.py +++ b/Orange/widgets/unsupervised/owtsne.py @@ -513,7 +513,6 @@ def run(self): def __ensure_task_same_for_pca(self, task: Task): assert self.data is not None - assert task.data is self.data assert task.normalize == self.normalize assert task.pca_components == self.pca_components assert isinstance(task.pca_projection, Table) and \