From 1184d2ba7624a3333aeb7f289e20e6804f04c58f Mon Sep 17 00:00:00 2001 From: Ales Erjavec Date: Wed, 26 Oct 2022 12:32:45 +0200 Subject: [PATCH 1/2] OWGEODatasets: Move GDSInfo initialization in a worker thread --- .../tests/widgets/test_OWGEODatasets.py | 2 + .../bioinformatics/widgets/OWGEODatasets.py | 65 ++++++++++++------- 2 files changed, 44 insertions(+), 23 deletions(-) diff --git a/orangecontrib/bioinformatics/tests/widgets/test_OWGEODatasets.py b/orangecontrib/bioinformatics/tests/widgets/test_OWGEODatasets.py index 9a1536dc..e1e7aac3 100644 --- a/orangecontrib/bioinformatics/tests/widgets/test_OWGEODatasets.py +++ b/orangecontrib/bioinformatics/tests/widgets/test_OWGEODatasets.py @@ -13,6 +13,8 @@ def setUp(self): self.test_sample = 'GDS1001' self.test_organism = '10090' self.widget = self.create_widget(OWGEODatasets) + self.wait_until_finished(self.widget) + self.process_events() def test_minimum_size(self): pass diff --git a/orangecontrib/bioinformatics/widgets/OWGEODatasets.py b/orangecontrib/bioinformatics/widgets/OWGEODatasets.py index 32c10d25..0e62d333 100755 --- a/orangecontrib/bioinformatics/widgets/OWGEODatasets.py +++ b/orangecontrib/bioinformatics/widgets/OWGEODatasets.py @@ -1,12 +1,13 @@ """ Gene Expression Omnibus datasets widget """ import sys from types import SimpleNamespace -from typing import Any, Optional, DefaultDict +from typing import Any, Optional, DefaultDict, Union from collections import defaultdict import requests -from AnyQt.QtCore import Qt +from AnyQt.QtCore import Qt, QTimer + from AnyQt.QtWidgets import ( QSplitter, QTreeWidget, @@ -63,6 +64,8 @@ def callback(): nonlocal current_iter current_iter += 1 state.set_progress_value(100 * (current_iter / max_iter)) + if state.is_interruption_requested(): + raise KeyboardInterrupt state.set_status("Downloading...") res.gds_dataset = dataset_download( @@ -71,6 +74,16 @@ def callback(): return res +class GDSInfoResult(SimpleNamespace): + gds_info: Optional[GDSInfo] + + +def run_gds_info_task(state: TaskState): + state.set_status("Fetching index...") + gds_info = GDSInfo() + return GDSInfoResult(gds_info=gds_info) + + class GEODatasetsModel(TableModel): ( indicator_col, @@ -211,6 +224,7 @@ class Warning(OWWidget.Warning): class Error(OWWidget.Error): no_connection = Msg("Widget can't connect to serverfiles.") + error = Msg("{}") class Outputs: gds_data = Output("Expression Data", Table) @@ -232,14 +246,7 @@ class Outputs: def __init__(self): OWWidget.__init__(self) ConcurrentWidgetMixin.__init__(self) - - try: - self.gds_info: Optional[GDSInfo] = GDSInfo() - except requests.exceptions.ConnectionError: - self.gds_info = {} - self.Error.no_connection() - return - + self.gds_info: Optional[GDSInfo] = None self.gds_data: Optional[Table] = None self.__updating_filter = False @@ -291,7 +298,7 @@ def __init__(self): self.table_view.verticalHeader().setVisible(False) self.table_view.viewport().setMouseTracking(True) - self.table_model = GEODatasetsModel(self.gds_info) + self.table_model = GEODatasetsModel({}) self.proxy_model = FilterProxyModel() self.proxy_model.setSourceModel(self.table_model) self.table_view.setModel(self.proxy_model) @@ -343,7 +350,7 @@ def __init__(self): ) self._apply_filter() - self.commit() + self.start(run_gds_info_task) def _splitter_moved(self, *args): self.splitter_settings = [bytes(sp.saveState()) for sp in self.splitters] @@ -452,7 +459,7 @@ def current_changed(): def _run(self): self.Warning.using_local_files.clear() - if self.selected_gds is not None: + if self.gds_info and self.selected_gds is not None: self.gds_data = None self.start( run_download_task, @@ -541,16 +548,28 @@ def commit(self): self._run() def on_exception(self, ex: Exception): - self.Warning.using_local_files() - - def on_done(self, result: Result): - assert isinstance(result.gds_dataset, Table) - self.gds_data = result.gds_dataset - - if self.gds_info: - self.table_model.update_cache_indicator() - - self.Outputs.gds_data.send(self.gds_data) + if isinstance(ex, requests.exceptions.ConnectionError): + self.Warning.using_local_files() + else: + self.Error.error("", exc_info=ex) + + def on_done(self, result: Union[GDSInfoResult, Result]): + self.Error.error.clear() + if isinstance(result, GDSInfoResult): + self.gds_info = result.gds_info + self.table_model = GEODatasetsModel(result.gds_info) + self.proxy_model.setSourceModel(self.table_model) + self.table_view.resizeColumnsToContents() + self._set_selection() + QTimer.singleShot(0, lambda: self.unconditional_commit()) + else: + assert isinstance(result.gds_dataset, Table) + self.gds_data = result.gds_dataset + + if self.gds_info: + self.table_model.update_cache_indicator() + + self.Outputs.gds_data.send(self.gds_data) def on_partial_result(self, result: Any) -> None: pass From e20673523a531f3e113a39323e6a3b5214ce3249 Mon Sep 17 00:00:00 2001 From: PrimozGodec Date: Wed, 20 Mar 2024 11:54:17 +0100 Subject: [PATCH 2/2] Miking lint happy --- .pre-commit-config.yaml | 6 +++--- orangecontrib/bioinformatics/widgets/OWGEODatasets.py | 10 +++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index efc2e4dc..5988bb92 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,18 +1,18 @@ repos: - repo: https://github.com/psf/black - rev: 23.7.0 + rev: 24.3.0 hooks: - id: black language_version: python3 - repo: https://github.com/timothycrosley/isort - rev: 5.12.0 + rev: 5.13.2 hooks: - id: isort language_version: python3 - repo: https://github.com/pycqa/flake8 - rev: 6.1.0 + rev: 7.0.0 hooks: - id: flake8 language_version: python3 diff --git a/orangecontrib/bioinformatics/widgets/OWGEODatasets.py b/orangecontrib/bioinformatics/widgets/OWGEODatasets.py index 0e62d333..daa2612c 100755 --- a/orangecontrib/bioinformatics/widgets/OWGEODatasets.py +++ b/orangecontrib/bioinformatics/widgets/OWGEODatasets.py @@ -1,13 +1,13 @@ """ Gene Expression Omnibus datasets widget """ + import sys from types import SimpleNamespace -from typing import Any, Optional, DefaultDict, Union +from typing import Any, Union, Optional, DefaultDict from collections import defaultdict import requests from AnyQt.QtCore import Qt, QTimer - from AnyQt.QtWidgets import ( QSplitter, QTreeWidget, @@ -121,9 +121,9 @@ def render_pubmed_url(row): TableModel.Column( title(""), { - Qt.DisplayRole: lambda row: " " - if is_cached(items[row]["name"]) - else "", + Qt.DisplayRole: lambda row: ( + " " if is_cached(items[row]["name"]) else "" + ), Qt.UserRole: lambda row: items[row], }, ),