Skip to content

Commit

Permalink
Add napari version update checker
Browse files Browse the repository at this point in the history
  • Loading branch information
goanpeca committed Nov 15, 2024
1 parent 394425f commit 2067179
Showing 1 changed file with 134 additions and 0 deletions.
134 changes: 134 additions & 0 deletions napari_plugin_manager/qt_check_updates.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
import json
import os
import sys
from concurrent.futures import ThreadPoolExecutor
from contextlib import suppress
from datetime import date
from functools import lru_cache
from urllib.error import HTTPError, URLError
from urllib.request import urlopen

Check warning on line 9 in napari_plugin_manager/qt_check_updates.py

View check run for this annotation

Codecov / codecov/patch

napari_plugin_manager/qt_check_updates.py#L1-L9

Added lines #L1 - L9 were not covered by tests

import packaging
import packaging.version
from napari import __version__
from napari._qt.qthreading import create_worker
from napari.utils.notifications import show_warning
from qtpy.QtCore import QObject
from qtpy.QtWidgets import QMessageBox
from superqt import ensure_main_thread

Check warning on line 18 in napari_plugin_manager/qt_check_updates.py

View check run for this annotation

Codecov / codecov/patch

napari_plugin_manager/qt_check_updates.py#L11-L18

Added lines #L11 - L18 were not covered by tests

IGNORE_DAYS = 21
IGNORE_FILE = "ignore.txt"

Check warning on line 21 in napari_plugin_manager/qt_check_updates.py

View check run for this annotation

Codecov / codecov/patch

napari_plugin_manager/qt_check_updates.py#L20-L21

Added lines #L20 - L21 were not covered by tests


@lru_cache
def github_tags():
url = 'https://api.github.com/repos/napari/napari/tags'
with urlopen(url) as r:
data = json.load(r)

Check warning on line 28 in napari_plugin_manager/qt_check_updates.py

View check run for this annotation

Codecov / codecov/patch

napari_plugin_manager/qt_check_updates.py#L24-L28

Added lines #L24 - L28 were not covered by tests

versions = []
for item in data:
version = item.get('name', None)
if version:
if version.startswith('v'):
version = version[1:]

Check warning on line 35 in napari_plugin_manager/qt_check_updates.py

View check run for this annotation

Codecov / codecov/patch

napari_plugin_manager/qt_check_updates.py#L30-L35

Added lines #L30 - L35 were not covered by tests

versions.append(version)

Check warning on line 37 in napari_plugin_manager/qt_check_updates.py

View check run for this annotation

Codecov / codecov/patch

napari_plugin_manager/qt_check_updates.py#L37

Added line #L37 was not covered by tests

return list(reversed(versions))

Check warning on line 39 in napari_plugin_manager/qt_check_updates.py

View check run for this annotation

Codecov / codecov/patch

napari_plugin_manager/qt_check_updates.py#L39

Added line #L39 was not covered by tests


@lru_cache
def conda_forge_releases():
url = 'https://api.anaconda.org/package/conda-forge/napari/'
with urlopen(url) as r:
data = json.load(r)
versions = data.get('versions', [])
return versions

Check warning on line 48 in napari_plugin_manager/qt_check_updates.py

View check run for this annotation

Codecov / codecov/patch

napari_plugin_manager/qt_check_updates.py#L42-L48

Added lines #L42 - L48 were not covered by tests


def get_latest_version():

Check warning on line 51 in napari_plugin_manager/qt_check_updates.py

View check run for this annotation

Codecov / codecov/patch

napari_plugin_manager/qt_check_updates.py#L51

Added line #L51 was not covered by tests
"""Check latest version between tags and conda forge."""
try:
with ThreadPoolExecutor() as executor:
tags = executor.submit(github_tags)
cf = executor.submit(conda_forge_releases)

Check warning on line 56 in napari_plugin_manager/qt_check_updates.py

View check run for this annotation

Codecov / codecov/patch

napari_plugin_manager/qt_check_updates.py#L53-L56

Added lines #L53 - L56 were not covered by tests

gh_tags = tags.result()
cf_versions = cf.result()
except (HTTPError, URLError):
show_warning(

Check warning on line 61 in napari_plugin_manager/qt_check_updates.py

View check run for this annotation

Codecov / codecov/patch

napari_plugin_manager/qt_check_updates.py#L58-L61

Added lines #L58 - L61 were not covered by tests
'Plugin manager: There seems to be an issue with network connectivity. '
)
return

Check warning on line 64 in napari_plugin_manager/qt_check_updates.py

View check run for this annotation

Codecov / codecov/patch

napari_plugin_manager/qt_check_updates.py#L64

Added line #L64 was not covered by tests

latest_version = packaging.version.parse(cf_versions[-1])
latest_tag = packaging.version.parse(gh_tags[-1])
if latest_version > latest_tag:
yield latest_version

Check warning on line 69 in napari_plugin_manager/qt_check_updates.py

View check run for this annotation

Codecov / codecov/patch

napari_plugin_manager/qt_check_updates.py#L66-L69

