Skip to content

Commit

Permalink
Add filename pattern to reader associations to preference dialog (nap…
Browse files Browse the repository at this point in the history
…ari#4459)

Co-authored-by: Juan Nunez-Iglesias <[email protected]>
  • Loading branch information
DragaDoncila and jni authored May 12, 2022
1 parent b39fcfa commit f891ac4
Show file tree
Hide file tree
Showing 18 changed files with 624 additions and 81 deletions.
3 changes: 2 additions & 1 deletion napari/_qt/dialogs/_tests/test_reader_dialog.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,8 @@ def test_open_with_dialog_choices_persist(make_napari_viewer, tmp_path):
viewer.window._qt_viewer,
)
assert len(viewer.layers) == 1
assert get_settings().plugins.extension2reader['.npy'] == 'builtins'
# make sure extension was saved with *
assert get_settings().plugins.extension2reader['*.npy'] == 'builtins'


def test_open_with_dialog_choices_raises(make_napari_viewer):
Expand Down
2 changes: 1 addition & 1 deletion napari/_qt/dialogs/qt_reader_dialog.py
Original file line number Diff line number Diff line change
Expand Up @@ -244,5 +244,5 @@ def open_with_dialog_choices(
if persist:
get_settings().plugins.extension2reader = {
**get_settings().plugins.extension2reader,
extension: plugin_name,
f'*{extension}': plugin_name,
}
4 changes: 3 additions & 1 deletion napari/_qt/qt_viewer.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
from qtpy.QtGui import QCursor, QGuiApplication
from qtpy.QtWidgets import QFileDialog, QSplitter, QVBoxLayout, QWidget

from napari.errors.reader_errors import MissingAssociatedReaderError

from ..components._interaction_box_mouse_bindings import (
InteractionBoxMouseBindings,
)
Expand Down Expand Up @@ -744,7 +746,7 @@ def _qt_open(self, filenames: List[str], stack: bool):
"""
try:
self.viewer._open_or_raise_error(filenames, stack=stack)
except ReaderPluginError as e:
except (ReaderPluginError, MissingAssociatedReaderError) as e:
handle_gui_reading(filenames, self, stack, e.reader_plugin, e)
except MultipleReaderError:
handle_gui_reading(filenames, self, stack)
Expand Down
176 changes: 175 additions & 1 deletion napari/_qt/widgets/_tests/test_qt_extension2reader.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,10 @@ def test_extension2reader_defaults(
widget = extension2reader_widget()

assert widget._table.rowCount() == 1
assert widget._table.itemAt(0, 0).text() == 'No extensions found.'
assert (
widget._table.itemAt(0, 0).text()
== 'No filename preferences found.'
)


def test_extension2reader_with_settings(
Expand Down Expand Up @@ -63,3 +66,174 @@ def test_extension2reader_removal(extension2reader_widget, qtbot):
}
assert widget._table.rowCount() == 1
assert widget._table.item(0, 0).text() == '.abc'

# remove remaining extension
btn_to_click = widget._table.cellWidget(0, 1).findChild(QPushButton)
qtbot.mouseClick(btn_to_click, Qt.LeftButton)
assert get_settings().plugins.extension2reader == {}
assert widget._table.rowCount() == 1
assert (
"No filename preferences found" in widget._table.item(0, 0).text()
)


def test_all_readers_in_dropdown(
extension2reader_widget, qtbot, tmp_reader, mock_npe2_pm
):
tmp_reader(mock_npe2_pm, 'npe2-name', filename_patterns=['*'])
tmp_reader(mock_npe2_pm, 'other-reader', filename_patterns=['*.tif'])

npe2_readers = {
'npe2-name': 'npe2 Display',
'other-reader': 'Other Reader',
}
npe1_readers = {'builtins': 'builtins'}

widget = extension2reader_widget(
npe2_readers=npe2_readers, npe1_readers=npe1_readers
)
all_reader_display_names = list(
dict(npe2_readers, **npe1_readers).values()
)
all_dropdown_items = [
widget._new_reader_dropdown.itemText(i)
for i in range(widget._new_reader_dropdown.count())
]
assert sorted(all_reader_display_names) == sorted(all_dropdown_items)


def test_directory_readers_not_in_dropdown(
extension2reader_widget, qtbot, tmp_reader, mock_npe2_pm
):
tmp_reader(
mock_npe2_pm,
'dir-reader',
filename_patterns=[],
accepts_directories=True,
)

widget = extension2reader_widget(
npe2_readers={'dir-reader': 'Directory Reader'}, npe1_readers={}
)
all_dropdown_items = [
widget._new_reader_dropdown.itemText(i)
for i in range(widget._new_reader_dropdown.count())
]
assert 'Directory Reader' not in all_dropdown_items


def test_filtering_readers(
extension2reader_widget, qtbot, tmp_reader, mock_npe2_pm
):
tmp_reader(mock_npe2_pm, 'npy-reader', filename_patterns=['*.npy'])
tmp_reader(mock_npe2_pm, 'tif-reader', filename_patterns=['*.tif'])

widget = extension2reader_widget(npe1_readers={'builtins': 'builtins'})

assert widget._new_reader_dropdown.count() == 3
widget._filter_compatible_readers('*.npy')
assert widget._new_reader_dropdown.count() == 2
all_dropdown_items = [
widget._new_reader_dropdown.itemText(i)
for i in range(widget._new_reader_dropdown.count())
]
assert sorted(['npy-reader', 'builtins']) == all_dropdown_items


def test_filtering_readers_complex_pattern(
extension2reader_widget, qtbot, tmp_reader, mock_npe2_pm
):
tmp_reader(mock_npe2_pm, 'npy-reader', filename_patterns=['*.npy'])
tmp_reader(
mock_npe2_pm,
'tif-reader',
filename_patterns=['my-specific-folder/*.tif'],
)

widget = extension2reader_widget(npe1_readers={})

assert widget._new_reader_dropdown.count() == 2
widget._filter_compatible_readers('my-specific-folder/my-file.tif')
assert widget._new_reader_dropdown.count() == 1
all_dropdown_items = [
widget._new_reader_dropdown.itemText(i)
for i in range(widget._new_reader_dropdown.count())
]
assert sorted(['tif-reader']) == all_dropdown_items


def test_adding_new_preference(
extension2reader_widget, qtbot, tmp_reader, mock_npe2_pm
):
tmp_reader(mock_npe2_pm, 'npy-reader', filename_patterns=['*.npy'])
tif_reader = tmp_reader(
mock_npe2_pm, 'tif-reader', filename_patterns=['*.tif']
)
tif_reader.manifest.display_name = "TIF Reader"

widget = extension2reader_widget(npe1_readers={})
widget._fn_pattern_edit.setText('*.tif')
# will be filtered and tif-reader will be only item
widget._new_reader_dropdown.setCurrentIndex(0)

with restore_settings_on_exit():
get_settings().plugins.extension2reader = {}
widget._save_new_preference(True)
settings = get_settings().plugins.extension2reader
assert '*.tif' in settings
assert settings['*.tif'] == 'tif-reader'
assert (
widget._table.item(widget._table.rowCount() - 1, 0).text()
== '*.tif'
)
plugin_label = widget._table.cellWidget(
widget._table.rowCount() - 1, 1
).findChild(QLabel)
assert plugin_label.text() == 'TIF Reader'


def test_adding_new_preference_no_asterisk(
extension2reader_widget, qtbot, tmp_reader, mock_npe2_pm
):
tmp_reader(mock_npe2_pm, 'npy-reader', filename_patterns=['*.npy'])
tif_reader = tmp_reader(
mock_npe2_pm, 'tif-reader', filename_patterns=['*.tif']
)
tif_reader.manifest.display_name = "TIF Reader"

widget = extension2reader_widget(npe1_readers={})
widget._fn_pattern_edit.setText('.tif')
# will be filtered and tif-reader will be only item
widget._new_reader_dropdown.setCurrentIndex(0)

with restore_settings_on_exit():
get_settings().plugins.extension2reader = {}
widget._save_new_preference(True)
settings = get_settings().plugins.extension2reader
assert '*.tif' in settings
assert settings['*.tif'] == 'tif-reader'


def test_editing_preference(
extension2reader_widget, qtbot, tmp_reader, mock_npe2_pm
):
tmp_reader(mock_npe2_pm, 'tif-reader', filename_patterns=['*.tif'])
tmp_reader(mock_npe2_pm, 'other-tif-reader', filename_patterns=['*.tif'])

with restore_settings_on_exit():
get_settings().plugins.extension2reader = {'*.tif': 'tif-reader'}

widget = extension2reader_widget(npe1_readers={})
widget._fn_pattern_edit.setText('*.tif')
# will be filtered and other-tif-reader will be first item
widget._new_reader_dropdown.setCurrentIndex(0)
original_row_count = widget._table.rowCount()
widget._save_new_preference(True)
settings = get_settings().plugins.extension2reader
assert '*.tif' in settings
assert settings['*.tif'] == 'other-tif-reader'
assert widget._table.rowCount() == original_row_count
plugin_label = widget._table.cellWidget(
original_row_count - 1, 1
).findChild(QLabel)
assert plugin_label.text() == 'other-tif-reader'
Loading

0 comments on commit f891ac4

Please sign in to comment.