From 6a2ee126782193e6c1707a823c9589c1b4935daa Mon Sep 17 00:00:00 2001
From: Ryan Clary <9618975+mrclary@users.noreply.github.com>
Date: Mon, 26 Feb 2024 13:39:08 -0800
Subject: [PATCH 01/22] Do not distinguish for bootstrap or development
versions on startup.
---
spyder/plugins/updatemanager/plugin.py | 8 +-------
1 file changed, 1 insertion(+), 7 deletions(-)
diff --git a/spyder/plugins/updatemanager/plugin.py b/spyder/plugins/updatemanager/plugin.py
index 39e6c4cb8e7..c43696e8957 100644
--- a/spyder/plugins/updatemanager/plugin.py
+++ b/spyder/plugins/updatemanager/plugin.py
@@ -9,14 +9,12 @@
"""
# Local imports
-from spyder import __version__
from spyder.api.plugins import Plugins, SpyderPluginV2
from spyder.api.translations import _
from spyder.api.plugin_registration.decorators import (
on_plugin_available,
on_plugin_teardown
)
-from spyder.config.base import DEV
from spyder.plugins.updatemanager.container import (
UpdateManagerActions,
UpdateManagerContainer
@@ -96,11 +94,7 @@ def on_mainwindow_visible(self):
container = self.get_container()
# Check for updates on startup
- if (
- DEV is None # Not bootstrap
- and 'dev' not in __version__ # Not dev version
- and self.get_conf('check_updates_on_startup')
- ):
+ if self.get_conf('check_updates_on_startup'):
container.start_check_update(startup=True)
# ---- Private API
From 1ca7e995999941827d9dade49f6ceb2343166886 Mon Sep 17 00:00:00 2001
From: Ryan Clary <9618975+mrclary@users.noreply.github.com>
Date: Mon, 26 Feb 2024 15:05:19 -0800
Subject: [PATCH 02/22] Process url data according to url value. The processing
algorithms are specific to the url data, so this is more robust.
Note that bootstrap and/or editable installs of Spyder fall back to conda-forge url
---
spyder/plugins/updatemanager/workers.py | 26 ++++++++++++-------------
1 file changed, 13 insertions(+), 13 deletions(-)
diff --git a/spyder/plugins/updatemanager/workers.py b/spyder/plugins/updatemanager/workers.py
index 72c8ec13a32..25e0068957e 100644
--- a/spyder/plugins/updatemanager/workers.py
+++ b/spyder/plugins/updatemanager/workers.py
@@ -100,21 +100,20 @@ def start(self):
self.update_available = False
error_msg = None
pypi_url = "https://pypi.org/pypi/spyder/json"
+ github_url = 'https://api.github.com/repos/spyder-ide/spyder/releases'
+ cf_url = 'https://conda.anaconda.org/conda-forge'
if is_conda_based_app():
- url = 'https://api.github.com/repos/spyder-ide/spyder/releases'
+ url = github_url
elif is_anaconda():
self.channel, channel_url = get_spyder_conda_channel()
if self.channel is None or channel_url is None:
- # Emit signal before returning so the slots connected to it
- # can do their job.
- try:
- self.sig_ready.emit()
- except RuntimeError:
- pass
-
- return
+ logger.debug(
+ f"channel = {self.channel}; channel_url = {channel_url}. "
+ )
+ # Spyder installed in development mode, use conda-forge
+ url = cf_url + '/channeldata.json'
elif self.channel == "pypi":
url = pypi_url
else:
@@ -129,16 +128,17 @@ def start(self):
data = page.json()
if self.releases is None:
- if is_conda_based_app():
+ if url == github_url:
self.releases = [
item['tag_name'].replace('v', '') for item in data
]
- elif is_anaconda() and url != pypi_url:
+ elif url == pypi_url:
+ self.releases = [data['info']['version']]
+ else:
+ # Conda type url
spyder_data = data['packages'].get('spyder')
if spyder_data:
self.releases = [spyder_data["version"]]
- else:
- self.releases = [data['info']['version']]
self.releases.sort(key=parse)
self._check_update_available()
From 3cca02015a39c7e06c8341b130cfc3a62c6bf942 Mon Sep 17 00:00:00 2001
From: Ryan Clary <9618975+mrclary@users.noreply.github.com>
Date: Mon, 26 Feb 2024 15:11:07 -0800
Subject: [PATCH 03/22] Use github url instead for editable mode.
---
spyder/plugins/updatemanager/workers.py | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/spyder/plugins/updatemanager/workers.py b/spyder/plugins/updatemanager/workers.py
index 25e0068957e..9be20762b4c 100644
--- a/spyder/plugins/updatemanager/workers.py
+++ b/spyder/plugins/updatemanager/workers.py
@@ -101,7 +101,6 @@ def start(self):
error_msg = None
pypi_url = "https://pypi.org/pypi/spyder/json"
github_url = 'https://api.github.com/repos/spyder-ide/spyder/releases'
- cf_url = 'https://conda.anaconda.org/conda-forge'
if is_conda_based_app():
url = github_url
@@ -112,8 +111,8 @@ def start(self):
logger.debug(
f"channel = {self.channel}; channel_url = {channel_url}. "
)
- # Spyder installed in development mode, use conda-forge
- url = cf_url + '/channeldata.json'
+ # Spyder installed in development mode, use GitHub
+ url = github_url
elif self.channel == "pypi":
url = pypi_url
else:
From 1b0e38f1ca685cc036e97bdf7235a2080fa22f41 Mon Sep 17 00:00:00 2001
From: Ryan Clary <9618975+mrclary@users.noreply.github.com>
Date: Mon, 26 Feb 2024 19:02:02 -0800
Subject: [PATCH 04/22] Hide update_manager statusbar widget on startup.
Do not set status on widget setup; the statusbar plugin will set visibility several times as it removes and re-adds the widget for layout purposes. Wait to set status and hide it until main window is visible.
---
spyder/plugins/updatemanager/container.py | 7 +------
spyder/plugins/updatemanager/plugin.py | 3 +++
2 files changed, 4 insertions(+), 6 deletions(-)
diff --git a/spyder/plugins/updatemanager/container.py b/spyder/plugins/updatemanager/container.py
index 211fea8df91..5be33b7d97f 100644
--- a/spyder/plugins/updatemanager/container.py
+++ b/spyder/plugins/updatemanager/container.py
@@ -20,10 +20,7 @@
from spyder.api.translations import _
from spyder.api.widgets.main_container import PluginMainContainer
from spyder.plugins.updatemanager.widgets.status import UpdateManagerStatus
-from spyder.plugins.updatemanager.widgets.update import (
- UpdateManagerWidget,
- NO_STATUS
-)
+from spyder.plugins.updatemanager.widgets.update import UpdateManagerWidget
from spyder.utils.qthelpers import DialogManager
# Logger setup
@@ -75,8 +72,6 @@ def setup(self):
self.update_manager_status.sig_show_progress_dialog.connect(
self.update_manager.show_progress_dialog)
- self.set_status(NO_STATUS)
-
def update_actions(self):
pass
diff --git a/spyder/plugins/updatemanager/plugin.py b/spyder/plugins/updatemanager/plugin.py
index c43696e8957..6d207972f26 100644
--- a/spyder/plugins/updatemanager/plugin.py
+++ b/spyder/plugins/updatemanager/plugin.py
@@ -93,6 +93,9 @@ def on_mainwindow_visible(self):
"""Actions after the mainwindow in visible."""
container = self.get_container()
+ # Hide statusbar widget on startup
+ container.update_manager_status.set_no_status()
+
# Check for updates on startup
if self.get_conf('check_updates_on_startup'):
container.start_check_update(startup=True)
From 450011b360c1e75155dfb27c830d3d283f53f59c Mon Sep 17 00:00:00 2001
From: Ryan Clary <9618975+mrclary@users.noreply.github.com>
Date: Mon, 26 Feb 2024 19:42:29 -0800
Subject: [PATCH 05/22] Only show statusbar widget while checking for updates,
an update is pending, or update is downloading.
---
spyder/plugins/updatemanager/widgets/status.py | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/spyder/plugins/updatemanager/widgets/status.py b/spyder/plugins/updatemanager/widgets/status.py
index 7d7468635cd..178889aa58f 100644
--- a/spyder/plugins/updatemanager/widgets/status.py
+++ b/spyder/plugins/updatemanager/widgets/status.py
@@ -84,16 +84,19 @@ def set_value(self, value):
self.spinner.hide()
self.spinner.stop()
self.custom_widget.show()
+ self.show()
elif value == CHECKING:
self.tooltip = self.BASE_TOOLTIP
self.custom_widget.hide()
self.spinner.show()
self.spinner.start()
+ self.show()
elif value == PENDING:
self.tooltip = value
self.custom_widget.hide()
self.spinner.hide()
self.spinner.stop()
+ self.show()
else:
self.tooltip = self.BASE_TOOLTIP
if self.custom_widget:
@@ -101,8 +104,8 @@ def set_value(self, value):
if self.spinner:
self.spinner.hide()
self.spinner.stop()
+ self.hide()
- self.setVisible(True)
self.update_tooltip()
value = f"Spyder: {value}"
logger.debug(f"Update manager status: {value}")
From 599755eba099b7f607b7ae177a73a695a7f044c2 Mon Sep 17 00:00:00 2001
From: Ryan Clary <9618975+mrclary@users.noreply.github.com>
Date: Mon, 26 Feb 2024 19:24:02 -0800
Subject: [PATCH 06/22] Do not use "Spyder: " in statusbar status value
---
spyder/plugins/updatemanager/widgets/status.py | 8 +++-----
1 file changed, 3 insertions(+), 5 deletions(-)
diff --git a/spyder/plugins/updatemanager/widgets/status.py b/spyder/plugins/updatemanager/widgets/status.py
index 178889aa58f..192766c7c46 100644
--- a/spyder/plugins/updatemanager/widgets/status.py
+++ b/spyder/plugins/updatemanager/widgets/status.py
@@ -107,7 +107,6 @@ def set_value(self, value):
self.hide()
self.update_tooltip()
- value = f"Spyder: {value}"
logger.debug(f"Update manager status: {value}")
super().set_value(value)
@@ -129,12 +128,11 @@ def set_download_progress(self, percent_progress):
@Slot()
def show_dialog_or_menu(self):
"""Show download dialog or status bar menu."""
- value = self.value.split(":")[-1].strip()
- if value == DOWNLOADING_INSTALLER:
+ if self.value == DOWNLOADING_INSTALLER:
self.sig_show_progress_dialog.emit(True)
- elif value in (PENDING, DOWNLOAD_FINISHED, INSTALL_ON_CLOSE):
+ elif self.value in (PENDING, DOWNLOAD_FINISHED, INSTALL_ON_CLOSE):
self.sig_start_update.emit()
- elif value == NO_STATUS:
+ elif self.value == NO_STATUS:
self.menu.clear()
check_for_updates_action = create_action(
self,
From 54671e91d940b9b9cbf5e6c4ca6c56c6feee7a1d Mon Sep 17 00:00:00 2001
From: Ryan Clary <9618975+mrclary@users.noreply.github.com>
Date: Mon, 26 Feb 2024 19:34:02 -0800
Subject: [PATCH 07/22] Remove obsolete statuses
---
spyder/plugins/updatemanager/widgets/update.py | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
diff --git a/spyder/plugins/updatemanager/widgets/update.py b/spyder/plugins/updatemanager/widgets/update.py
index 9ca760e0c12..b4b43aba026 100644
--- a/spyder/plugins/updatemanager/widgets/update.py
+++ b/spyder/plugins/updatemanager/widgets/update.py
@@ -36,15 +36,12 @@
# Logger setup
logger = logging.getLogger(__name__)
-# Update installation process statuses
+# Update manager process statuses
NO_STATUS = __version__
DOWNLOADING_INSTALLER = _("Downloading update")
DOWNLOAD_FINISHED = _("Download finished")
-INSTALLING = _("Installing update")
-FINISHED = _("Installation finished")
PENDING = _("Update available")
CHECKING = _("Checking for updates")
-CANCELLED = _("Cancelled update")
INSTALL_ON_CLOSE = _("Install on close")
HEADER = _("
Spyder {} is available!
")
From 62eb49d602ce1eeac71ff9e47b8bab94ba47641a Mon Sep 17 00:00:00 2001
From: Ryan Clary <9618975+mrclary@users.noreply.github.com>
Date: Mon, 26 Feb 2024 19:43:21 -0800
Subject: [PATCH 08/22] Do not need base tooltip, since widget is hidden.
---
spyder/plugins/updatemanager/widgets/status.py | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/spyder/plugins/updatemanager/widgets/status.py b/spyder/plugins/updatemanager/widgets/status.py
index 192766c7c46..3dfa30b8030 100644
--- a/spyder/plugins/updatemanager/widgets/status.py
+++ b/spyder/plugins/updatemanager/widgets/status.py
@@ -38,7 +38,6 @@
class UpdateManagerStatus(StatusBarWidget):
"""Status bar widget for update manager."""
- BASE_TOOLTIP = _("Application update status")
ID = 'update_manager_status'
sig_check_update = Signal()
@@ -61,7 +60,7 @@ class UpdateManagerStatus(StatusBarWidget):
def __init__(self, parent):
- self.tooltip = self.BASE_TOOLTIP
+ self.tooltip = None
super().__init__(parent, show_spinner=True)
# Check for updates action menu
@@ -86,7 +85,7 @@ def set_value(self, value):
self.custom_widget.show()
self.show()
elif value == CHECKING:
- self.tooltip = self.BASE_TOOLTIP
+ self.tooltip = value
self.custom_widget.hide()
self.spinner.show()
self.spinner.start()
@@ -98,7 +97,7 @@ def set_value(self, value):
self.spinner.stop()
self.show()
else:
- self.tooltip = self.BASE_TOOLTIP
+ self.tooltip = None
if self.custom_widget:
self.custom_widget.hide()
if self.spinner:
From e57514f8e0a6c62c50a61de7153422144d9ffe2b Mon Sep 17 00:00:00 2001
From: Ryan Clary <9618975+mrclary@users.noreply.github.com>
Date: Mon, 26 Feb 2024 19:46:06 -0800
Subject: [PATCH 09/22] Remove "Check for updates..." widget action.
---
.../plugins/updatemanager/widgets/status.py | 19 +------------------
1 file changed, 1 insertion(+), 18 deletions(-)
diff --git a/spyder/plugins/updatemanager/widgets/status.py b/spyder/plugins/updatemanager/widgets/status.py
index 3dfa30b8030..77354ce882e 100644
--- a/spyder/plugins/updatemanager/widgets/status.py
+++ b/spyder/plugins/updatemanager/widgets/status.py
@@ -10,10 +10,9 @@
# Standard library imports
import logging
-import os
# Third party imports
-from qtpy.QtCore import QPoint, Qt, Signal, Slot
+from qtpy.QtCore import Qt, Signal, Slot
from qtpy.QtWidgets import QLabel
# Local imports
@@ -29,7 +28,6 @@
PENDING
)
from spyder.utils.icon_manager import ima
-from spyder.utils.qthelpers import add_actions, create_action
# Setup logger
@@ -131,18 +129,3 @@ def show_dialog_or_menu(self):
self.sig_show_progress_dialog.emit(True)
elif self.value in (PENDING, DOWNLOAD_FINISHED, INSTALL_ON_CLOSE):
self.sig_start_update.emit()
- elif self.value == NO_STATUS:
- self.menu.clear()
- check_for_updates_action = create_action(
- self,
- text=_("Check for updates..."),
- triggered=self.sig_check_update.emit
- )
-
- add_actions(self.menu, [check_for_updates_action])
- rect = self.contentsRect()
- os_height = 7 if os.name == 'nt' else 12
- pos = self.mapToGlobal(
- rect.topLeft() + QPoint(-10, -rect.height() - os_height)
- )
- self.menu.popup(pos)
From f6aefbd30b2615cd23ad41305bcb719b586897b4 Mon Sep 17 00:00:00 2001
From: Ryan Clary <9618975+mrclary@users.noreply.github.com>
Date: Tue, 27 Feb 2024 12:25:02 -0800
Subject: [PATCH 10/22] Do not show statusbar widget while checking for
updates. The spinner is no longer needed either.
---
spyder/plugins/updatemanager/widgets/status.py | 13 ++-----------
1 file changed, 2 insertions(+), 11 deletions(-)
diff --git a/spyder/plugins/updatemanager/widgets/status.py b/spyder/plugins/updatemanager/widgets/status.py
index 77354ce882e..66baa558ba1 100644
--- a/spyder/plugins/updatemanager/widgets/status.py
+++ b/spyder/plugins/updatemanager/widgets/status.py
@@ -59,7 +59,7 @@ class UpdateManagerStatus(StatusBarWidget):
def __init__(self, parent):
self.tooltip = None
- super().__init__(parent, show_spinner=True)
+ super().__init__(parent)
# Check for updates action menu
self.menu = SpyderMenu(self)
@@ -78,29 +78,20 @@ def set_value(self, value):
"Downloading the update will continue in the background.\n"
"Click here to show the download dialog again."
)
- self.spinner.hide()
- self.spinner.stop()
self.custom_widget.show()
self.show()
elif value == CHECKING:
self.tooltip = value
self.custom_widget.hide()
- self.spinner.show()
- self.spinner.start()
- self.show()
+ self.hide()
elif value == PENDING:
self.tooltip = value
self.custom_widget.hide()
- self.spinner.hide()
- self.spinner.stop()
self.show()
else:
self.tooltip = None
if self.custom_widget:
self.custom_widget.hide()
- if self.spinner:
- self.spinner.hide()
- self.spinner.stop()
self.hide()
self.update_tooltip()
From d41092bf58ae0320bc56ba49f97005734e9b22c7 Mon Sep 17 00:00:00 2001
From: Ryan Clary <9618975+mrclary@users.noreply.github.com>
Date: Wed, 13 Mar 2024 14:03:30 -0700
Subject: [PATCH 11/22] Send untracked errors from update worker to the error
reporter
---
spyder/plugins/updatemanager/container.py | 5 +-
.../plugins/updatemanager/widgets/update.py | 15 +++++-
spyder/plugins/updatemanager/workers.py | 51 +++++++++++++++----
3 files changed, 56 insertions(+), 15 deletions(-)
diff --git a/spyder/plugins/updatemanager/container.py b/spyder/plugins/updatemanager/container.py
index 5be33b7d97f..75d6a217ac6 100644
--- a/spyder/plugins/updatemanager/container.py
+++ b/spyder/plugins/updatemanager/container.py
@@ -56,12 +56,13 @@ def setup(self):
# Signals
self.update_manager.sig_set_status.connect(self.set_status)
self.update_manager.sig_disable_actions.connect(
- self._set_actions_state
- )
+ self._set_actions_state)
self.update_manager.sig_block_status_signals.connect(
self.update_manager_status.blockSignals)
self.update_manager.sig_download_progress.connect(
self.update_manager_status.set_download_progress)
+ self.update_manager.sig_exception_occurred.connect(
+ self.sig_exception_occurred)
self.update_manager.sig_install_on_close.connect(
self.set_install_on_close)
self.update_manager.sig_quit_requested.connect(self.sig_quit_requested)
diff --git a/spyder/plugins/updatemanager/widgets/update.py b/spyder/plugins/updatemanager/widgets/update.py
index b4b43aba026..3a0c9d0ea32 100644
--- a/spyder/plugins/updatemanager/widgets/update.py
+++ b/spyder/plugins/updatemanager/widgets/update.py
@@ -10,9 +10,9 @@
import logging
import os
import os.path as osp
-import sys
-import subprocess
import platform
+import subprocess
+import sys
# Third-party imports
from packaging.version import parse
@@ -96,6 +96,11 @@ class UpdateManagerWidget(QWidget, SpyderConfigurationAccessor):
Latest release version detected.
"""
+ sig_exception_occurred = Signal(dict)
+ """
+ Pass untracked exceptions from workers to error reporter.
+ """
+
sig_install_on_close = Signal(bool)
"""
Signal to request running the install process on close.
@@ -167,6 +172,9 @@ def start_check_update(self, startup=False):
self.update_thread = QThread(None)
self.update_worker = WorkerUpdate(self.get_conf('check_stable_only'))
+ self.update_worker.sig_exception_occurred.connect(
+ self.sig_exception_occurred
+ )
self.update_worker.sig_ready.connect(self._process_check_update)
self.update_worker.sig_ready.connect(self.update_thread.quit)
self.update_worker.sig_ready.connect(
@@ -319,6 +327,9 @@ def _start_download(self):
self.progress_dialog.cancel.clicked.connect(self._cancel_download)
self.download_thread = QThread(None)
+ self.download_worker.sig_exception_occurred.connect(
+ self.sig_exception_occurred
+ )
self.download_worker.sig_ready.connect(self._confirm_install)
self.download_worker.sig_ready.connect(self.download_thread.quit)
self.download_worker.sig_ready.connect(
diff --git a/spyder/plugins/updatemanager/workers.py b/spyder/plugins/updatemanager/workers.py
index 9be20762b4c..2f70fee0702 100644
--- a/spyder/plugins/updatemanager/workers.py
+++ b/spyder/plugins/updatemanager/workers.py
@@ -56,14 +56,43 @@ class UpdateDownloadIncompleteError(Exception):
pass
-class WorkerUpdate(QObject):
+class Worker(QObject):
+ """Base worker class for the updater"""
+
+ sig_ready = Signal()
+ """Signal to inform that the worker has finished."""
+
+ sig_exception_occurred = Signal(dict)
+ """
+ Send untracked exceptions to the error reporter
+
+ Parameters
+ ----------
+ error_data: dict
+ The dictionary containing error data. The allowed keys are:
+ text: str
+ Error text to display. This may be a translated string or
+ formatted exception string.
+ is_traceback: bool
+ Whether `text` is plain text or an error traceback.
+ repo: str
+ Customized display of repo in GitHub error submission report.
+ title: str
+ Customized display of title in GitHub error submission report.
+ label: str
+ Customized content of the error dialog.
+ steps: str
+ Customized content of the error dialog.
+ """
+
+
+class WorkerUpdate(Worker):
"""
Worker that checks for releases using either the Anaconda
default channels or the Github Releases page without
blocking the Spyder user interface, in case of connection
issues.
"""
- sig_ready = Signal()
def __init__(self, stable_only):
super().__init__()
@@ -151,11 +180,14 @@ def start(self):
error_msg = HTTP_ERROR_MSG.format(status_code=page.status_code)
logger.warning(err, exc_info=err)
except Exception as err:
- # Only log the error when it's a generic one because we can't give
- # users proper feedback on how to address it. Otherwise we'd show
- # a long traceback that most probably would be incomprehensible to
- # them.
- logger.warning(err, exc_info=err)
+ # Send untracked errors to our error reporter
+ error_data = dict(
+ text=traceback.format_exc(),
+ is_traceback=True,
+ title="Check for update error",
+ )
+ self.sig_exception_occurred.emit(error_data)
+ logger.error(err, exc_info=err)
finally:
self.error = error_msg
@@ -169,15 +201,12 @@ def start(self):
pass
-class WorkerDownloadInstaller(QObject):
+class WorkerDownloadInstaller(Worker):
"""
Worker that donwloads standalone installers for Windows, macOS,
and Linux without blocking the Spyder user interface.
"""
- sig_ready = Signal()
- """Signal to inform that the worker has finished successfully."""
-
sig_download_progress = Signal(int, int)
"""
Signal to send the download progress.
From d16b13b181ccb8a032047addcb382fd576c2ee00 Mon Sep 17 00:00:00 2001
From: Ryan Clary <9618975+mrclary@users.noreply.github.com>
Date: Wed, 13 Mar 2024 14:52:27 -0700
Subject: [PATCH 12/22] Add pre-release element to version_info, when
appropriate.
---
spyder/__init__.py | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/spyder/__init__.py b/spyder/__init__.py
index 708a699ce5b..efd0b842837 100644
--- a/spyder/__init__.py
+++ b/spyder/__init__.py
@@ -29,9 +29,11 @@
OTHER DEALINGS IN THE SOFTWARE.
"""
-version_info = (6, 0, 0, "dev0")
+from packaging.version import parse
-__version__ = '.'.join(map(str, version_info))
+version_info = (6, 0, 0, "a5", "dev0")
+
+__version__ = str(parse('.'.join(map(str, version_info))))
__installer_version__ = __version__
__title__ = 'Spyder'
__author__ = 'Spyder Project Contributors and others'
From 9d14a6b2e88c9f92aad5e2d27ec7f30835f5cdc2 Mon Sep 17 00:00:00 2001
From: Ryan Clary <9618975+mrclary@users.noreply.github.com>
Date: Thu, 21 Mar 2024 13:56:31 -0700
Subject: [PATCH 13/22] Revert "Merge from 5.x: PR #21910"
This reverts commit f64ff79fa573841bebfd70bce224064dc1adfc20, reversing
changes made to 6ecbbae4461338e7365f4602b8ccaf7f4ed1aeb5.
---
spyder/plugins/updatemanager/workers.py | 12 ++----------
1 file changed, 2 insertions(+), 10 deletions(-)
diff --git a/spyder/plugins/updatemanager/workers.py b/spyder/plugins/updatemanager/workers.py
index 2f70fee0702..ebc153a9e1c 100644
--- a/spyder/plugins/updatemanager/workers.py
+++ b/spyder/plugins/updatemanager/workers.py
@@ -8,7 +8,6 @@
import logging
import os
import os.path as osp
-import shutil
from time import sleep
import traceback
@@ -278,16 +277,9 @@ def _download_installer(self):
def _clean_installer_path(self):
"""Remove downloaded file"""
if osp.exists(self.installer_path):
- try:
- shutil.rmtree(self.installer_path)
- except OSError as err:
- logger.debug(err, stack_info=True)
-
+ os.remove(self.installer_path)
if osp.exists(self.installer_size_path):
- try:
- shutil.rmtree(self.installer_size_path)
- except OSError as err:
- logger.debug(err, stack_info=True)
+ os.remove(self.installer_size_path)
def start(self):
"""Main method of the worker."""
From 5059c82b572c86f9718be4e471ae54b4e710e5b9 Mon Sep 17 00:00:00 2001
From: Ryan Clary <9618975+mrclary@users.noreply.github.com>
Date: Mon, 25 Mar 2024 08:45:30 -0700
Subject: [PATCH 14/22] Remap local channel to conda-forge.
I don't think there is a way to remap the local channel to different channels depending on the package, e.g. spyder-kernels to use conda-forge/label/spyder_kernels_rc and spyder to use conda-forge/label/spyder_dev. However, I think conda-forge will be sufficient to allow the updater to perform its actions.
---
installers-conda/build_installers.py | 18 ++++++++++++++++--
1 file changed, 16 insertions(+), 2 deletions(-)
diff --git a/installers-conda/build_installers.py b/installers-conda/build_installers.py
index d9c6c658325..2bb85537766 100644
--- a/installers-conda/build_installers.py
+++ b/installers-conda/build_installers.py
@@ -33,7 +33,7 @@
from pathlib import Path
import platform
import re
-from subprocess import check_call
+from subprocess import run
import sys
from textwrap import dedent, indent
from time import time
@@ -217,6 +217,14 @@ def _get_condarc():
return str(file)
+def _get_conda_bld_path_url():
+ bld_path_url = "file://"
+ if WINDOWS:
+ bld_path_url += "/"
+ bld_path_url += Path(os.getenv('CONDA_BLD_PATH')).as_posix()
+ return bld_path_url
+
+
def _definitions():
condarc = _get_condarc()
definitions = {
@@ -246,6 +254,12 @@ def _definitions():
"specs": [k + v for k, v in specs.items()],
},
},
+ "channels_remap": [
+ {
+ "src": _get_conda_bld_path_url(),
+ "dest": "https://conda.anaconda.org/conda-forge"
+ }
+ ]
}
if not args.no_local:
@@ -371,7 +385,7 @@ def _constructor():
yaml.dump(definitions, BUILD / "construct.yaml")
- check_call(cmd_args, env=env)
+ run(cmd_args, check=True, env=env)
def licenses():
From 049793b05e80bb33c2259b2e93c5b927f3dc9914 Mon Sep 17 00:00:00 2001
From: Ryan Clary <9618975+mrclary@users.noreply.github.com>
Date: Thu, 28 Mar 2024 15:31:16 -0700
Subject: [PATCH 15/22] Explicitly add packaging to Python build system
---
pyproject.toml | 6 ++++++
1 file changed, 6 insertions(+)
create mode 100644 pyproject.toml
diff --git a/pyproject.toml b/pyproject.toml
new file mode 100644
index 00000000000..e611bb6583c
--- /dev/null
+++ b/pyproject.toml
@@ -0,0 +1,6 @@
+[build-system]
+requires = [
+ "setuptools>=42",
+ "packaging",
+]
+build-backend = "setuptools.build_meta"
From 29182fe88ebfe4ac54339ae9bb622a304c39e99b Mon Sep 17 00:00:00 2001
From: Ryan Clary <9618975+mrclary@users.noreply.github.com>
Date: Tue, 9 Apr 2024 10:38:07 -0700
Subject: [PATCH 16/22] Apply suggestions from code review
Co-authored-by: Carlos Cordoba
---
spyder/plugins/updatemanager/container.py | 6 ++++--
spyder/plugins/updatemanager/plugin.py | 3 ++-
.../plugins/updatemanager/widgets/status.py | 4 ++--
spyder/plugins/updatemanager/workers.py | 20 +++++++++++--------
4 files changed, 20 insertions(+), 13 deletions(-)
diff --git a/spyder/plugins/updatemanager/container.py b/spyder/plugins/updatemanager/container.py
index 75d6a217ac6..0105dfce250 100644
--- a/spyder/plugins/updatemanager/container.py
+++ b/spyder/plugins/updatemanager/container.py
@@ -56,13 +56,15 @@ def setup(self):
# Signals
self.update_manager.sig_set_status.connect(self.set_status)
self.update_manager.sig_disable_actions.connect(
- self._set_actions_state)
+ self._set_actions_state
+ )
self.update_manager.sig_block_status_signals.connect(
self.update_manager_status.blockSignals)
self.update_manager.sig_download_progress.connect(
self.update_manager_status.set_download_progress)
self.update_manager.sig_exception_occurred.connect(
- self.sig_exception_occurred)
+ self.sig_exception_occurred
+ )
self.update_manager.sig_install_on_close.connect(
self.set_install_on_close)
self.update_manager.sig_quit_requested.connect(self.sig_quit_requested)
diff --git a/spyder/plugins/updatemanager/plugin.py b/spyder/plugins/updatemanager/plugin.py
index 6d207972f26..22d7a2dcfe9 100644
--- a/spyder/plugins/updatemanager/plugin.py
+++ b/spyder/plugins/updatemanager/plugin.py
@@ -93,7 +93,8 @@ def on_mainwindow_visible(self):
"""Actions after the mainwindow in visible."""
container = self.get_container()
- # Hide statusbar widget on startup
+ # Initialize status.
+ # Note that NO_STATUS also hides the statusbar widget.
container.update_manager_status.set_no_status()
# Check for updates on startup
diff --git a/spyder/plugins/updatemanager/widgets/status.py b/spyder/plugins/updatemanager/widgets/status.py
index 66baa558ba1..f3cbedb4ed9 100644
--- a/spyder/plugins/updatemanager/widgets/status.py
+++ b/spyder/plugins/updatemanager/widgets/status.py
@@ -58,7 +58,7 @@ class UpdateManagerStatus(StatusBarWidget):
def __init__(self, parent):
- self.tooltip = None
+ self.tooltip = ""
super().__init__(parent)
# Check for updates action menu
@@ -89,7 +89,7 @@ def set_value(self, value):
self.custom_widget.hide()
self.show()
else:
- self.tooltip = None
+ self.tooltip = ""
if self.custom_widget:
self.custom_widget.hide()
self.hide()
diff --git a/spyder/plugins/updatemanager/workers.py b/spyder/plugins/updatemanager/workers.py
index ebc153a9e1c..9ee12a896d8 100644
--- a/spyder/plugins/updatemanager/workers.py
+++ b/spyder/plugins/updatemanager/workers.py
@@ -8,6 +8,7 @@
import logging
import os
import os.path as osp
+import shutil
from time import sleep
import traceback
@@ -55,7 +56,7 @@ class UpdateDownloadIncompleteError(Exception):
pass
-class Worker(QObject):
+class BaseWorker(QObject):
"""Base worker class for the updater"""
sig_ready = Signal()
@@ -85,7 +86,7 @@ class Worker(QObject):
"""
-class WorkerUpdate(Worker):
+class WorkerUpdate(BaseWorker):
"""
Worker that checks for releases using either the Anaconda
default channels or the Github Releases page without
@@ -139,6 +140,7 @@ def start(self):
logger.debug(
f"channel = {self.channel}; channel_url = {channel_url}. "
)
+
# Spyder installed in development mode, use GitHub
url = github_url
elif self.channel == "pypi":
@@ -183,7 +185,7 @@ def start(self):
error_data = dict(
text=traceback.format_exc(),
is_traceback=True,
- title="Check for update error",
+ title="Error when checking for updates",
)
self.sig_exception_occurred.emit(error_data)
logger.error(err, exc_info=err)
@@ -200,7 +202,7 @@ def start(self):
pass
-class WorkerDownloadInstaller(Worker):
+class WorkerDownloadInstaller(BaseWorker):
"""
Worker that donwloads standalone installers for Windows, macOS,
and Linux without blocking the Spyder user interface.
@@ -276,10 +278,12 @@ def _download_installer(self):
def _clean_installer_path(self):
"""Remove downloaded file"""
- if osp.exists(self.installer_path):
- os.remove(self.installer_path)
- if osp.exists(self.installer_size_path):
- os.remove(self.installer_size_path)
+ installer_dir = osp.dirname(self.installer_path)
+ if osp.exists(installer_dir):
+ try:
+ shutil.rmtree(installer_dir)
+ except OSError as err:
+ logger.debug(err, stack_info=True)
def start(self):
"""Main method of the worker."""
From 89d26bdceaf36c950cc2890f9c8bfe106847ce9e Mon Sep 17 00:00:00 2001
From: Ryan Clary <9618975+mrclary@users.noreply.github.com>
Date: Tue, 9 Apr 2024 18:00:34 -0700
Subject: [PATCH 17/22] Apply suggestions from code review
Co-authored-by: Carlos Cordoba
---
pyproject.toml | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/pyproject.toml b/pyproject.toml
index e611bb6583c..edd2d210dc2 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -3,4 +3,7 @@ requires = [
"setuptools>=42",
"packaging",
]
-build-backend = "setuptools.build_meta"
+
+# We're not ready yet to build Spyder with the setuptools backend, but we're
+# leaving this for the future.
+# build-backend = "setuptools.build_meta"
From 5f7a58c6761cafa50121bffbe0e4ef7fe8c101cb Mon Sep 17 00:00:00 2001
From: Ryan Clary <9618975+mrclary@users.noreply.github.com>
Date: Wed, 10 Apr 2024 23:38:09 -0700
Subject: [PATCH 18/22] Make CONDA_BLD_PATH available to the entire job and
condition NSIS_USING_LOG_BUILD on pre-/release.
---
.github/workflows/installers-conda.yml | 16 ++++++++++------
1 file changed, 10 insertions(+), 6 deletions(-)
diff --git a/.github/workflows/installers-conda.yml b/.github/workflows/installers-conda.yml
index e754f8f82c3..b146b8b6b27 100644
--- a/.github/workflows/installers-conda.yml
+++ b/.github/workflows/installers-conda.yml
@@ -54,6 +54,7 @@ name: Nightly conda-based installers
env:
IS_RELEASE: ${{ github.event_name == 'release' }}
+ IS_PRE_RELEASE: ${{ github.event_name == 'workflow_dispatch' && inputs.pre }}
ENABLE_SSH: ${{ github.event_name == 'workflow_dispatch' && inputs.ssh }}
BUILD_MAC: ${{ github.event_name != 'workflow_dispatch' || inputs.macos-x86_64 }}
BUILD_ARM: ${{ github.event_name != 'workflow_dispatch' || inputs.macos-arm64 }}
@@ -125,7 +126,6 @@ jobs:
MACOS_INSTALLER_CERTIFICATE: ${{ secrets.MACOS_INSTALLER_CERTIFICATE }}
APPLICATION_PWD: ${{ secrets.APPLICATION_PWD }}
CONSTRUCTOR_TARGET_PLATFORM: ${{ matrix.target-platform }}
- NSIS_USING_LOG_BUILD: 1
steps:
- name: Checkout Code
@@ -193,11 +193,17 @@ jobs:
cache-environment: true
- name: Env Variables
- run: env | sort
+ run: |
+ NSIS_USING_LOG_BUILD=1
+ [[ "$IS_RELEASE" == "true" || "$IS_PRE_RELEASE" == "true" ]] && NSIS_USING_LOG_BUILD=0
+ CONDA_BLD_PATH=${RUNNER_TEMP}/conda-bld
+
+ echo "NSIS_USING_LOG_BUILD=$NSIS_USING_LOG_BUILD" >> $GITHUB_ENV
+ echo "CONDA_BLD_PATH=$CONDA_BLD_PATH" >> $GITHUB_ENV
+
+ env | sort
- name: Build ${{ matrix.target-platform }} spyder Conda Package
- env:
- CONDA_BLD_PATH: ${{ runner.temp }}/conda-bld
run: |
# Copy built packages to new build location because spyder cannot be
# built in workspace
@@ -206,8 +212,6 @@ jobs:
python build_conda_pkgs.py --build spyder
- name: Create Local Conda Channel
- env:
- CONDA_BLD_PATH: ${{ runner.temp }}/conda-bld
run: |
conda config --set bld_path $CONDA_BLD_PATH
conda index $CONDA_BLD_PATH
From f1850d0dae692ac6da5d4a9b9d1594d3145f718e Mon Sep 17 00:00:00 2001
From: Ryan Clary <9618975+mrclary@users.noreply.github.com>
Date: Fri, 12 Apr 2024 15:23:39 -0700
Subject: [PATCH 19/22] Fix issue where install script for windows could not
properly determine if Spyder was still running.
The shortcut no longer uses spyder.exe, but rather pythonw.exe. To positively identify Spyder, we need to expose the WindowTitle using verbosity and searching for "Spyder".
---
spyder/plugins/updatemanager/scripts/install.bat | 10 ++++------
1 file changed, 4 insertions(+), 6 deletions(-)
diff --git a/spyder/plugins/updatemanager/scripts/install.bat b/spyder/plugins/updatemanager/scripts/install.bat
index 4bdb5533469..23e271017d3 100644
--- a/spyder/plugins/updatemanager/scripts/install.bat
+++ b/spyder/plugins/updatemanager/scripts/install.bat
@@ -23,6 +23,8 @@ echo IMPORTANT: Do not close this window until it has finished
echo =========================================================
echo.
+call :wait_for_spyder_quit
+
IF not "%conda%"=="" IF not "%spy_ver%"=="" (
call :update_subroutine
call :launch_spyder
@@ -40,8 +42,6 @@ exit %ERRORLEVEL%
:install_subroutine
echo Installing Spyder from: %install_exe%
- call :wait_for_spyder_quit
-
:: Uninstall Spyder
for %%I in ("%prefix%\..\..") do set "conda_root=%%~fI"
@@ -69,16 +69,14 @@ exit %ERRORLEVEL%
:update_subroutine
echo Updating Spyder
- call :wait_for_spyder_quit
-
%conda% install -p %prefix% -y spyder=%spy_ver%
- set /P CONT=Press any key to exit...
+ set /P =Press any key to exit...
goto :EOF
:wait_for_spyder_quit
echo Waiting for Spyder to quit...
:loop
- tasklist /fi "ImageName eq spyder.exe" /fo csv 2>NUL | find /i "spyder.exe">NUL
+ tasklist /v /fi "ImageName eq pythonw.exe" /fo csv 2>NUL | find "Spyder">NUL
IF "%ERRORLEVEL%"=="0" (
timeout /t 1 /nobreak > nul
goto loop
From d52b7a1da312f073f94cbb902495d3e84b0b951d Mon Sep 17 00:00:00 2001
From: Ryan Clary <9618975+mrclary@users.noreply.github.com>
Date: Fri, 12 Apr 2024 15:35:07 -0700
Subject: [PATCH 20/22] Fix issue where install script used incorrect shortcut
for launching Spyder
---
spyder/plugins/updatemanager/scripts/install.bat | 13 +++++++------
spyder/plugins/updatemanager/scripts/install.sh | 11 ++++++++---
2 files changed, 15 insertions(+), 9 deletions(-)
diff --git a/spyder/plugins/updatemanager/scripts/install.bat b/spyder/plugins/updatemanager/scripts/install.bat
index 23e271017d3..decafbd18d9 100644
--- a/spyder/plugins/updatemanager/scripts/install.bat
+++ b/spyder/plugins/updatemanager/scripts/install.bat
@@ -85,10 +85,11 @@ exit %ERRORLEVEL%
goto :EOF
:launch_spyder
- echo %prefix% | findstr /b "%USERPROFILE%" > nul && (
- set shortcut_root=%APPDATA%
- ) || (
- set shortcut_root=%ALLUSERSPROFILE%
- )
- start "" /B "%shortcut_root%\Microsoft\Windows\Start Menu\Programs\spyder\Spyder.lnk"
+ for %%C in ("%conda%") do set scripts=%%~dpC
+ set pythonexe=%scripts%..\python.exe
+ set menuinst=%scripts%menuinst_cli.py
+ if exist "%prefix%\.nonadmin" (set mode=user) else set mode=system
+ for /f "delims=" %%s in ('%pythonexe% %menuinst% shortcut --mode=%mode%') do set "shortcut_path=%%~s"
+
+ start "" /B "%shortcut_path%"
goto :EOF
diff --git a/spyder/plugins/updatemanager/scripts/install.sh b/spyder/plugins/updatemanager/scripts/install.sh
index 75b894ad8ec..b58637f7580 100755
--- a/spyder/plugins/updatemanager/scripts/install.sh
+++ b/spyder/plugins/updatemanager/scripts/install.sh
@@ -18,11 +18,16 @@ update_spyder(){
}
launch_spyder(){
+ root=$(dirname $conda)
+ pythonexe=$root/python
+ menuinst=$root/menuinst_cli.py
+ mode=$([[ -e "${prefix}/.nonadmin" ]] && echo "user" || echo "system")
+ shortcut_path=$($pythonexe $menuinst shortcut --mode=$mode)
+
if [[ "$OSTYPE" = "darwin"* ]]; then
- shortcut=/Applications/Spyder.app
- [[ "$prefix" = "$HOME"* ]] && open -a $HOME$shortcut || open -a $shortcut
+ open -a $shortcut
elif [[ -n "$(which gtk-launch)" ]]; then
- gtk-launch spyder_spyder
+ gtk-launch $(basename ${shortcut_path%.*})
else
nohup $prefix/bin/spyder &>/dev/null &
fi
From 48ff669e9351b87c2541ba610bc8c8966afbce92 Mon Sep 17 00:00:00 2001
From: Ryan Clary <9618975+mrclary@users.noreply.github.com>
Date: Fri, 12 Apr 2024 18:13:05 -0700
Subject: [PATCH 21/22] Fix continue message
---
spyder/plugins/updatemanager/scripts/install.bat | 2 +-
spyder/plugins/updatemanager/scripts/install.sh | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/spyder/plugins/updatemanager/scripts/install.bat b/spyder/plugins/updatemanager/scripts/install.bat
index decafbd18d9..3969f20059b 100644
--- a/spyder/plugins/updatemanager/scripts/install.bat
+++ b/spyder/plugins/updatemanager/scripts/install.bat
@@ -70,7 +70,7 @@ exit %ERRORLEVEL%
echo Updating Spyder
%conda% install -p %prefix% -y spyder=%spy_ver%
- set /P =Press any key to exit...
+ set /P =Press return to exit...
goto :EOF
:wait_for_spyder_quit
diff --git a/spyder/plugins/updatemanager/scripts/install.sh b/spyder/plugins/updatemanager/scripts/install.sh
index b58637f7580..e5bee00d239 100755
--- a/spyder/plugins/updatemanager/scripts/install.sh
+++ b/spyder/plugins/updatemanager/scripts/install.sh
@@ -14,7 +14,7 @@ shift $(($OPTIND - 1))
update_spyder(){
$conda install -p $prefix -y spyder=$spy_ver
- read -p "Press any key to exit..."
+ read -p "Press return to exit..."
}
launch_spyder(){
From 61efbc42d32a826d1c14c12cf195510035858139 Mon Sep 17 00:00:00 2001
From: Ryan Clary <9618975+mrclary@users.noreply.github.com>
Date: Mon, 15 Apr 2024 22:11:00 -0700
Subject: [PATCH 22/22] Copy install.[sh|bat] script to temporary location.
This is required for Windows, otherwise adverse behavior occurs when
executing a file that is being over-written. Copy for macOS and Linux too,
just to be safe.
---
spyder/plugins/updatemanager/widgets/update.py | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/spyder/plugins/updatemanager/widgets/update.py b/spyder/plugins/updatemanager/widgets/update.py
index 3a0c9d0ea32..007c929c4f1 100644
--- a/spyder/plugins/updatemanager/widgets/update.py
+++ b/spyder/plugins/updatemanager/widgets/update.py
@@ -11,6 +11,7 @@
import os
import os.path as osp
import platform
+import shutil
import subprocess
import sys
@@ -414,11 +415,14 @@ def start_install(self):
"""Install from downloaded installer or update through conda."""
# Install script
- script = osp.abspath(__file__ + '/../../scripts/install.' +
- ('bat' if os.name == 'nt' else 'sh'))
+ # Copy to temp location to be safe
+ script_name = 'install.' + ('bat' if os.name == 'nt' else 'sh')
+ script_path = osp.abspath(__file__ + '/../../scripts/' + script_name)
+ tmpscript_path = osp.join(get_temp_dir(), script_name)
+ shutil.copy2(script_path, tmpscript_path)
# Sub command
- sub_cmd = [script, '-p', sys.prefix]
+ sub_cmd = [tmpscript_path, '-p', sys.prefix]
if osp.exists(self.installer_path):
# Run downloaded installer
sub_cmd.extend(['-i', self.installer_path])