8000 Surface original error when a selected plugin fails to read file. by DragaDoncila · Pull Request #7901 · napari/napari · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Surface original error when a selected plugin fails to read file. #7901

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

Merged
merged 8 commits into from
May 14, 2025

Conversation

DragaDoncila
Copy link
Contributor
@DragaDoncila DragaDoncila commented May 9, 2025

References and relevant issues

Discussed in #7826

Description

When a plugin is selected to read a file, but it fails OR when there is only a single plugin available to read a file, we raise our own error message from the original error. However, this means the (likely more useful) original error thrown by the plugin doesn't appear unless you scroll up in the stack trace, even if the error would be relatively easy to fix e.g. just install imagecodecs or something.

This PR improves our own error message so that the original error is printed to the user, and they are advised to scroll up to see the full stack trace. @brisvag and I discussed maybe bringing the actual stack trace down, but decided that would be a lot more complex, and potentially confusing for developers who are used to just scrolling up to get to their own code.

Prior to this PR, if you don't have tifffile installed (for some reason) and try to open a tiff file:

image

With this PR:

image

@DragaDoncila DragaDoncila requested review from Czaki, psobolewskiPhD and a team as code owners May 9, 2025 06:39
@github-actions github-actions bot added the qt Relates to qt label May 9, 2025
@DragaDoncila
Copy link
Contributor Author

@psobolewskiPhD what do you think

@jni
Copy link
Member
jni commented May 9, 2025

if you don't have tifffile installed (for some reason) and try to open a tiff file:

