diff --git a/Orange/widgets/data/owfile.py b/Orange/widgets/data/owfile.py index 04ba71da662..5071496ca75 100644 --- a/Orange/widgets/data/owfile.py +++ b/Orange/widgets/data/owfile.py @@ -117,6 +117,9 @@ class Warning(widget.OWWidget.Warning): file_too_big = widget.Msg("The file is too large to load automatically." " Press Reload to load.") + class Error(widget.OWWidget.Error): + file_not_found = widget.Msg("File not found.") + def __init__(self): super().__init__() RecentPathsWComboMixin.__init__(self) @@ -219,7 +222,8 @@ def __init__(self): if self.source == self.LOCAL_FILE: last_path = self.last_path() - if last_path and os.path.getsize(last_path) > self.SIZE_LIMIT: + if last_path and os.path.exists(last_path) and \ + os.path.getsize(last_path) > self.SIZE_LIMIT: self.Warning.file_too_big() return @@ -271,7 +275,13 @@ def load_data(self): self.closeContext() self.domain_editor.set_domain(None) self.apply_button.setEnabled(False) - self.Warning.file_too_big.clear() + self.clear_messages() + self.set_file_list() + if self.last_path() and not os.path.exists(self.last_path()): + self.Error.file_not_found() + self.send("Data", None) + self.info.setText("No data.") + return error = None try: diff --git a/Orange/widgets/data/tests/test_owfile.py b/Orange/widgets/data/tests/test_owfile.py index 47a12cc99a0..10dec85bd43 100644 --- a/Orange/widgets/data/tests/test_owfile.py +++ b/Orange/widgets/data/tests/test_owfile.py @@ -1,13 +1,16 @@ # Test methods with long descriptive names can omit docstrings # pylint: disable=missing-docstring -from os import path +from os import path, remove from unittest.mock import Mock +import numpy as np + from AnyQt.QtCore import QMimeData, QPoint, Qt, QUrl from AnyQt.QtGui import QDragEnterEvent, QDropEvent import Orange -from Orange.data import FileFormat, dataset_dirs, StringVariable +from Orange.data import FileFormat, dataset_dirs, StringVariable, Table, \ + Domain, DiscreteVariable from Orange.widgets.data.owfile import OWFile from Orange.widgets.tests.base import WidgetTest @@ -99,3 +102,28 @@ def test_no_last_path(self): self.create_widget(OWFile, stored_settings={"recent_paths": []}) # Doesn't crash and contains a single item, (none). self.assertEqual(self.widget.file_combo.count(), 1) + + def test_file_not_found(self): + # Create a dummy file + file_name = "test_owfile_data.tab" + domainA = Domain([DiscreteVariable("d1", values=("a", "b"))], + DiscreteVariable("c1", values=("aaa", "bbb"))) + dataA = Table(domainA, np.array([[0], [1], [0], [np.nan]]), + np.array([0, 1, 0, 1])) + dataA.save(file_name) + + # Open the file with the widget + self.open_dataset(file_name) + self.assertEqual(self.get_output("Data").domain, dataA.domain) + + # Delete the file and try to reload it + remove(file_name) + self.widget.load_data() + self.assertEqual(file_name, path.basename(self.widget.last_path())) + self.assertTrue(self.widget.Error.file_not_found.is_shown()) + self.assertIsNone(self.get_output("Data")) + self.assertEqual(self.widget.info.text(), "No data.") + + # Open a sample dataset + self.open_dataset("iris") + self.assertFalse(self.widget.Error.file_not_found.is_shown()) diff --git a/Orange/widgets/utils/filedialogs.py b/Orange/widgets/utils/filedialogs.py index 231c4ae7992..93be147b9ca 100644 --- a/Orange/widgets/utils/filedialogs.py +++ b/Orange/widgets/utils/filedialogs.py @@ -1,6 +1,7 @@ import os -from AnyQt.QtCore import QFileInfo +from AnyQt.QtCore import QFileInfo, Qt +from AnyQt.QtGui import QBrush from AnyQt.QtWidgets import \ QMessageBox, QFileDialog, QFileIconProvider, QComboBox @@ -281,6 +282,8 @@ def _relocate_recent_files(self): rec.append( RecentPath.create(recent.search(search_paths), search_paths, **kwargs) ) + else: + rec.append(recent) # change the list in-place for the case the widgets wraps this list # in some model (untested!) self.recent_paths[:] = rec @@ -351,6 +354,9 @@ def set_file_list(self): for i, recent in enumerate(self.recent_paths): self.file_combo.addItem(recent.basename) self.file_combo.model().item(i).setToolTip(recent.abspath) + if not os.path.exists(recent.abspath): + self.file_combo.setItemData(i, QBrush(Qt.red), + Qt.TextColorRole) def workflowEnvChanged(self, key, value, oldvalue): super().workflowEnvChanged(key, value, oldvalue)