diff --git a/spyder/config/manager.py b/spyder/config/manager.py index e8712215dcc..0ca2a40f346 100644 --- a/spyder/config/manager.py +++ b/spyder/config/manager.py @@ -12,12 +12,14 @@ import logging import os import os.path as osp +import sys import traceback from typing import Any, Dict, List, Optional, Set, Tuple import weakref # Third-party imports import keyring +from keyring.errors import NoKeyringError # Local imports from spyder.api.utils import PrefixedTuple @@ -574,7 +576,33 @@ def set(self, section, option, value, verbose=False, save=True, f"Saving option {option} with keyring because it was marked " f"as secure." ) - keyring.set_password(section, option, value) + + # Catch error when there's no keyring backend available. + # Fixes spyder-ide/spyder#22623 + try: + keyring.set_password(section, option, value) + except NoKeyringError: + # This file must not have top-level Qt imports. This also + # prevents possible circular imports. + from qtpy.QtWidgets import QMessageBox + from spyder_kernels.utils.pythonenv import is_conda_env + + pkg_manager = "conda" if is_conda_env(sys.prefix) else "pip" + msg = _( + "It was not possible to save a configuration setting " + "securely. A possible solution is to install the " + "keyrings.alt package with {}.

" + "Note: That package may have security risks or " + "other implications. Hence, it's not advised to use it in " + "general production or security-sensitive systems." + ).format(pkg_manager) + + QMessageBox.critical( + None, + _("Error"), + msg, + QMessageBox.Ok, + ) else: config.set( section=section,