diff --git a/spyder/__init__.py b/spyder/__init__.py
index 792950912bc..a0a357f287c 100644
--- a/spyder/__init__.py
+++ b/spyder/__init__.py
@@ -33,6 +33,7 @@
__license__ = __doc__
__project_url__ = 'https://github.com/spyder-ide/spyder'
__forum_url__ = 'http://groups.google.com/group/spyderlib'
+__trouble_url__ = __project_url__ + '/wiki/Troubleshooting-Guide-and-FAQ'
# Dear (Debian, RPM, ...) package makers, please feel free to customize the
# following path to module's data (images) and translations:
diff --git a/spyder/app/mainwindow.py b/spyder/app/mainwindow.py
index d00ab8fd474..527481b1173 100644
--- a/spyder/app/mainwindow.py
+++ b/spyder/app/mainwindow.py
@@ -140,7 +140,8 @@
#==============================================================================
# Local utility imports
#==============================================================================
-from spyder import __version__, __project_url__, __forum_url__, get_versions
+from spyder import (__version__, __project_url__, __forum_url__,
+ __trouble_url__, get_versions)
from spyder.config.base import (get_conf_path, get_module_data_path,
get_module_source_path, STDERR, DEBUG,
debug_print, MAC_APP_NAME, get_home_dir,
@@ -936,6 +937,9 @@ def create_edit_action(text, tr_text, icon):
self.set_splash(_("Setting up main window..."))
# Help menu
+ trouble_action = create_action(self,
+ _("Troubleshooting..."),
+ triggered=self.trouble_guide)
dep_action = create_action(self, _("Dependencies..."),
triggered=self.show_dependencies,
icon=ima.icon('advanced'))
@@ -1010,7 +1014,8 @@ def trigger(i=i, self=self): # closure needed!
self.help_menu_actions = [doc_action, tut_action, shortcuts_action,
self.tours_menu,
- MENU_SEPARATOR, report_action, dep_action,
+ MENU_SEPARATOR, trouble_action,
+ report_action, dep_action,
self.check_updates_action, support_action,
MENU_SEPARATOR]
# Python documentation
@@ -2349,9 +2354,10 @@ def about(self):
Developed and maintained by the
Spyder Project Contributors.
Many thanks to all the Spyder beta testers and regular users.
-
For bug reports and feature requests, please go - to our Github website. For discussions around the - project, please go to our Google Group +
For help with Spyder errors and crashes, please read our + Troubleshooting page, and for bug reports and + feature requests, visit our Github website. + For project discussion, see our Google Group.
This project is part of a larger effort to promote and
facilitate the use of Python for scientific and engineering
software development. The popular Python distributions
@@ -2367,7 +2373,7 @@ def about(self):
The Oxygen icon theme.
"""
- % (versions['spyder'], revlink, __project_url__,
+ % (versions['spyder'], revlink, __project_url__, __trouble_url__,
__project_url__, __forum_url__, versions['python'],
versions['bitness'], versions['qt'], versions['qt_api'],
versions['qt_api_ver'], versions['system']))
@@ -2457,6 +2463,9 @@ def report_issue(self, body=None, title=None):
if title:
url.addEncodedQueryItem("title", quote(title))
+ @Slot()
+ def trouble_guide(self):
+ url = QUrl(__trouble_url__)
QDesktopServices.openUrl(url)
@Slot()
@@ -3123,7 +3132,8 @@ def main():
CONF.set('main', 'crash', False)
if SPLASH is not None:
SPLASH.hide()
- QMessageBox.information(None, "Spyder",
+ QMessageBox.information(
+ None, "Spyder",
"Spyder crashed during last session.
"
"If Spyder does not start at all and before submitting a "
"bug report, please try to reset settings to defaults by "
@@ -3133,12 +3143,15 @@ def main():
"Warning: "
"this command will remove all your Spyder configuration files "
"located in '%s').
"
- "If restoring the default settings does not help, please take "
+ "If Spyder still fails to launch, you should consult our "
+ "comprehensive Troubleshooting Guide, "
+ "which when followed carefully solves the vast majority of "
+ "crashes; also, take "
"the time to search for known bugs or "
"discussions matching your situation before "
- "eventually creating a new issue here. "
+ "submitting a report to our issue tracker. "
"Your feedback will always be greatly appreciated."
- "" % (get_conf_path(), __project_url__,
+ "" % (get_conf_path(), __trouble_url__, __project_url__,
__forum_url__, __project_url__))
# Create main window
diff --git a/spyder/app/tests/test_mainwindow.py b/spyder/app/tests/test_mainwindow.py
index 69f8c70a39b..fa1abd94469 100644
--- a/spyder/app/tests/test_mainwindow.py
+++ b/spyder/app/tests/test_mainwindow.py
@@ -13,6 +13,10 @@
from sys import version_info
import shutil
import tempfile
+try:
+ from unittest.mock import Mock, MagicMock
+except ImportError:
+ from mock import Mock, MagicMock # Python 2
from flaky import flaky
from jupyter_client.manager import KernelManager
@@ -24,8 +28,9 @@
from qtpy.QtTest import QTest
from qtpy.QtWidgets import QApplication, QFileDialog, QLineEdit
+from spyder import __trouble_url__
from spyder.app.cli_options import get_options
-from spyder.app.mainwindow import initialize, run_spyder
+from spyder.app.mainwindow import initialize, run_spyder, MainWindow
from spyder.config.base import get_home_dir
from spyder.config.main import CONF
from spyder.plugins.runconfig import RunConfiguration
@@ -33,6 +38,14 @@
from spyder.utils.ipython.kernelspec import SpyderKernelSpec
from spyder.utils.programs import is_module_installed
+# For testing various Spyder urls
+if not PY2:
+ from urllib.request import urlopen
+ from urllib.error import URLError
+else:
+ from urllib2 import urlopen, URLError
+
+
#==============================================================================
# Constants
#==============================================================================
@@ -1142,5 +1155,33 @@ def test_run_static_code_analysis(main_window, qtbot):
main_window.editor.close_file()
+@flaky(max_runs=3)
+def test_troubleshooting_menu_item_and_url(monkeypatch):
+ """Test that the troubleshooting menu item calls the valid URL."""
+ MockMainWindow = MagicMock(spec=MainWindow)
+ mockMainWindow_instance = MockMainWindow()
+ mockMainWindow_instance.__class__ = MainWindow
+ MockQDesktopServices = Mock()
+ mockQDesktopServices_instance = MockQDesktopServices()
+ attr_to_patch = ('spyder.app.mainwindow.QDesktopServices')
+ monkeypatch.setattr(attr_to_patch, MockQDesktopServices)
+
+ # Unit test of help menu item: Make sure the correct URL is called.
+ MainWindow.trouble_guide(mockMainWindow_instance)
+ assert MockQDesktopServices.openUrl.call_count == 1
+ mockQDesktopServices_instance.openUrl.called_once_with(__trouble_url__)
+
+ # Check that the URL resolves correctly. Ignored if no internet connection.
+ try:
+ urlopen("https://www.github.com", timeout=1)
+ except Exception:
+ pass
+ else:
+ try:
+ urlopen(__trouble_url__, timeout=1)
+ except URLError:
+ raise
+
+
if __name__ == "__main__":
pytest.main()