napari-plugin-manager 0.1.5rc1__py3-none-any.whl → 0.1.6__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- napari_plugin_manager/_tests/test_npe2api.py +1 -0
- napari_plugin_manager/_tests/test_utils.py +32 -1
- napari_plugin_manager/_version.py +2 -2
- napari_plugin_manager/base_qt_package_installer.py +3 -3
- napari_plugin_manager/base_qt_plugin_dialog.py +4 -3
- napari_plugin_manager/npe2api.py +8 -3
- napari_plugin_manager/utils.py +55 -0
- {napari_plugin_manager-0.1.5rc1.dist-info → napari_plugin_manager-0.1.6.dist-info}/METADATA +1 -1
- napari_plugin_manager-0.1.6.dist-info/RECORD +23 -0
- {napari_plugin_manager-0.1.5rc1.dist-info → napari_plugin_manager-0.1.6.dist-info}/WHEEL +1 -1
- napari_plugin_manager-0.1.5rc1.dist-info/RECORD +0 -23
- {napari_plugin_manager-0.1.5rc1.dist-info → napari_plugin_manager-0.1.6.dist-info}/licenses/LICENSE +0 -0
- {napari_plugin_manager-0.1.5rc1.dist-info → napari_plugin_manager-0.1.6.dist-info}/top_level.txt +0 -0
|
@@ -3,7 +3,7 @@ from unittest.mock import patch
|
|
|
3
3
|
|
|
4
4
|
import pytest
|
|
5
5
|
|
|
6
|
-
from napari_plugin_manager.utils import is_conda_package
|
|
6
|
+
from napari_plugin_manager.utils import get_homepage_url, is_conda_package
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
@pytest.mark.parametrize(
|
|
@@ -25,3 +25,34 @@ def test_is_conda_package(pkg_name, expected, tmp_path):
|
|
|
25
25
|
|
|
26
26
|
with patch.object(sys, 'prefix', tmp_path):
|
|
27
27
|
assert is_conda_package(pkg_name) is expected
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def test_get_homepage_url():
|
|
31
|
+
assert get_homepage_url({}) == ''
|
|
32
|
+
|
|
33
|
+
meta = {
|
|
34
|
+
'Home-page': None,
|
|
35
|
+
}
|
|
36
|
+
assert get_homepage_url(meta) == ''
|
|
37
|
+
|
|
38
|
+
meta['Home-page'] = 'http://example.com'
|
|
39
|
+
assert get_homepage_url(meta) == 'http://example.com'
|
|
40
|
+
|
|
41
|
+
meta['Project-URL'] = ['Home Page, http://projurl.com']
|
|
42
|
+
assert get_homepage_url(meta) == 'http://example.com'
|
|
43
|
+
|
|
44
|
+
meta['home_page'] = meta.pop('Home-page')
|
|
45
|
+
meta['project_url'] = meta.pop('Project-URL')
|
|
46
|
+
assert get_homepage_url(meta) == 'http://example.com'
|
|
47
|
+
|
|
48
|
+
meta['home_page'] = None
|
|
49
|
+
assert get_homepage_url(meta) == 'http://projurl.com'
|
|
50
|
+
|
|
51
|
+
meta['project_url'] = ['Source Code, http://projurl.com']
|
|
52
|
+
assert get_homepage_url(meta) == 'http://projurl.com'
|
|
53
|
+
|
|
54
|
+
meta['project_url'] = ['Source, http://projurl.com']
|
|
55
|
+
assert get_homepage_url(meta) == 'http://projurl.com'
|
|
56
|
+
|
|
57
|
+
meta['project_url'] = None
|
|
58
|
+
assert get_homepage_url(meta) == ''
|
|
@@ -23,7 +23,7 @@ from logging import getLogger
|
|
|
23
23
|
from pathlib import Path
|
|
24
24
|
from subprocess import call
|
|
25
25
|
from tempfile import gettempdir
|
|
26
|
-
from typing import TypedDict
|
|
26
|
+
from typing import Optional, TypedDict
|
|
27
27
|
|
|
28
28
|
from napari.plugins import plugin_manager
|
|
29
29
|
from napari.plugins.npe2api import _user_agent
|
|
@@ -636,8 +636,8 @@ class InstallerQueue(QObject):
|
|
|
636
636
|
def _on_process_done(
|
|
637
637
|
self,
|
|
638
638
|
exit_code: int | None = None,
|
|
639
|
-
exit_status: QProcess.ExitStatus
|
|
640
|
-
error: QProcess.ProcessError
|
|
639
|
+
exit_status: Optional[QProcess.ExitStatus] = None, # noqa
|
|
640
|
+
error: Optional[QProcess.ProcessError] = None, # noqa
|
|
641
641
|
):
|
|
642
642
|
item = None
|
|
643
643
|
with contextlib.suppress(IndexError):
|
|
@@ -53,7 +53,7 @@ from napari_plugin_manager.base_qt_package_installer import (
|
|
|
53
53
|
)
|
|
54
54
|
from napari_plugin_manager.qt_warning_dialog import RestartWarningDialog
|
|
55
55
|
from napari_plugin_manager.qt_widgets import ClickableLabel
|
|
56
|
-
from napari_plugin_manager.utils import is_conda_package
|
|
56
|
+
from napari_plugin_manager.utils import get_homepage_url, is_conda_package
|
|
57
57
|
|
|
58
58
|
CONDA = 'Conda'
|
|
59
59
|
PYPI = 'PyPI'
|
|
@@ -1225,7 +1225,8 @@ class BaseQtPluginDialog(QDialog):
|
|
|
1225
1225
|
self.already_installed.add(norm_name)
|
|
1226
1226
|
else:
|
|
1227
1227
|
meta = {}
|
|
1228
|
-
|
|
1228
|
+
meta_dict = meta if isinstance(meta, dict) else meta.json
|
|
1229
|
+
home_page = get_homepage_url(meta_dict)
|
|
1229
1230
|
self.installed_list.addItem(
|
|
1230
1231
|
self.PROJECT_INFO_VERSION_CLASS(
|
|
1231
1232
|
display_name=norm_name,
|
|
@@ -1236,7 +1237,7 @@ class BaseQtPluginDialog(QDialog):
|
|
|
1236
1237
|
name=norm_name,
|
|
1237
1238
|
version=meta.get('version', ''),
|
|
1238
1239
|
summary=meta.get('summary', ''),
|
|
1239
|
-
home_page=
|
|
1240
|
+
home_page=home_page,
|
|
1240
1241
|
author=meta.get('author', ''),
|
|
1241
1242
|
license=meta.get('license', ''),
|
|
1242
1243
|
),
|
napari_plugin_manager/npe2api.py
CHANGED
|
@@ -19,6 +19,8 @@ from napari.utils.notifications import show_warning
|
|
|
19
19
|
from npe2 import PackageMetadata
|
|
20
20
|
from typing_extensions import NotRequired
|
|
21
21
|
|
|
22
|
+
from napari_plugin_manager.utils import get_homepage_url
|
|
23
|
+
|
|
22
24
|
PyPIname = str
|
|
23
25
|
|
|
24
26
|
|
|
@@ -98,12 +100,15 @@ def iter_napari_plugin_info() -> Iterator[tuple[PackageMetadata, bool, dict]]:
|
|
|
98
100
|
|
|
99
101
|
conda_set = {normalized_name(x) for x in conda}
|
|
100
102
|
for info in data_set:
|
|
101
|
-
info_copy = dict(info)
|
|
103
|
+
info_copy: dict[str, str | list[str]] = dict(info)
|
|
102
104
|
info_copy.pop('display_name', None)
|
|
103
105
|
pypi_versions = info_copy.pop('pypi_versions')
|
|
104
106
|
conda_versions = info_copy.pop('conda_versions')
|
|
105
107
|
info_ = cast(_ShortSummaryDict, info_copy)
|
|
106
|
-
|
|
108
|
+
home_page = get_homepage_url(info_copy)
|
|
109
|
+
# this URL is used for the widget, so we have to replace the home_page
|
|
110
|
+
# link here as well as returning it in extra_info
|
|
111
|
+
info_['home_page'] = home_page
|
|
107
112
|
# TODO: use this better.
|
|
108
113
|
# this would require changing the api that qt_plugin_dialog expects to
|
|
109
114
|
# receive
|
|
@@ -111,7 +116,7 @@ def iter_napari_plugin_info() -> Iterator[tuple[PackageMetadata, bool, dict]]:
|
|
|
111
116
|
# TODO: once the new version of npe2 is out, this can be refactored
|
|
112
117
|
# to all the metadata includes the conda and pypi versions.
|
|
113
118
|
extra_info = {
|
|
114
|
-
'home_page':
|
|
119
|
+
'home_page': home_page,
|
|
115
120
|
'display_name': info.get('display_name', ''),
|
|
116
121
|
'pypi_versions': pypi_versions,
|
|
117
122
|
'conda_versions': conda_versions,
|
napari_plugin_manager/utils.py
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import re
|
|
2
|
+
import string
|
|
2
3
|
import sys
|
|
3
4
|
from pathlib import Path
|
|
4
5
|
|
|
@@ -19,3 +20,57 @@ def is_conda_package(pkg: str, prefix: str | None = None) -> bool:
|
|
|
19
20
|
re.match(rf"{pkg}-[^-]+-[^-]+.json", p.name)
|
|
20
21
|
for p in conda_meta_dir.glob(f"{pkg}-*-*.json")
|
|
21
22
|
)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def normalize_label(label: str) -> str:
|
|
26
|
+
"""Normalize project URL label.
|
|
27
|
+
|
|
28
|
+
Code reproduced from:
|
|
29
|
+
https://packaging.python.org/en/latest/specifications/well-known-project-urls/#label-normalization
|
|
30
|
+
"""
|
|
31
|
+
chars_to_remove = string.punctuation + string.whitespace
|
|
32
|
+
removal_map = str.maketrans("", "", chars_to_remove)
|
|
33
|
+
return label.translate(removal_map).lower()
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def get_homepage_url(metadata: dict[str, str | list[str] | None]) -> str:
|
|
37
|
+
"""Get URL for package homepage, if available.
|
|
38
|
+
|
|
39
|
+
Checks metadata first for `Home-page` field before
|
|
40
|
+
looking for `Project-URL` 'homepage' label and finally
|
|
41
|
+
'source'/'sourcecode' label.
|
|
42
|
+
|
|
43
|
+
Parameters
|
|
44
|
+
----------
|
|
45
|
+
metadata : dict[str, str | list[str] | None]
|
|
46
|
+
Package metadata information.
|
|
47
|
+
|
|
48
|
+
Returns
|
|
49
|
+
-------
|
|
50
|
+
str
|
|
51
|
+
Returns homepage URL if present, otherwise empty string.
|
|
52
|
+
"""
|
|
53
|
+
if not len(metadata):
|
|
54
|
+
return ''
|
|
55
|
+
|
|
56
|
+
homepage = metadata.get('Home-page', '') or metadata.get('home_page', '')
|
|
57
|
+
if isinstance(homepage, str) and len(homepage):
|
|
58
|
+
return homepage
|
|
59
|
+
|
|
60
|
+
urls = {}
|
|
61
|
+
project_urls = metadata.get('Project-URL', []) or metadata.get(
|
|
62
|
+
'project_url', []
|
|
63
|
+
)
|
|
64
|
+
if project_urls is None:
|
|
65
|
+
return ''
|
|
66
|
+
|
|
67
|
+
for url_info in project_urls:
|
|
68
|
+
label, url = url_info.split(', ')
|
|
69
|
+
urls[normalize_label(label)] = url
|
|
70
|
+
|
|
71
|
+
homepage = (
|
|
72
|
+
urls.get('homepage', '')
|
|
73
|
+
or urls.get('source', '')
|
|
74
|
+
or urls.get('sourcecode', '')
|
|
75
|
+
)
|
|
76
|
+
return homepage
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
napari_plugin_manager/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
+
napari_plugin_manager/_version.py,sha256=ESbJO0YD7TYfOUv_WDIJJgWELGepEWsoyhqVifEcXPA,511
|
|
3
|
+
napari_plugin_manager/base_qt_package_installer.py,sha256=Nw6EIjZOmKVrJJCQrb1TjUMVeey4WIbib6hzBXMcSBc,21857
|
|
4
|
+
napari_plugin_manager/base_qt_plugin_dialog.py,sha256=nLqOJs_kUdGmmlTjaQRCu-EWB-4smwjbHlYpoSJ5jZs,66093
|
|
5
|
+
napari_plugin_manager/npe2api.py,sha256=KtfV-fspfADxSHMD_AoBaRt2WFkfeZ-W4aRl0SLyna8,4367
|
|
6
|
+
napari_plugin_manager/qt_package_installer.py,sha256=j-pacW6wHVq3iJaZXsj6D-_VH25Fz-55r7clcd_CQvE,2804
|
|
7
|
+
napari_plugin_manager/qt_plugin_dialog.py,sha256=Ig4TtjCh9Z2Dx_QpiOsfLlgolPJHmJ5_7VuTU2DE0Ag,9607
|
|
8
|
+
napari_plugin_manager/qt_warning_dialog.py,sha256=ue4CeMptlBBkBctPg7qCayamrkm75iLqASSFUvwo_Bc,669
|
|
9
|
+
napari_plugin_manager/qt_widgets.py,sha256=O8t5CbN8r_16cQzshyjvhTEYdUcj7OX0-bfYIiN2uSs,356
|
|
10
|
+
napari_plugin_manager/styles.qss,sha256=9ODPba2IorJybWObWoEO9VGq4AO0IYlAa8brN14tgZU,7379
|
|
11
|
+
napari_plugin_manager/utils.py,sha256=u0OSzNbSTyk7a-NdwGfrqry_q94GiHfKQnWB20r6V9A,2247
|
|
12
|
+
napari_plugin_manager/_tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
13
|
+
napari_plugin_manager/_tests/conftest.py,sha256=OvzenfBP2oIS6x8ksr9FhPXdsLV3Q_3Kzr6PRJe45Uc,1885
|
|
14
|
+
napari_plugin_manager/_tests/test_base_installer_process.py,sha256=Cv-nBnUeNAX6pYUE1zs38I9vGtCE-ahBN4q-xcBH-pw,561
|
|
15
|
+
napari_plugin_manager/_tests/test_installer_process.py,sha256=qPSDcYWPQ08gzM38av2tcE9XCtruHv-Mo6duQ0sZp-8,11614
|
|
16
|
+
napari_plugin_manager/_tests/test_npe2api.py,sha256=nf3UG68gqoCFyiPDisToZsLpZG0uvzGUUk8H6Fy3dqE,1248
|
|
17
|
+
napari_plugin_manager/_tests/test_qt_plugin_dialog.py,sha256=IRXodt3IrE7rXHZO0R69lhz4_2mMW3MOE9LLQ5tCxWY,21727
|
|
18
|
+
napari_plugin_manager/_tests/test_utils.py,sha256=I9rYJV_JVKg6GeBlhY4A_6aY1N5MbM7jgNz5wewiWIQ,1669
|
|
19
|
+
napari_plugin_manager-0.1.6.dist-info/licenses/LICENSE,sha256=8dAlKbOqTMYe9L-gL_kEx5Xr1Sd0AbaWQDUkpiOp3vI,1506
|
|
20
|
+
napari_plugin_manager-0.1.6.dist-info/METADATA,sha256=HQvATPh6tVJmaZBlNTG9BmG488v4ATn6OoposuwN4zE,13810
|
|
21
|
+
napari_plugin_manager-0.1.6.dist-info/WHEEL,sha256=ooBFpIzZCPdw3uqIQsOo4qqbA4ZRPxHnOH7peeONza0,91
|
|
22
|
+
napari_plugin_manager-0.1.6.dist-info/top_level.txt,sha256=pmCqLetuumhY1CKSuTZ5eQsitzazrSvc7V_mkugEPTY,22
|
|
23
|
+
napari_plugin_manager-0.1.6.dist-info/RECORD,,
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
napari_plugin_manager/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
-
napari_plugin_manager/_version.py,sha256=wQaAqCMIBuF3fOz_hscpjKVmnhNsU3hxiNQwtVyHi3c,514
|
|
3
|
-
napari_plugin_manager/base_qt_package_installer.py,sha256=Tp2dt5BBT-5CsXXlQPIPxuXSDMvUgKy2kSgw2Y2G9Dk,21825
|
|
4
|
-
napari_plugin_manager/base_qt_plugin_dialog.py,sha256=gkrEkVf_WGJHjZFORMoCiw-gxCwFuTZ04Q0PGFK8gLk,65978
|
|
5
|
-
napari_plugin_manager/npe2api.py,sha256=bXmhwFkwKw_1DfnGLhWhEGaEAA3oYPFaw4eR4SX2Nyg,4075
|
|
6
|
-
napari_plugin_manager/qt_package_installer.py,sha256=j-pacW6wHVq3iJaZXsj6D-_VH25Fz-55r7clcd_CQvE,2804
|
|
7
|
-
napari_plugin_manager/qt_plugin_dialog.py,sha256=Ig4TtjCh9Z2Dx_QpiOsfLlgolPJHmJ5_7VuTU2DE0Ag,9607
|
|
8
|
-
napari_plugin_manager/qt_warning_dialog.py,sha256=ue4CeMptlBBkBctPg7qCayamrkm75iLqASSFUvwo_Bc,669
|
|
9
|
-
napari_plugin_manager/qt_widgets.py,sha256=O8t5CbN8r_16cQzshyjvhTEYdUcj7OX0-bfYIiN2uSs,356
|
|
10
|
-
napari_plugin_manager/styles.qss,sha256=9ODPba2IorJybWObWoEO9VGq4AO0IYlAa8brN14tgZU,7379
|
|
11
|
-
napari_plugin_manager/utils.py,sha256=V0QmCQNP2OwszoQ2n9Gnau9jH81rLKwfskL4ebex7EE,722
|
|
12
|
-
napari_plugin_manager/_tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
13
|
-
napari_plugin_manager/_tests/conftest.py,sha256=OvzenfBP2oIS6x8ksr9FhPXdsLV3Q_3Kzr6PRJe45Uc,1885
|
|
14
|
-
napari_plugin_manager/_tests/test_base_installer_process.py,sha256=Cv-nBnUeNAX6pYUE1zs38I9vGtCE-ahBN4q-xcBH-pw,561
|
|
15
|
-
napari_plugin_manager/_tests/test_installer_process.py,sha256=qPSDcYWPQ08gzM38av2tcE9XCtruHv-Mo6duQ0sZp-8,11614
|
|
16
|
-
napari_plugin_manager/_tests/test_npe2api.py,sha256=GRXucH7kWHt6thgueppHHWaToTvQG1PXH6UECFeVxcM,1225
|
|
17
|
-
napari_plugin_manager/_tests/test_qt_plugin_dialog.py,sha256=IRXodt3IrE7rXHZO0R69lhz4_2mMW3MOE9LLQ5tCxWY,21727
|
|
18
|
-
napari_plugin_manager/_tests/test_utils.py,sha256=7EilxmDkRjU6UO2AnaqyYovdAs18D0ZA5GCVGN62-3M,720
|
|
19
|
-
napari_plugin_manager-0.1.5rc1.dist-info/licenses/LICENSE,sha256=8dAlKbOqTMYe9L-gL_kEx5Xr1Sd0AbaWQDUkpiOp3vI,1506
|
|
20
|
-
napari_plugin_manager-0.1.5rc1.dist-info/METADATA,sha256=QeYCn3PpTMce-zZOvmAftJacUGvf4eUNkMU2p9Gv6PI,13813
|
|
21
|
-
napari_plugin_manager-0.1.5rc1.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
|
|
22
|
-
napari_plugin_manager-0.1.5rc1.dist-info/top_level.txt,sha256=pmCqLetuumhY1CKSuTZ5eQsitzazrSvc7V_mkugEPTY,22
|
|
23
|
-
napari_plugin_manager-0.1.5rc1.dist-info/RECORD,,
|
{napari_plugin_manager-0.1.5rc1.dist-info → napari_plugin_manager-0.1.6.dist-info}/licenses/LICENSE
RENAMED
|
File without changes
|
{napari_plugin_manager-0.1.5rc1.dist-info → napari_plugin_manager-0.1.6.dist-info}/top_level.txt
RENAMED
|
File without changes
|