Can you copy the complete stack traces to a gist? (I'm curious about what the complete original stack trace is.)

discussed maybe bringing the actual stack trace down, but decided that would be a lot more complex, and potentially confusing for developers who are used to just scrolling up to get to their own code.

yeah 100% please don't do this — when in Rome Python, do as the Romans Pythonistas do. But the little printout at the bottom is nice. 👌

Looking at the commit history, are we expecting #7826 to merge first?

Copy link
codecov bot commented May 9, 2025

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 92.94%. Comparing base (00026c1) to head (ff4ad40).
Report is 17 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #7901      +/-   ##
==========================================
+ Coverage   92.91%   92.94%   +0.02%     
==========================================
  Files         641      641              
  Lines       60615    60628      +13     
==========================================
+ Hits        56319    56348      +29     
+ Misses       4296     4280      -16     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
< 8000 form class="js-comment-update" id="issuecomment-2865435783-edit-form" data-turbo="false" action="/napari/napari/issue_comments/2865435783" accept-charset="UTF-8" method="post">

@DragaDoncila
Copy link
Contributor Author

@jni the gist is here. You basically have to scroll past two of our ReaderPluginErrors to get up to the real error. The first one is thrown by our ViewerModel nonqt stuff, and the second is thrown by the reader dialog qt stuff.

Looking at the commit history, are we expecting #7826 to merge first?

No, I had just branched off that for convenience (but turned out not to be that convenient) and then I was too lazy to go back to main once I'd committed 😆

#7826 will help because there's some stuff that we don't even try to open right now, but they're independent.

@brisvag brisvag added the maintenance PR with maintance changes, label May 9, 2025
@psobolewskiPhD
Copy link
Member
psobolewskiPhD commented May 9, 2025

I just tested with an ome-tiff:

ReaderPluginError: Tried to read /Users/sobolp/Downloads/C7_24.ome.tiff with plugin napari, because it was associated with that file extension/because it is the only plugin capable of reading that path, but it gave an error. Try associating a different plugin or installing a different plugin for this kind of file.

Scroll up to see the full stack trace.

Original error from plugin "napari":
ValueError: <COMPRESSION.LZW: 5> requires the 'imagecodecs' package

I like this! much better!

For imageio it still swallows the error though.
Here's what napari shows:

---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
File ~/Documents/dev/napari/napari/components/viewer_model.py:1544, in ViewerModel._open_or_raise_error(self=Viewer(camera=Camera(center=(0.0, 0.0, 0.0), zoo...use_drag_gen={}, _mouse_wheel_gen={}, _keymap={}), paths=['/Users/sobolp/Downloads/view_ray.mp4'], kwargs={}, layer_type=None, stack=False)
   1543 try:
-> 1544     added = self._add_layers_with_plugins(
        self = Viewer(camera=Camera(center=(0.0, 0.0, 0.0), zoom=1.0, angles=(0.0, 0.0, 90.0), perspective=0.0, mouse_pan=True, mouse_zoom=True, orientation=(<DepthAxisOrientation.TOWARDS: 'towards'>, <VerticalAxisOrientation.DOWN: 'down'>, <HorizontalAxisOrientation.RIGHT: 'right'>)), cursor=Cursor(position=(1.0, 1.0), scaled=True, style=<CursorStyle.STANDARD: 'standard'>, size=1.0), dims=Dims(ndim=2, ndisplay=2, order=(0, 1), axis_labels=('0', '1'), rollable=(True, True), range=(RangeTuple(start=0.0, stop=2.0, step=1.0), RangeTuple(start=0.0, stop=2.0, step=1.0)), margin_left=(0.0, 0.0), margin_right=(0.0, 0.0), point=(np.float64(0.0), np.float64(0.0)), last_used=0), grid=GridCanvas(stride=1, shape=(-1, -1), enabled=False, spacing=0.0), layers=[], help='', status='Ready', tooltip=Tooltip(visible=False, text=''), theme='dark', title='napari', mouse_over_canvas=True, mouse_move_callbacks=[], mouse_drag_callbacks=[], mouse_double_click_callbacks=[<function double_click_to_zoom at 0x126ee4360>], mouse_wheel_callbacks=[<function dims_scroll at 0x126ee42c0>], _persisted_mouse_event={}, _mouse_drag_gen={}, _mouse_wheel_gen={}, _keymap={})
        paths = ['/Users/sobolp/Downloads/view_ray.mp4']
        kwargs = {}
        stack = False
        plugin = 'napari'
        layer_type = None   1545         paths,
   1546         kwargs=kwargs,
   1547         stack=stack,
   1548         plugin=plugin,
   1549         layer_type=layer_type,
   1550     )
   1551 # plugin failed

File ~/Documents/dev/napari/napari/components/viewer_model.py:1635, in ViewerModel._add_layers_with_plugins(self=Viewer(camera=Camera(center=(0.0, 0.0, 0.0), zoo...use_drag_gen={}, _mouse_wheel_gen={}, _keymap={}), paths=['/Users/sobolp/Downloads/view_ray.mp4'], stack=False, kwargs={}, plugin='napari', layer_type=None)
   1634     assert len(paths) == 1
-> 1635     layer_data, hookimpl = read_data_with_plugins(
        paths = ['/Users/sobolp/Downloads/view_ray.mp4']
        stack = False
        plugin = 'napari'   1636         paths, plugin=plugin, stack=stack
   1637     )
   1639 if layer_data is None:

File ~/Documents/dev/napari/napari/plugins/io.py:80, in read_data_with_plugins(paths=['/Users/sobolp/Downloads/view_ray.mp4'], plugin='napari', stack=False)
     78 hookimpl: HookImplementation | None
---> 80 res = _npe2.read(paths, plugin, stack=stack)
        paths = ['/Users/sobolp/Downloads/view_ray.mp4']
        plugin = 'napari'
        stack = False
        _npe2 = <module 'napari.plugins._npe2' from '/Users/sobolp/Documents/dev/napari/napari/plugins/_npe2.py'>     81 if res is not None:

File ~/Documents/dev/napari/napari/plugins/_npe2.py:56, in read(paths=['/Users/sobolp/Downloads/view_ray.mp4'], plugin='napari', stack=False)
     55 try:
---> 56     layer_data, reader = io_utils.read_get_reader(
        io_utils = <module 'npe2.io_utils' from '/Users/sobolp/micromamba/envs/napari-dev/lib/python3.13/site-packages/npe2/io_utils.py'>
        plugin = 'napari'
        npe1_path = '/Users/sobolp/Downloads/view_ray.mp4'     57         npe1_path, plugin_name=plugin
     58     )
     59 except ValueError as e:
     60     # plugin wasn't passed and no reader was found

File ~/micromamba/envs/napari-dev/lib/python3.13/site-packages/npe2/io_utils.py:66, in read_get_reader(path='/Users/sobolp/Downloads/view_ray.mp4', plugin_name='napari', stack=None)
     65     new_path, new_stack = v1_to_v2(path)
---> 66     return _read(
        new_path = ['/Users/sobolp/Downloads/view_ray.mp4']
        new_stack = False
        plugin_name = 'napari'     67         new_path, plugin_name=plugin_name, return_reader=True, stack=new_stack
     68     )
     69 else:

File ~/micromamba/envs/napari-dev/lib/python3.13/site-packages/npe2/io_utils.py:174, in _read(paths=['/Users/sobolp/Downloads/view_ray.mp4'], stack=False, plugin_name='napari', return_reader=True, _pm=<npe2._plugin_manager.PluginManager object>)
    173 if plugin_name:
--> 174     raise ValueError(
        plugin_name = 'napari'
        paths = ['/Users/sobolp/Downloads/view_ray.mp4']    175         f"Reader {plugin_name!r} was selected to open "
    176         + f"{paths!r}, but returned no data."
    177     )
    178 raise ValueError(f"No readers returned data for {paths!r}")

ValueError: Reader 'napari' was selected to open ['/Users/sobolp/Downloads/view_ray.mp4'], but returned no data.

The above exception was the direct cause of the following exception:

ReaderPluginError                         Traceback (most recent call last)
File ~/Documents/dev/napari/napari/_qt/qt_viewer.py:979, in QtViewer._qt_open(self=<napari._qt.qt_viewer.QtViewer object>, filenames=['/Users/sobolp/Downloads/view_ray.mp4'], stack=False, choose_plugin=False, plugin=None, layer_type=None, **kwargs={})
    978 try:
--> 979     self.viewer.open(
        self = <napari._qt.qt_viewer.QtViewer object at 0x133cbbd90>
        self.viewer = Viewer(camera=Camera(center=(0.0, 0.0, 0.0), zoom=1.0, angles=(0.0, 0.0, 90.0), perspective=0.0, mouse_pan=True, mouse_zoom=True, orientation=(<DepthAxisOrientation.TOWARDS: 'towards'>, <VerticalAxisOrientation.DOWN: 'down'>, <HorizontalAxisOrientation.RIGHT: 'right'>)), cursor=Cursor(position=(1.0, 1.0), scaled=True, style=<CursorStyle.STANDARD: 'standard'>, size=1.0), dims=Dims(ndim=2, ndisplay=2, order=(0, 1), axis_labels=('0', '1'), rollable=(True, True), range=(RangeTuple(start=0.0, stop=2.0, step=1.0), RangeTuple(start=0.0, stop=2.0, step=1.0)), margin_left=(0.0, 0.0), margin_right=(0.0, 0.0), point=(np.float64(0.0), np.float64(0.0)), last_used=0), grid=GridCanvas(stride=1, shape=(-1, -1), enabled=False, spacing=0.0), layers=[], help='', status='Ready', tooltip=Tooltip(visible=False, text=''), theme='dark', title='napari', mouse_over_canvas=True, mouse_move_callbacks=[], mouse_drag_callbacks=[], mouse_double_click_callbacks=[<function double_click_to_zoom at 0x126ee4360>], mouse_wheel_callbacks=[<function dims_scroll at 0x126ee42c0>], _persisted_mouse_event={}, _mouse_drag_gen={}, _mouse_wheel_gen={}, _keymap={})
        filenames = ['/Users/sobolp/Downloads/view_ray.mp4']
        stack = False
        plugin = None
        layer_type = None
        kwargs = {}    980         filenames,
    981         stack=stack,
    982         plugin=plugin,
    983         layer_type=layer_type,
    984         **kwargs,
    985     )
    986 except ReaderPluginError as e:

File ~/Documents/dev/napari/napari/components/viewer_model.py:1444, in ViewerModel.open(self=Viewer(camera=Camera(center=(0.0, 0.0, 0.0), zoo...use_drag_gen={}, _mouse_wheel_gen={}, _keymap={}), path=['/Users/sobolp/Downloads/view_ray.mp4'], stack=False, plugin=None, layer_type=None, **kwargs={})
   1442 # no plugin choice was made
   1443 else:
-> 1444     layers = self._open_or_raise_error(
        layers = <module 'napari.layers' from '/Users/sobolp/Documents/dev/napari/napari/layers/__init__.py'>
        self = Viewer(camera=Camera(center=(0.0, 0.0, 0.0), zoom=1.0, angles=(0.0, 0.0, 90.0), perspective=0.0, mouse_pan=True, mouse_zoom=True, orientation=(<DepthAxisOrientation.TOWARDS: 'towards'>, <VerticalAxisOrientation.DOWN: 'down'>, <HorizontalAxisOrientation.RIGHT: 'right'>)), cursor=Cursor(position=(1.0, 1.0), scaled=True, style=<CursorStyle.STANDARD: 'standard'>, size=1.0), dims=Dims(ndim=2, ndisplay=2, order=(0, 1), axis_labels=('0', '1'), rollable=(True, True), range=(RangeTuple(start=0.0, stop=2.0, step=1.0), RangeTuple(start=0.0, stop=2.0, step=1.0)), margin_left=(0.0, 0.0), margin_right=(0.0, 0.0), point=(np.float64(0.0), np.float64(0.0)), last_used=0), grid=GridCanvas(stride=1, shape=(-1, -1), enabled=False, spacing=0.0), layers=[], help='', status='Ready', tooltip=Tooltip(visible=False, text=''), theme='dark', title='napari', mouse_over_canvas=True, mouse_move_callbacks=[], mouse_drag_callbacks=[], mouse_double_click_callbacks=[<function double_click_to_zoom at 0x126ee4360>], mouse_wheel_callbacks=[<function dims_scroll at 0x126ee42c0>], _persisted_mouse_event={}, _mouse_drag_gen={}, _mouse_wheel_gen={}, _keymap={})
        _path = ['/Users/sobolp/Downloads/view_ray.mp4']
        _stack = False
        kwargs = {}
        layer_type = None   1445         _path, kwargs, layer_type, _stack
   1446     )
   1447     added.extend(layers)

File ~/Documents/dev/napari/napari/components/viewer_model.py:1553, in ViewerModel._open_or_raise_error(self=Viewer(camera=Camera(center=(0.0, 0.0, 0.0), zoo...use_drag_gen={}, _mouse_wheel_gen={}, _keymap={}), paths=['/Users/sobolp/Downloads/view_ray.mp4'], kwargs={}, layer_type=None, stack=False)
   1552     except Exception as e:
-> 1553         raise ReaderPluginError(
        trans = <napari.utils.translations.TranslationBundle object at 0x1138c4590>
        plugin = 'napari'
        paths = ['/Users/sobolp/Downloads/view_ray.mp4']   1554             trans._(
   1555                 'Tried opening with {plugin}, but failed.',
   1556                 deferred=True,
   1557                 plugin=plugin,
   1558             ),
   1559             plugin,
   1560             paths,
   1561             original_error=e,
   1562         ) from e
   1563 # multiple plugins
   1564 else:

ReaderPluginError: Tried opening with napari, but failed.

Scroll up to see the full stack trace.

Original error from plugin "napari":
ValueError: Reader 'napari' was selected to open ['/Users/sobolp/Downloads/view_ray.mp4'], but returned no data.

The above exception was the direct cause of the following exception:

ReaderPluginError                         Traceback (most recent call last)
File ~/Documents/dev/napari/napari/_qt/qt_viewer.py:1144, in QtViewer.dropEvent(self=<napari._qt.qt_viewer.QtViewer object>, event=<PyQt6.QtGui.QDropEvent object>)
   1136 shift_down = (
   1137     QGuiApplication.keyboardModifiers()
   1138     & Qt.KeyboardModifier.ShiftModifier
   1139 )
   1140 alt_down = (
   1141     QGuiApplication.keyboardModifiers()
   1142     & Qt.KeyboardModifier.AltModifier
   1143 )
-> 1144 self._open_from_list_of_urls_data(
        self = <napari._qt.qt_viewer.QtViewer object at 0x133cbbd90>
        event = <PyQt6.QtGui.QDropEvent object at 0x1409adef0>
        shift_down = <KeyboardModifier.NoModifier: 0>
        alt_down = <KeyboardModifier.NoModifier: 0>   1145     event.mimeData().urls(),
   1146     stack=bool(shift_down),
   1147     choose_plugin=bool(alt_down),
   1148 )

File ~/Documents/dev/napari/napari/_qt/qt_viewer.py:1161, in QtViewer._open_from_list_of_urls_data(self=<napari._qt.qt_viewer.QtViewer object>, urls_list=[PyQt6.QtCore.QUrl('file:///Users/sobolp/Downloads/view_ray.mp4')], stack=False, choose_plugin=False)
   1158     else:
   1159         filenames.append(url.toString())
-> 1161 self._qt_open(
        self = <napari._qt.qt_viewer.QtViewer object at 0x133cbbd90>
        filenames = ['/Users/sobolp/Downloads/view_ray.mp4']
        stack = False
        choose_plugin = False   1162     filenames,
   1163     stack=stack,
   1164     choose_plugin=choose_plugin,
   1165 )

File ~/Documents/dev/napari/napari/_qt/qt_viewer.py:987, in QtViewer._qt_open(self=<napari._qt.qt_viewer.QtViewer object>, filenames=['/Users/sobolp/Downloads/view_ray.mp4'], stack=False, choose_plugin=False, plugin=None, layer_type=None, **kwargs={})
    979     self.viewer.open(
    980         filenames,
    981         stack=stack,
   (...)    984         **kwargs,
    985     )
    986 except ReaderPluginError as e:
--> 987     handle_gui_reading(
        filenames = ['/Users/sobolp/Downloads/view_ray.mp4']
        self = <napari._qt.qt_viewer.QtViewer object at 0x133cbbd90>
        stack = False
        layer_type = None
        kwargs = {}    988         filenames,
    989         self,
    990         stack,
    991         e.reader_plugin,
    992         e,
    993         layer_type=layer_type,
    994         **kwargs,
    995     )
    996 except MultipleReaderError:
    997     handle_gui_reading(filenames, self, stack, **kwargs)

File ~/Documents/dev/napari/napari/_qt/dialogs/qt_reader_dialog.py:189, in handle_gui_reading(paths=['/Users/sobolp/Downloads/view_ray.mp4'], qt_viewer=<napari._qt.qt_viewer.QtViewer object>, stack=False, plugin_name='napari', error=ReaderPluginError('Tried opening with napari, bu...ownloads/view_ray.mp4\'], but returned no data.'), plugin_override=False, **kwargs={'layer_type': None})
    162 """Present reader dialog to choose reader and open paths based on result.
    163 
    164 This function is called whenever ViewerModel._open_or_get_error returns
   (...)    186     Dictates whether checkbox to remember choice is unchecked by default
    187 """
    188 _path = paths[0]
--> 189 readers = prepare_remaining_readers(paths, plugin_name, error)
        paths = ['/Users/sobolp/Downloads/view_ray.mp4']
        plugin_name = 'napari'
        error = ReaderPluginError('Tried opening with napari, but failed.\n\nScroll up to see the full stack trace.\n\nOriginal error from plugin "napari":\nValueError: Reader \'napari\' was selected to open [\'/Users/sobolp/Downloads/view_ray.mp4\'], but returned no data.')    190 error_message = str(error) if error else ''
    191 readerDialog = QtReaderDialog(
    192     parent=qt_viewer,
    193     pth=_path,
   (...)    196     persist_checked=plugin_override,
    197 )

File ~/Documents/dev/napari/napari/_qt/dialogs/qt_reader_dialog.py:251, in prepare_remaining_readers(paths=['/Users/sobolp/Downloads/view_ray.mp4'], plugin_name='napari', error=ReaderPluginError('Tried opening with napari, bu...ownloads/view_ray.mp4\'], but returned no data.'))
    243 if not readers and error:
    244     error_msg = trans._(
    245         'Tried to read {path_message} with plugin {plugin}, because it was associated with that file extension/because it is the only plugin capable of reading that path, but it gave an error. Try associating a different plugin or installing a different plugin for this kind of file.',
    246         path_message=(
   (...)    249         plugin=plugin_name,
    250     )
--> 251     raise ReaderPluginError(
        error_msg = 'Tried to read /Users/sobolp/Downloads/view_ray.mp4 with plugin napari, because it was associated with that file extension/because it is the only plugin capable of reading that path, but it gave an error. Try associating a different plugin or installing a different plugin for this kind of file.'
        plugin_name = 'napari'
        paths = ['/Users/sobolp/Downloads/view_ray.mp4']
        error = ReaderPluginError('Tried opening with napari, but failed.\n\nScroll up to see the full stack trace.\n\nOriginal error from plugin "napari":\nValueError: Reader \'napari\' was selected to open [\'/Users/sobolp/Downloads/view_ray.mp4\'], but returned no data.')    252         error_msg,
    253         plugin_name,
    254         paths,
    255         getattr(error, 'original_error', None),
    256     ) from error
    258 return readers

ReaderPluginError: Tried to read /Users/sobolp/Downloads/view_ray.mp4 with plugin napari, because it was associated with that file extension/because it is the only plugin capable of reading that path, but it gave an error. Try associating a different plugin or installing a different plugin for this kind of file.

Scroll up to see the full stack trace.

Original error from plugin "napari":
ValueError: Reader 'napari' was selected to open ['/Users/sobolp/Downloads/view_ray.mp4'], but returned no data.

So it's the generic no data
and what using iio.imread shows:

---------------------------------------------------------------------------
OSError                                   Traceback (most recent call last)
Cell In[3], line 1
----> 1 test = iio.imread(path)

File ~/micromamba/envs/napari-dev/lib/python3.13/site-packages/imageio/v3.py:53, in imread(uri, index, plugin, extension, format_hint, **kwargs)
     50 if index is not None:
     51     call_kwargs["index"] = index
---> 53 with imopen(uri, "r", **plugin_kwargs) as img_file:
     54     return np.asarray(img_file.read(**call_kwargs))

File ~/micromamba/envs/napari-dev/lib/python3.13/site-packages/imageio/core/imopen.py:281, in imopen(uri, io_mode, plugin, extension, format_hint, legacy_mode, **kwargs)
    275         err_msg += (
    276             "\nBased on the extension, the following plugins might add capable backends:\n"
    277             f"{install_candidates}"
    278         )
    280 request.finish()
--> 281 raise err_type(err_msg)

OSError: Could not find a backend to open `/Users/sobolp/Downloads/view_ray.mp4`` with iomode `r`.
Based on the extension, the following plugins might add capable backends:
  FFMPEG:  pip install imageio[ffmpeg]
  pyav:  pip install imageio[pyav]

very helpful!

So not sure if that's a function of the implementation here a real limitation or related to the other PR.

@jni
Copy link
Member
jni commented May 10, 2025

Super weird. Looking at our reader file, I believe we just call imageio:

return iio.imread(filename)

There's no try/except around it that would swallow things and there's no try except anywhere that would swallow an OSError. (Which btw seems to me to be a very weird error class for this error, but whatever!)

Given that the traceback comes from npe2._read:

File ~/micromamba/envs/napari-dev/lib/python3.13/site-packages/npe2/io_utils.py:174, in _read(paths=['/Users/sobolp/Downloads/view_ray.mp4'], stack=False, plugin_name='napari', return_reader=True, _pm=<npe2._plugin_manager.PluginManager object>)
    173 if plugin_name:
--> 174     raise ValueError(
        plugin_name = 'napari'
        paths = ['/Users/sobolp/Downloads/view_ray.mp4']    175         f"Reader {plugin_name!r} was selected to open "
    176         + f"{paths!r}, but returned no data."
    177     )
    178 raise ValueError(f"No readers returned data for {paths!r}")

I suspect that the fix must go there.

@DragaDoncila
Copy link
Contributor Author

I'll take a look at the imageio case. It's weird because that npe2 error is thrown afaik when the plugin returns a null layer, OR if a plugin isn't tried at all, rather than when it errors. I'll try reproduce, but I'm not sure I can, cause when I try to open mp4s I don't get that same error from image.io

@DragaDoncila DragaDoncila added this to the 0.6.1 milestone May 11, 2025
@DragaDoncila
Copy link
Contributor Author

Ok @psobolewskiPhD I still haven't reproduced that OSError you see, but I think I know what's happening.

Without #7826, our napari_get_reader actually bails on reading mp4 files, even though they're listed in the manifest. That causes npe2 to throw a generic No readers returned data error, which is what you see as the "original" error. Note that this is also kinda not correct - it's not that no readers returned data, it's that we refused to even try to read. I make that error more specific in npe2/#377 - among other things which I'd love your input on 🤣.

So:

  • With this PR and the npe2 PR you'd get:
ReaderPluginError: Tried to read /home/ddon0001/Videos/sensitivity_example.mp4 with plugin napari, because it was associated with that file extension/because it is the only plugin capable of reading that path, but it gave an error. Try associating a different plugin or installing a different plugin for this kind of file.

Scroll up to see the full stack trace.

Original error from plugin "napari":
ValueError: Reader 'napari' was selected to open ['/home/ddon0001/Videos/sensitivity_example.mp4'], but refused the file.

which is not amazing, but it is better.

plugin_name,
paths,
getattr(error, 'original_error', None),
Copy link
Collaborator

Choose a reason for hiding this comment

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

What is the benefit from adding a message to string inside ReaderPluginError constructor, instead of here?

Copy link
Contributor

Choose a reason for hiding this comment

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

when we discussed this we were considering using the error's stack trace rather than just the message, but maybe now this can be reverted @DragaDoncila?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@Czaki in this case we have two "layers" of ReaderPluginError that we need to surface the original error through i.e. error here isn't the error we're actually trying to show.

We first raise ReaderPluginError from e in ViewerModel and then we raise it here in the GUI handling code. I therefore decided to store an original error with the ReaderPluginError so that regardless of whether we catch this error elsewhere or just raise it here, we have easy access to that original non-napari-reading-code error.

I could just concatenate the original error to the error message in ViewerModel and then "re-concatenate` it here, but this seemed cleaner. Open to suggestions!

@TimMonko TimMonko added the ready to merge Last chance for comments! Will be merged in ~24h label May 13, 2025
@TimMonko TimMonko merged commit 8b08903 into napari:main May 14, 2025
47 checks passed
@github-actions github-actions bot removed the ready to merge Last chance for comments! Will be merged in ~24h label May 14, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
maintenance PR with maintance changes, qt Relates to qt
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants
0