Added lines #L66 - L69 were not covered by tests
else:
yield latest_tag

Check warning on line 71 in napari_plugin_manager/qt_check_updates.py

View check run for this annotation

Codecov / codecov/patch

napari_plugin_manager/qt_check_updates.py#L71

Added line #L71 was not covered by tests


class UpdateChecker(QObject):

Check warning on line 74 in napari_plugin_manager/qt_check_updates.py

View check run for this annotation

Codecov / codecov/patch

napari_plugin_manager/qt_check_updates.py#L74

Added line #L74 was not covered by tests

def __init__(self, parent=None):
super().__init__(parent=parent)

Check warning on line 77 in napari_plugin_manager/qt_check_updates.py

View check run for this annotation

Codecov / codecov/patch

napari_plugin_manager/qt_check_updates.py#L76-L77

Added lines #L76 - L77 were not covered by tests

self._current_version = packaging.version.parse(__version__)
self._latest_version = None
self._worker = None
self._base_folder = sys.prefix

Check warning on line 82 in napari_plugin_manager/qt_check_updates.py

View check run for this annotation

Codecov / codecov/patch

napari_plugin_manager/qt_check_updates.py#L79-L82

Added lines #L79 - L82 were not covered by tests

def check(self):

Check warning on line 84 in napari_plugin_manager/qt_check_updates.py

View check run for this annotation

Codecov / codecov/patch

napari_plugin_manager/qt_check_updates.py#L84

Added line #L84 was not covered by tests

if os.path.exists(os.path.join(self._base_folder, IGNORE_FILE)):
with (

Check warning on line 87 in napari_plugin_manager/qt_check_updates.py

View check run for this annotation

Codecov / codecov/patch

napari_plugin_manager/qt_check_updates.py#L86-L87

Added lines #L86 - L87 were not covered by tests
open(
os.path.join(self._base_folder, IGNORE_FILE),
encoding="utf-8",
) as f_p,
suppress(ValueError),
):
old_date = date.fromisoformat(f_p.read())
if (date.today() - old_date).days < IGNORE_DAYS:
return

Check warning on line 96 in napari_plugin_manager/qt_check_updates.py

View check run for this annotation

Codecov / codecov/patch

napari_plugin_manager/qt_check_updates.py#L94-L96

Added lines #L94 - L96 were not covered by tests

os.remove(os.path.join(self._base_folder, IGNORE_FILE))

Check warning on line 98 in napari_plugin_manager/qt_check_updates.py

View check run for this annotation

Codecov / codecov/patch

napari_plugin_manager/qt_check_updates.py#L98

Added line #L98 was not covered by tests

self._worker = create_worker(get_latest_version)
self._worker.yielded.connect(self.show_version_info)
self._worker.start()

Check warning on line 102 in napari_plugin_manager/qt_check_updates.py

View check run for this annotation

Codecov / codecov/patch

napari_plugin_manager/qt_check_updates.py#L100-L102

Added lines #L100 - L102 were not covered by tests

@ensure_main_thread
def show_version_info(self, latest_version):
my_version = self._current_version
remote_version = latest_version
if remote_version > my_version:
message = QMessageBox(

Check warning on line 109 in napari_plugin_manager/qt_check_updates.py

View check run for this annotation

Codecov / codecov/patch

napari_plugin_manager/qt_check_updates.py#L104-L109

Added lines #L104 - L109 were not covered by tests
QMessageBox.Icon.Information,
"New release",
f"You use outdated version of napari. "
f"Your version is {my_version} and current is {remote_version}.",
QMessageBox.StandardButton.Ok
| QMessageBox.StandardButton.Ignore,
)

if message.exec_() == QMessageBox.StandardButton.Ignore:
os.makedirs(self._base_folder, exist_ok=True)
with open(

Check warning on line 120 in napari_plugin_manager/qt_check_updates.py

View check run for this annotation

Codecov / codecov/patch

napari_plugin_manager/qt_check_updates.py#L118-L120

Added lines #L118 - L120 were not covered by tests
os.path.join(self._base_folder, IGNORE_FILE),
"w",
encoding="utf-8",
) as f_p:
f_p.write(date.today().isoformat())

Check warning on line 125 in napari_plugin_manager/qt_check_updates.py

View check run for this annotation

Codecov / codecov/patch

napari_plugin_manager/qt_check_updates.py#L125

Added line #L125 was not covered by tests


if __name__ == '__main__':
from qtpy.QtWidgets import QApplication

Check warning on line 129 in napari_plugin_manager/qt_check_updates.py

View check run for this annotation

Codecov / codecov/patch

napari_plugin_manager/qt_check_updates.py#L128-L129

Added lines #L128 - L129 were not covered by tests

app = QApplication([])
checker = UpdateChecker()
checker.check()
sys.exit(app.exec_())

Check warning on line 134 in napari_plugin_manager/qt_check_updates.py

View check run for this annotation

Codecov / codecov/patch

napari_plugin_manager/qt_check_updates.py#L131-L134

Added lines #L131 - L134 were not covered by tests

0 comments on commit 2067179

Please sign in to comment.