napari: KeyError: 'version' when installing a plugin

🐛 Bug

KeyError: ‘version’ when installing a plugin (that is on pypi but not yet on napari hub). This error is maybe the reason why the warning message ‘When installing/uninstalling npe2 plugins, you must restart napari for UI changes to take effect.’ is not displaying…

To Reproduce

Steps to reproduce the behavior:

  1. Install the napari-deepfinder plugin from the UI by typing napari-deepfinder in the text bar.
  2. The
KeyError                                  Traceback (most recent call last)
File /home/cnstt/test-nap/venv1/lib/python3.9/site-packages/superqt/utils/_qthreading.py:616, in create_worker.<locals>.reraise(e=KeyError('version'))
    615 def reraise(e):
--> 616     raise e
        e = KeyError('version')

File /home/cnstt/test-nap/venv1/lib/python3.9/site-packages/superqt/utils/_qthreading.py:176, in WorkerBase.run(self=<napari._qt.qthreading.GeneratorWorker object>)
    174     warnings.filterwarnings("always")
    175     warnings.showwarning = lambda *w: self.warned.emit(w)
--> 176     result = self.work()
        self = <napari._qt.qthreading.GeneratorWorker object at 0x7faf71497790>
    177 if isinstance(result, Exception):
    178     if isinstance(result, RuntimeError):
    179         # The Worker object has likely been deleted.
    180         # A deleted wrapped C/C++ object may result in a runtime
    181         # error that will cause segfault if we try to do much other
    182         # than simply notify the user.

File /home/cnstt/test-nap/venv1/lib/python3.9/site-packages/superqt/utils/_qthreading.py:443, in GeneratorWorker.work(self=<napari._qt.qthreading.GeneratorWorker object>)
    441 try:
    442     input = self._next_value()
--> 443     output = self._gen.send(input)
        self = <napari._qt.qthreading.GeneratorWorker object at 0x7faf71497790>
        input = None
        output = (PackageMetadata(metadata_version='1.0', name='zarpaint', version='0.2.0', dynamic=None, platform=None, supported_platform=None, summary='Paint segmentations directly to on-disk/remote zarr arrays', description=None, description_content_type=None, keywords=None, home_page='https://github.com/jni/zarpaint', download_url=None, author='Abigail McGovern and Juan Nunez-Iglesias', author_email=None, maintainer=None, maintainer_email=None, license='BSD-3-Clause', classifier=None, requires_dist=None, requires_python=None, requires_external=None, project_url=None, provides_extra=None, provides_dist=None, obsoletes_dist=None), True)
        self._gen = <generator object iter_hub_plugin_info at 0x7faf714d2c80>
    444     self.yielded.emit(output)
    445 except StopIteration as exc:

File /home/cnstt/test-nap/venv1/lib/python3.9/site-packages/napari/plugins/hub.py:101, in iter_hub_plugin_info(skip={}, conda_forge=False)
     94 futures = [
     95     executor.submit(hub_plugin_info, name, conda_forge=conda_forge)
     96     for name in sorted(plugins)
     97     if name not in skip
     98 ]
    100 for future in as_completed(futures):
--> 101     info, is_available_in_conda_forge = future.result()
        future = <Future at 0x7faf7270c9d0 state=finished raised KeyError>
        info, is_available_in_conda_forge = (PackageMetadata(metadata_version='1.0', name='zarpaint', version='0.2.0', dynamic=None, platform=None, supported_platform=None, summary='Paint segmentations directly to on-disk/remote zarr arrays', description=None, description_content_type=None, keywords=None, home_page='https://github.com/jni/zarpaint', download_url=None, author='Abigail McGovern and Juan Nunez-Iglesias', author_email=None, maintainer=None, maintainer_email=None, license='BSD-3-Clause', classifier=None, requires_dist=None, requires_python=None, requires_external=None, project_url=None, provides_extra=None, provides_dist=None, obsoletes_dist=None), True)
        info = PackageMetadata(metadata_version='1.0', name='zarpaint', version='0.2.0', dynamic=None, platform=None, supported_platform=None, summary='Paint segmentations directly to on-disk/remote zarr arrays', description=None, description_content_type=None, keywords=None, home_page='https://github.com/jni/zarpaint', download_url=None, author='Abigail McGovern and Juan Nunez-Iglesias', author_email=None, maintainer=None, maintainer_email=None, license='BSD-3-Clause', classifier=None, requires_dist=None, requires_python=None, requires_external=None, project_url=None, provides_extra=None, provides_dist=None, obsoletes_dist=None)
        is_available_in_conda_forge = True
    102     if info and info not in already_yielded:
    103         already_yielded.append(info)

