From cc76d558d4d392e46d8c7ba4d97ce26b4ce16d5e Mon Sep 17 00:00:00 2001 From: Pam <54282105+ppwadhwa@users.noreply.github.com> Date: Fri, 10 Mar 2023 07:04:20 -0600 Subject: [PATCH 01/13] Update plugin dialog design & functionality to add conda install (#5198) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Changes the plugin dialog to match the design discussed in #4952 Co-authored-by: Draga Doncila Pop <17995243+DragaDoncila@users.noreply.github.com> Co-authored-by: Gonzalo Pena-Castellanos Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Grzegorz Bokota Co-authored-by: Daniel Althviz Moré Co-authored-by: Peter Sobolewski <76622105+psobolewskiPhD@users.noreply.github.com> --- napari_plugin_manager/plugins/npe2api.py | 101 +++++++++++++++++++++++ 1 file changed, 101 insertions(+) create mode 100644 napari_plugin_manager/plugins/npe2api.py diff --git a/napari_plugin_manager/plugins/npe2api.py b/napari_plugin_manager/plugins/npe2api.py new file mode 100644 index 0000000..3c8a67a --- /dev/null +++ b/napari_plugin_manager/plugins/npe2api.py @@ -0,0 +1,101 @@ +""" +These convenience functions will be useful for searching pypi for packages +that match the plugin naming convention, and retrieving related metadata. +""" +import json +from concurrent.futures import ThreadPoolExecutor +from functools import lru_cache +from typing import Dict, Iterator, List, Optional, Tuple, TypedDict, cast +from urllib.request import Request, urlopen + +from npe2 import PackageMetadata + +from napari.plugins.utils import normalized_name + +PyPIname = str + + +@lru_cache +def _user_agent() -> str: + """Return a user agent string for use in http requests.""" + import platform + + from napari import __version__ + from napari.utils import misc + + if misc.running_as_bundled_app(): + env = 'briefcase' + elif misc.running_as_constructor_app(): + env = 'constructor' + elif misc.in_jupyter(): + env = 'jupyter' + elif misc.in_ipython(): + env = 'ipython' + else: + env = 'python' + + parts = [ + ('napari', __version__), + ('runtime', env), + (platform.python_implementation(), platform.python_version()), + (platform.system(), platform.release()), + ] + return ' '.join(f'{k}/{v}' for k, v in parts) + + +class SummaryDict(TypedDict): + """Objects returned at https://npe2api.vercel.app/api/extended_summary .""" + + name: PyPIname + version: str + display_name: str + summary: str + author: str + license: str + home_page: str + + +@lru_cache +def plugin_summaries() -> List[SummaryDict]: + """Return PackageMetadata object for all known napari plugins.""" + url = "https://npe2api.vercel.app/api/extended_summary" + with urlopen(Request(url, headers={'User-Agent': _user_agent()})) as resp: + return json.load(resp) + + +@lru_cache +def conda_map() -> Dict[PyPIname, Optional[str]]: + """Return map of PyPI package name to conda_channel/package_name ().""" + url = "https://npe2api.vercel.app/api/conda" + with urlopen(Request(url, headers={'User-Agent': _user_agent()})) as resp: + return json.load(resp) + + +def iter_napari_plugin_info() -> ( + Iterator[Tuple[PackageMetadata, bool, Dict[str, str]]] +): + """Iterator of tuples of ProjectInfo, Conda availability for all napari plugins.""" + with ThreadPoolExecutor() as executor: + data = executor.submit(plugin_summaries) + _conda = executor.submit(conda_map) + + conda = _conda.result() + for info in data.result(): + _info = cast(Dict[str, str], dict(info)) + + # TODO: use this better. + # this would require changing the api that qt_plugin_dialog expects to + # receive + _info.pop("display_name", None) + + # TODO: once the new version of npe2 is out, this can be refactored + # to all the metadata includes the conda and pypi versions. + extra_info = { + "home_page": _info.get("home_page", ""), + "pypi_versions": _info.pop("pypi_versions"), + "conda_versions": _info.pop("conda_versions"), + } + name = _info.pop("name") + meta = PackageMetadata(name=normalized_name(name), **_info) + + yield meta, (name in conda), extra_info From 9c7a98440010d65a80e3ba5a8953b686636a9a14 Mon Sep 17 00:00:00 2001 From: Grzegorz Bokota Date: Tue, 18 Apr 2023 20:57:44 +0200 Subject: [PATCH 02/13] Maint: Bump mypy (#5727) # Fixes/Closes Closes #5724 # Description # References ## Type of change - [x] Bug-fix (non-breaking change which fixes an issue) - [ ] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) - [ ] This change requires a documentation update # How has this been tested? - [ ] example: the test suite for my feature covers cases x, y, and z - [ ] example: all tests pass with my change - [ ] example: I check if my changes works with both PySide and PyQt backends as there are small differences between the two Qt bindings. ## Final checklist: - [ ] My PR is the minimum possible work for the desired functionality - [ ] I have commented my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes to the documentation - [ ] I have added tests that prove my fix is effective or that my feature works - [ ] If I included new strings, I have used `trans.` to make them localizable. For more information see our [translations guide](https://napari.org/developers/translations.html). --- napari_plugin_manager/plugins/npe2api.py | 37 +++++++++++++++--------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/napari_plugin_manager/plugins/npe2api.py b/napari_plugin_manager/plugins/npe2api.py index 3c8a67a..9d35e72 100644 --- a/napari_plugin_manager/plugins/npe2api.py +++ b/napari_plugin_manager/plugins/npe2api.py @@ -5,10 +5,19 @@ import json from concurrent.futures import ThreadPoolExecutor from functools import lru_cache -from typing import Dict, Iterator, List, Optional, Tuple, TypedDict, cast +from typing import ( + Dict, + Iterator, + List, + Optional, + Tuple, + TypedDict, + cast, +) from urllib.request import Request, urlopen from npe2 import PackageMetadata +from typing_extensions import NotRequired from napari.plugins.utils import normalized_name @@ -46,13 +55,15 @@ def _user_agent() -> str: class SummaryDict(TypedDict): """Objects returned at https://npe2api.vercel.app/api/extended_summary .""" - name: PyPIname + name: NotRequired[PyPIname] version: str - display_name: str + display_name: NotRequired[str] summary: str author: str license: str home_page: str + pypi_versions: NotRequired[List[str]] + conda_versions: NotRequired[List[str]] @lru_cache @@ -71,9 +82,7 @@ def conda_map() -> Dict[PyPIname, Optional[str]]: return json.load(resp) -def iter_napari_plugin_info() -> ( - Iterator[Tuple[PackageMetadata, bool, Dict[str, str]]] -): +def iter_napari_plugin_info() -> Iterator[Tuple[PackageMetadata, bool, dict]]: """Iterator of tuples of ProjectInfo, Conda availability for all napari plugins.""" with ThreadPoolExecutor() as executor: data = executor.submit(plugin_summaries) @@ -81,21 +90,21 @@ def iter_napari_plugin_info() -> ( conda = _conda.result() for info in data.result(): - _info = cast(Dict[str, str], dict(info)) + info_ = cast(SummaryDict, dict(info)) # TODO: use this better. # this would require changing the api that qt_plugin_dialog expects to # receive - _info.pop("display_name", None) + info_.pop("display_name", None) # TODO: once the new version of npe2 is out, this can be refactored # to all the metadata includes the conda and pypi versions. extra_info = { - "home_page": _info.get("home_page", ""), - "pypi_versions": _info.pop("pypi_versions"), - "conda_versions": _info.pop("conda_versions"), + 'home_page': info_.get("home_page", ""), + 'pypi_versions': info_.pop("pypi_versions"), + 'conda_versions': info_.pop("conda_versions"), } - name = _info.pop("name") - meta = PackageMetadata(name=normalized_name(name), **_info) + info_["name"] = normalized_name(info_["name"]) + meta = PackageMetadata(**info_) - yield meta, (name in conda), extra_info + yield meta, (info_["name"] in conda), extra_info From 6419819751509cdbfd7242c4833c8c1c5e47be2c Mon Sep 17 00:00:00 2001 From: jaimergp Date: Wed, 24 May 2023 16:36:28 +0000 Subject: [PATCH 03/13] Remove support for briefcase installers (#5804) # Fixes/Closes Closes https://github.com/napari/napari/issues/5506 # Description The Briefcase bundles have not been working for a while (at least in some platforms), nobody is testing them either, and our development efforts are mostly directed to the `constructor` installers. In this PR, they are removed to [avoid CI waste](https://github.com/napari/napari/issues/5660) and permit deleting some strange code paths for Briefcase workarounds. # References ## Type of change - [X] Removes / deprecates code # How has this been tested? - [x] No CI jobs for Briefcase - [x] Tests pass without the extra Briefcase workarounds ## Final checklist: - [X] My PR is the minimum possible work for the desired functionality - [x] I have made corresponding changes to the documentation: https://github.com/napari/docs/pull/147 --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Grzegorz Bokota --- napari_plugin_manager/plugins/npe2api.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/napari_plugin_manager/plugins/npe2api.py b/napari_plugin_manager/plugins/npe2api.py index 9d35e72..cb87fd7 100644 --- a/napari_plugin_manager/plugins/npe2api.py +++ b/napari_plugin_manager/plugins/npe2api.py @@ -32,9 +32,7 @@ def _user_agent() -> str: from napari import __version__ from napari.utils import misc - if misc.running_as_bundled_app(): - env = 'briefcase' - elif misc.running_as_constructor_app(): + if misc.running_as_constructor_app(): env = 'constructor' elif misc.in_jupyter(): env = 'jupyter' From b9b4398c02a0b10488d02d4a88920cf4d11ee3e4 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Thu, 17 Aug 2023 10:21:52 +0200 Subject: [PATCH 04/13] MAINT: Fix more typing and enable mypy on more files. (#5897) Step toward #2751 Start taking mypy errors one by one and fix/ignore them. --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Wouter-Michiel Vierdag --- napari_plugin_manager/plugins/npe2api.py | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/napari_plugin_manager/plugins/npe2api.py b/napari_plugin_manager/plugins/npe2api.py index cb87fd7..aaa9d12 100644 --- a/napari_plugin_manager/plugins/npe2api.py +++ b/napari_plugin_manager/plugins/npe2api.py @@ -50,16 +50,19 @@ def _user_agent() -> str: return ' '.join(f'{k}/{v}' for k, v in parts) -class SummaryDict(TypedDict): +class _ShortSummaryDict(TypedDict): """Objects returned at https://npe2api.vercel.app/api/extended_summary .""" name: NotRequired[PyPIname] version: str - display_name: NotRequired[str] summary: str author: str license: str home_page: str + + +class SummaryDict(_ShortSummaryDict): + display_name: NotRequired[str] pypi_versions: NotRequired[List[str]] conda_versions: NotRequired[List[str]] @@ -88,19 +91,22 @@ def iter_napari_plugin_info() -> Iterator[Tuple[PackageMetadata, bool, dict]]: conda = _conda.result() for info in data.result(): - info_ = cast(SummaryDict, dict(info)) + info_copy = dict(info) + info_copy.pop("display_name", None) + pypi_versions = info_copy.pop("pypi_versions") + conda_versions = info_copy.pop("conda_versions") + info_ = cast(_ShortSummaryDict, info_copy) # TODO: use this better. # this would require changing the api that qt_plugin_dialog expects to # receive - info_.pop("display_name", None) # TODO: once the new version of npe2 is out, this can be refactored # to all the metadata includes the conda and pypi versions. extra_info = { 'home_page': info_.get("home_page", ""), - 'pypi_versions': info_.pop("pypi_versions"), - 'conda_versions': info_.pop("conda_versions"), + 'pypi_versions': pypi_versions, + 'conda_versions': conda_versions, } info_["name"] = normalized_name(info_["name"]) meta = PackageMetadata(**info_) From 05bbeeadb74bd6cd608c1430271e5279daa854a0 Mon Sep 17 00:00:00 2001 From: Grzegorz Bokota Date: Sun, 31 Dec 2023 16:57:15 +0100 Subject: [PATCH 05/13] Fix check if plugin is available from conda (#6545) --- napari_plugin_manager/plugins/npe2api.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/napari_plugin_manager/plugins/npe2api.py b/napari_plugin_manager/plugins/npe2api.py index aaa9d12..462f7f3 100644 --- a/napari_plugin_manager/plugins/npe2api.py +++ b/napari_plugin_manager/plugins/npe2api.py @@ -90,6 +90,7 @@ def iter_napari_plugin_info() -> Iterator[Tuple[PackageMetadata, bool, dict]]: _conda = executor.submit(conda_map) conda = _conda.result() + conda_set = {normalized_name(x) for x in conda} for info in data.result(): info_copy = dict(info) info_copy.pop("display_name", None) @@ -111,4 +112,4 @@ def iter_napari_plugin_info() -> Iterator[Tuple[PackageMetadata, bool, dict]]: info_["name"] = normalized_name(info_["name"]) meta = PackageMetadata(**info_) - yield meta, (info_["name"] in conda), extra_info + yield meta, (info_["name"] in conda_set), extra_info From 58c4c74d44959383b3bee1decb3e0b625dc0e5ac Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 2 Feb 2024 14:23:43 +0100 Subject: [PATCH 06/13] pre-commit autoupdate (#6581) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/astral-sh/ruff-pre-commit: v0.1.9 → v0.1.11](https://github.com/astral-sh/ruff-pre-commit/compare/v0.1.9...v0.1.11) --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Grzegorz Bokota --- napari_plugin_manager/plugins/npe2api.py | 1 + 1 file changed, 1 insertion(+) diff --git a/napari_plugin_manager/plugins/npe2api.py b/napari_plugin_manager/plugins/npe2api.py index 462f7f3..caabee1 100644 --- a/napari_plugin_manager/plugins/npe2api.py +++ b/napari_plugin_manager/plugins/npe2api.py @@ -2,6 +2,7 @@ These convenience functions will be useful for searching pypi for packages that match the plugin naming convention, and retrieving related metadata. """ + import json from concurrent.futures import ThreadPoolExecutor from functools import lru_cache From 6f93b39512c3c48a982f293c18b42dc9c868721d Mon Sep 17 00:00:00 2001 From: Grzegorz Bokota Date: Sun, 18 Feb 2024 00:00:34 +0100 Subject: [PATCH 07/13] Use ruff to format strings to single quotes. (#6407) # Description Based on a discussion from #6386 I updated the ruff configuration to enable `Q000` https://docs.astral.sh/ruff/rules/#flake8-quotes-q rule and configured it to use a single quotes string. We have many double quotes string, but less than single quotes. This PR does not change the quotation of docstrings (`"""`) and multiline strings (`"""`) as they are already enforced by ruff configuration and could be easy changed. to see configuration changes please use: https://github.com/napari/napari/pull/6407/commits/a422ad7515c04c386eb97eea364d60444ba89af5 cc @jni @brisvag --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- napari_plugin_manager/plugins/npe2api.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/napari_plugin_manager/plugins/npe2api.py b/napari_plugin_manager/plugins/npe2api.py index caabee1..5f2cbc4 100644 --- a/napari_plugin_manager/plugins/npe2api.py +++ b/napari_plugin_manager/plugins/npe2api.py @@ -71,7 +71,7 @@ class SummaryDict(_ShortSummaryDict): @lru_cache def plugin_summaries() -> List[SummaryDict]: """Return PackageMetadata object for all known napari plugins.""" - url = "https://npe2api.vercel.app/api/extended_summary" + url = 'https://npe2api.vercel.app/api/extended_summary' with urlopen(Request(url, headers={'User-Agent': _user_agent()})) as resp: return json.load(resp) @@ -79,7 +79,7 @@ def plugin_summaries() -> List[SummaryDict]: @lru_cache def conda_map() -> Dict[PyPIname, Optional[str]]: """Return map of PyPI package name to conda_channel/package_name ().""" - url = "https://npe2api.vercel.app/api/conda" + url = 'https://npe2api.vercel.app/api/conda' with urlopen(Request(url, headers={'User-Agent': _user_agent()})) as resp: return json.load(resp) @@ -94,9 +94,9 @@ def iter_napari_plugin_info() -> Iterator[Tuple[PackageMetadata, bool, dict]]: conda_set = {normalized_name(x) for x in conda} for info in data.result(): info_copy = dict(info) - info_copy.pop("display_name", None) - pypi_versions = info_copy.pop("pypi_versions") - conda_versions = info_copy.pop("conda_versions") + info_copy.pop('display_name', None) + pypi_versions = info_copy.pop('pypi_versions') + conda_versions = info_copy.pop('conda_versions') info_ = cast(_ShortSummaryDict, info_copy) # TODO: use this better. @@ -106,11 +106,11 @@ def iter_napari_plugin_info() -> Iterator[Tuple[PackageMetadata, bool, dict]]: # TODO: once the new version of npe2 is out, this can be refactored # to all the metadata includes the conda and pypi versions. extra_info = { - 'home_page': info_.get("home_page", ""), + 'home_page': info_.get('home_page', ''), 'pypi_versions': pypi_versions, 'conda_versions': conda_versions, } - info_["name"] = normalized_name(info_["name"]) + info_['name'] = normalized_name(info_['name']) meta = PackageMetadata(**info_) - yield meta, (info_["name"] in conda_set), extra_info + yield meta, (info_['name'] in conda_set), extra_info From a73d915a89abc84682769223389829f06da5a8d1 Mon Sep 17 00:00:00 2001 From: Grzegorz Bokota Date: Mon, 25 Mar 2024 09:26:09 +0100 Subject: [PATCH 08/13] Drop Python 3.8, add Python 3.12 testing (#6738) # Description Drop python 3.8 start testing on python 3.12 * Disable PySide6 for python 3.12 (need #6062) * Workflows updated with new versions, by bumping each python version by 1 (as well as project and tox.ini) * a couple of "if version < 3.9" checks removed * Change List and Tuple to list and tuple in type annotation (part of them automatically) Also, automatically by pre-commit * a couple of parenthesized context managers * change to import from `collections` instead of `typing` for a bunch of types (like `Sequence`) * import part of things from `typing` instead of `typing_extension` (like `Annotated`). * one lru_cache to cache --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- napari_plugin_manager/plugins/npe2api.py | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/napari_plugin_manager/plugins/npe2api.py b/napari_plugin_manager/plugins/npe2api.py index 5f2cbc4..8120bc6 100644 --- a/napari_plugin_manager/plugins/npe2api.py +++ b/napari_plugin_manager/plugins/npe2api.py @@ -4,14 +4,11 @@ """ import json +from collections.abc import Iterator from concurrent.futures import ThreadPoolExecutor from functools import lru_cache from typing import ( - Dict, - Iterator, - List, Optional, - Tuple, TypedDict, cast, ) @@ -64,12 +61,12 @@ class _ShortSummaryDict(TypedDict): class SummaryDict(_ShortSummaryDict): display_name: NotRequired[str] - pypi_versions: NotRequired[List[str]] - conda_versions: NotRequired[List[str]] + pypi_versions: NotRequired[list[str]] + conda_versions: NotRequired[list[str]] @lru_cache -def plugin_summaries() -> List[SummaryDict]: +def plugin_summaries() -> list[SummaryDict]: """Return PackageMetadata object for all known napari plugins.""" url = 'https://npe2api.vercel.app/api/extended_summary' with urlopen(Request(url, headers={'User-Agent': _user_agent()})) as resp: @@ -77,14 +74,14 @@ def plugin_summaries() -> List[SummaryDict]: @lru_cache -def conda_map() -> Dict[PyPIname, Optional[str]]: +def conda_map() -> dict[PyPIname, Optional[str]]: """Return map of PyPI package name to conda_channel/package_name ().""" url = 'https://npe2api.vercel.app/api/conda' with urlopen(Request(url, headers={'User-Agent': _user_agent()})) as resp: return json.load(resp) -def iter_napari_plugin_info() -> Iterator[Tuple[PackageMetadata, bool, dict]]: +def iter_napari_plugin_info() -> Iterator[tuple[PackageMetadata, bool, dict]]: """Iterator of tuples of ProjectInfo, Conda availability for all napari plugins.""" with ThreadPoolExecutor() as executor: data = executor.submit(plugin_summaries) From bed9b6acaa5f71f9f05c64fed359bb206d3c61d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20Pe=C3=B1a-Castellanos?= Date: Wed, 17 Apr 2024 18:52:24 -0500 Subject: [PATCH 09/13] Add extra field to store plugin display name (#6841) Co-authored-by: Grzegorz Bokota --- napari_plugin_manager/plugins/npe2api.py | 1 + 1 file changed, 1 insertion(+) diff --git a/napari_plugin_manager/plugins/npe2api.py b/napari_plugin_manager/plugins/npe2api.py index 8120bc6..3c8c9c3 100644 --- a/napari_plugin_manager/plugins/npe2api.py +++ b/napari_plugin_manager/plugins/npe2api.py @@ -104,6 +104,7 @@ def iter_napari_plugin_info() -> Iterator[tuple[PackageMetadata, bool, dict]]: # to all the metadata includes the conda and pypi versions. extra_info = { 'home_page': info_.get('home_page', ''), + 'display_name': info.get('display_name', ''), 'pypi_versions': pypi_versions, 'conda_versions': conda_versions, } From bd619110319f08860ea0240bde8f469cb1b93af2 Mon Sep 17 00:00:00 2001 From: napari-bot <81196843+napari-bot@users.noreply.github.com> Date: Thu, 2 May 2024 19:58:04 +0800 Subject: [PATCH 10/13] Update `hypothesis`, `pytest`, `virtualenv`, bump mypy constraints and resolve pointed problems. (#6866) Updated packages: `filelock`, `hypothesis`, `pyproject-hooks`, `pytest`, `virtualenv` Fix workflow for bumping mypy constraints and manual bump them, then resolve new pointed bugs. --------- Co-authored-by: napari-bot Co-authored-by: Grzegorz Bokota --- napari_plugin_manager/plugins/npe2api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/napari_plugin_manager/plugins/npe2api.py b/napari_plugin_manager/plugins/npe2api.py index 3c8c9c3..d453fa9 100644 --- a/napari_plugin_manager/plugins/npe2api.py +++ b/napari_plugin_manager/plugins/npe2api.py @@ -109,6 +109,6 @@ def iter_napari_plugin_info() -> Iterator[tuple[PackageMetadata, bool, dict]]: 'conda_versions': conda_versions, } info_['name'] = normalized_name(info_['name']) - meta = PackageMetadata(**info_) + meta = PackageMetadata(**info_) # type:ignore[call-arg] yield meta, (info_['name'] in conda_set), extra_info From 73231706a152207682dc2ce8b41e8879f1cc6517 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20Pe=C3=B1a-Castellanos?= Date: Mon, 27 May 2024 03:54:43 -0500 Subject: [PATCH 11/13] Add warning notification when connectivity errors occur in when opening the plugin manager (#6931) Fixes https://github.com/napari/napari-plugin-manager/issues/26 # Description Catches connectivity errors when fetching for plugin information when opening the plugin manager. Although the issue lives in the plugin manager repo, the code that fetches the code still lives in napari, hence with the PR seem to be better resolved on this side. # Result ## Before this PR ![napari-before](https://github.com/napari/napari/assets/3627835/6e704463-2dd3-4701-9aa5-93f2501e48fd) ## With this PR ![napari](https://github.com/napari/napari/assets/3627835/ffa3ad0a-da18-4e76-a4aa-8a007f90ce36) The warning reads: >There seems to be an issue with network connectivity. Remote plugins cannot be installed, only local ones. --- napari_plugin_manager/plugins/npe2api.py | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/napari_plugin_manager/plugins/npe2api.py b/napari_plugin_manager/plugins/npe2api.py index d453fa9..b6f6511 100644 --- a/napari_plugin_manager/plugins/npe2api.py +++ b/napari_plugin_manager/plugins/npe2api.py @@ -12,12 +12,14 @@ TypedDict, cast, ) +from urllib.error import HTTPError, URLError from urllib.request import Request, urlopen from npe2 import PackageMetadata from typing_extensions import NotRequired from napari.plugins.utils import normalized_name +from napari.utils.notifications import show_warning PyPIname = str @@ -65,7 +67,6 @@ class SummaryDict(_ShortSummaryDict): conda_versions: NotRequired[list[str]] -@lru_cache def plugin_summaries() -> list[SummaryDict]: """Return PackageMetadata object for all known napari plugins.""" url = 'https://npe2api.vercel.app/api/extended_summary' @@ -83,13 +84,22 @@ def conda_map() -> dict[PyPIname, Optional[str]]: def iter_napari_plugin_info() -> Iterator[tuple[PackageMetadata, bool, dict]]: """Iterator of tuples of ProjectInfo, Conda availability for all napari plugins.""" - with ThreadPoolExecutor() as executor: - data = executor.submit(plugin_summaries) - _conda = executor.submit(conda_map) + try: + with ThreadPoolExecutor() as executor: + data = executor.submit(plugin_summaries) + _conda = executor.submit(conda_map) + + conda = _conda.result() + data_set = data.result() + except (HTTPError, URLError): + show_warning( + 'There seems to be an issue with network connectivity. ' + 'Remote plugins cannot be installed, only local ones.\n' + ) + return - conda = _conda.result() conda_set = {normalized_name(x) for x in conda} - for info in data.result(): + for info in data_set: info_copy = dict(info) info_copy.pop('display_name', None) pypi_versions = info_copy.pop('pypi_versions') From 9080174b20f9c41a1341b55dcc7de824f8b24a7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20Pe=C3=B1a-Castellanos?= Date: Mon, 27 May 2024 18:43:46 -0500 Subject: [PATCH 12/13] Move npe2api.py from napari repo to this repo --- napari_plugin_manager/{plugins => }/npe2api.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename napari_plugin_manager/{plugins => }/npe2api.py (100%) diff --git a/napari_plugin_manager/plugins/npe2api.py b/napari_plugin_manager/npe2api.py similarity index 100% rename from napari_plugin_manager/plugins/npe2api.py rename to napari_plugin_manager/npe2api.py From 86716725f25aa3e33af94ad88ff5dd4a2fc0e9f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20Pe=C3=B1a-Castellanos?= Date: Mon, 27 May 2024 18:49:35 -0500 Subject: [PATCH 13/13] Fix and updte import --- napari_plugin_manager/npe2api.py | 5 ++--- napari_plugin_manager/qt_plugin_dialog.py | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/napari_plugin_manager/npe2api.py b/napari_plugin_manager/npe2api.py index b6f6511..24e01f9 100644 --- a/napari_plugin_manager/npe2api.py +++ b/napari_plugin_manager/npe2api.py @@ -15,11 +15,10 @@ from urllib.error import HTTPError, URLError from urllib.request import Request, urlopen -from npe2 import PackageMetadata -from typing_extensions import NotRequired - from napari.plugins.utils import normalized_name from napari.utils.notifications import show_warning +from npe2 import PackageMetadata +from typing_extensions import NotRequired PyPIname = str diff --git a/napari_plugin_manager/qt_plugin_dialog.py b/napari_plugin_manager/qt_plugin_dialog.py index 3568846..d86762a 100644 --- a/napari_plugin_manager/qt_plugin_dialog.py +++ b/napari_plugin_manager/qt_plugin_dialog.py @@ -12,7 +12,6 @@ from napari._qt.qthreading import create_worker from napari._qt.widgets.qt_message_popup import WarnPopup from napari._qt.widgets.qt_tooltip import QtToolTipLabel -from napari.plugins.npe2api import iter_napari_plugin_info from napari.plugins.utils import normalized_name from napari.settings import get_settings from napari.utils.misc import ( @@ -42,6 +41,7 @@ ) from superqt import QCollapsible, QElidingLabel +from napari_plugin_manager.npe2api import iter_napari_plugin_info from napari_plugin_manager.qt_package_installer import ( InstallerActions, InstallerQueue,