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()