1import logging
2import time
3import sys
4import pkg_resources
5
6from AnyQt.QtCore import QSettings, QThread, pyqtSignal, Qt, QUrl
7from AnyQt.QtGui import QDesktopServices
8from AnyQt.QtWidgets import QMessageBox
9from urllib.request import urlopen, Request
10from Orange.version import version as current
11
12
13log = logging.getLogger(__name__)
14VERSION_URL = 'https://singlecell.biolab.si/version/'
15DOWNLOAD_URL = 'https://singlecell.biolab.si/download/'
16USER_AGENT = 'scOrange{orange_version}:Python{py_version}:{platform}:{conda}'
17UPDATE_AVAILABLE_TITLE = 'scOrange Update Available'
18UPDATE_AVAILABLE_MESSAGE = (
19    'A newer version of scOrange is available.<br><br>'
20    '<b>Current version:</b> {current_version}<br>'
21    '<b>Latest version:</b> {latest_version}'
22)
23
24
25def check_for_updates():
26    settings = QSettings()
27    check_updates = settings.value('startup/check-updates', True, type=bool)
28    last_check_time = settings.value('startup/last-update-check-time', 0, type=int)
29    ONE_DAY = 86400
30
31    if check_updates and time.time() - last_check_time > ONE_DAY:
32        settings.setValue('startup/last-update-check-time', int(time.time()))
33
34        thread = GetLatestVersion()
35        thread.resultReady.connect(compare_versions)
36        thread.start()
37        return thread
38
39
40class GetLatestVersion(QThread):
41    resultReady = pyqtSignal(str)
42
43    def run(self):
44        try:
45            request = Request(VERSION_URL,
46                              headers={
47                                  'Accept': 'text/plain',
48                                  'Accept-Encoding': 'gzip, deflate',
49                                  'Connection': 'close',
50                                  'User-Agent': self.ua_string()})
51            contents = urlopen(request, timeout=10).read().decode()
52        # Nothing that this fails with should make Orange crash
53        except Exception:  # pylint: disable=broad-except
54            log.exception('Failed to check for updates')
55        else:
56            self.resultReady.emit(contents)
57
58    @staticmethod
59    def ua_string():
60        is_anaconda = 'Continuum' in sys.version or 'conda' in sys.version
61        return USER_AGENT.format(
62            orange_version=current,
63            py_version='.'.join(sys.version[:3]),
64            platform=sys.platform,
65            conda='Anaconda' if is_anaconda else '',
66        )
67
68
69def current_version():
70    return pkg_resources.get_distribution("Orange3-SingleCell").version
71
72
73def compare_versions(latest):
74    current = current_version()
75    version = pkg_resources.parse_version
76    if version(latest) <= version(current):
77        return
78    question = QMessageBox(
79        QMessageBox.Information,
80        UPDATE_AVAILABLE_TITLE,
81        UPDATE_AVAILABLE_MESSAGE.format(
82            current_version=current,
83            latest_version=latest),
84        textFormat=Qt.RichText)
85    ok = question.addButton('Download Now', question.AcceptRole)
86    question.setDefaultButton(ok)
87    question.addButton('Remind Later', question.RejectRole)
88    question.finished.connect(
89        lambda:
90        question.clickedButton() == ok and
91        QDesktopServices.openUrl(QUrl(DOWNLOAD_URL)))
92    question.show()
93