File /usr/lib64/python3.9/concurrent/futures/_base.py:439, in Future.result(self=None, timeout=None)
    437     raise CancelledError()
    438 elif self._state == FINISHED:
--> 439     return self.__get_result()
        self = None
    441 self._condition.wait(timeout)
    443 if self._state in [CANCELLED, CANCELLED_AND_NOTIFIED]:

File /usr/lib64/python3.9/concurrent/futures/_base.py:391, in Future.__get_result(self=None)
    389 if self._exception:
    390     try:
--> 391         raise self._exception
        self = None
    392     finally:
    393         # Break a reference cycle with the exception in self._exception
    394         self = None

File /usr/lib64/python3.9/concurrent/futures/thread.py:58, in _WorkItem.run(self=None)
     55     return
     57 try:
---> 58     result = self.fn(*self.args, **self.kwargs)
        self = None
     59 except BaseException as exc:
     60     self.future.set_exception(exc)

File /home/cnstt/test-nap/venv1/lib/python3.9/site-packages/napari/plugins/hub.py:47, in hub_plugin_info(name='napari-deepfinder', min_dev_status=3, conda_forge=False)
     44 except error.HTTPError:
     45     return None, False
---> 47 version = info["version"]
        info = {'conda': [], 'display_name': '', 'plugin_types': [], 'reader_file_extensions': [], 'writer_file_extensions': [], 'writer_save_layers': []}
     48 norm_name = normalized_name(info["name"])
     49 is_available_in_conda_forge = True

KeyError: 'version'


Expected behavior

This error should not happen!

Environment

napari: 0.4.16 Platform: Linux-5.18.10-100.fc35.x86_64-x86_64-with-glibc2.34 System: Fedora Linux 35 (Workstation Edition) Python: 3.9.13 (main, Jun 9 2022, 00:00:00) [GCC 11.3.1 20220421 (Red Hat 11.3.1-2)] Qt: 5.15.2 PyQt5: 5.15.7 NumPy: 1.23.1 SciPy: 1.8.1 Dask: 2022.7.1 VisPy: 0.10.0

OpenGL:

  • GL version: 4.6.0 NVIDIA 515.48.07
  • MAX_TEXTURE_SIZE: 16384

Screens:

  • screen 1: resolution 1920x1200, scale 1.0

Plugins:

  • console: 0.0.4
  • napari-svg: 0.1.6
  • scikit-image: 0.4.16

About this issue

  • Original URL
  • State: closed
  • Created 2 years ago
  • Comments: 15 (10 by maintainers)

Most upvoted comments

we need to update hub.py to more gracefully handle a payload that doesn’t have the expected info

I would recommend this until we can properly spec and build an API that isn’t just our frontend API exposed to the world 😛

I suggested a revision to #4863 that should help to avoid any stray fields (since any real plugin will have a name): https://github.com/napari/napari/pull/4863/files#r929364346

ok, well… use the PyPI API for now, and we’ll put your PR on hold until we get some feedback from the hub team

When using the napari hub api, I get this error but fortunately the installation of the plugin succeeds nevertheless 😃

yeah. that’s cause the hub is only attempting to provide the metadata for plugins (not the actual plugin)… and it looks like something’s going on with their payloads at the moment

@goanpeca, @neuromusic … if we’re going to use the hub API in napari code, it would be very handy if we had

  1. some type hinting with TypedDicts in hub.py that would show us the structure we’re supposed to expect from those payloads
  2. a link in hub.py to the exact source code page in napari-hub that defines the schema (I couldn’t in the swagger-docs what structure we should be expecting) … edit scratch that, I found it at the bottom of the page. in that case, an idea of when these keys might be missing 😃

What’s fun is I just got this error when installing a different plugin! (napari-serialcellpose from GitHub):

File ~/Dev/miniforge3/envs/pytorch-env/lib/python3.9/site-packages/napari/plugins/hub.py:47, in hub_plugin_info(name='napari-deepfinder', min_dev_status=3, conda_forge=False)
     44 except error.HTTPError:
     45     return None, False
---> 47 version = info["version"]
        info = {'conda': [], 'display_name': '', 'plugin_types': [], 'reader_file_extensions': [], 'writer_file_extensions': [], 'writer_save_layers': []}
     48 norm_name = normalized_name(info["name"])
     49 is_available_in_conda_forge = True

KeyError: 'version'