diff --git a/spyder/app/tests/test_mainwindow.py b/spyder/app/tests/test_mainwindow.py index 045dbf1914c..b5438b82035 100644 --- a/spyder/app/tests/test_mainwindow.py +++ b/spyder/app/tests/test_mainwindow.py @@ -30,6 +30,7 @@ from qtpy.QtCore import Qt, QTimer, QEvent, QUrl from qtpy.QtTest import QTest from qtpy.QtWidgets import QApplication, QFileDialog, QLineEdit, QTabBar +from qtpy.QtWebEngineWidgets import WEBENGINE # Local imports from spyder import __trouble_url__, __project_url__ @@ -40,6 +41,7 @@ from spyder.plugins import TabFilter from spyder.plugins.help import ObjectComboBox from spyder.plugins.runconfig import RunConfiguration +from spyder.plugins.tests.test_help import check_text from spyder.py3compat import PY2, to_text_string from spyder.utils.ipython.kernelspec import SpyderKernelSpec from spyder.utils.programs import is_module_installed @@ -209,6 +211,52 @@ def test_calltip(main_window, qtbot): main_window.editor.close_file() +@pytest.mark.slow +@flaky(max_runs=3) +@pytest.mark.use_introspection +def test_get_help(main_window, qtbot): + """ + Test that Help is working when called from the Editor and the + IPython console. + """ + shell = main_window.ipyconsole.get_current_shellwidget() + control = shell._control + qtbot.waitUntil(lambda: shell._prompt_html is not None, timeout=SHELL_TIMEOUT) + + help_plugin = main_window.help + webview = help_plugin.rich_text.webview._webview + if WEBENGINE: + webpage = webview.page() + else: + webpage = webview.page().mainFrame() + + # --- From the console --- + # Write some object in the console + qtbot.keyClicks(control, 'runfile') + + # Get help + control.inspect_current_object() + + # Check that a expected text is part of the page + qtbot.waitUntil(lambda: check_text(webpage, "namespace"), timeout=4000) + + # --- From the editor --- + qtbot.wait(2000) + main_window.editor.new() + code_editor = main_window.editor.get_focus_widget() + editorstack = main_window.editor.get_current_editorstack() + + # Write some object in the editor + code_editor.set_text('range') + code_editor.move_cursor(len('range')) + + # Get help + editorstack.inspect_current_object() + + # Check that a expected text is part of the page + qtbot.waitUntil(lambda: check_text(webpage, "range"), timeout=4000) + + @pytest.mark.slow def test_window_title(main_window, tmpdir): """Test window title with non-ascii characters.""" diff --git a/spyder/plugins/help.py b/spyder/plugins/help.py index c63c3565492..d9712bc49bc 100644 --- a/spyder/plugins/help.py +++ b/spyder/plugins/help.py @@ -338,8 +338,6 @@ def __init__(self, parent=None): self.internal_shell = None self.console = None - self.ipyconsole = None - self.editor = None # Initialize plugin self.initialize_plugin() @@ -507,8 +505,6 @@ def register_plugin(self): self.internal_shell = self.main.console.shell self.console = self.main.console - self.ipyconsole = self.main.ipyconsole - self.editor = self.main.editor def closing_plugin(self, cancelable=False): """Perform actions before parent main window is closed""" @@ -549,8 +545,8 @@ def apply_plugin_settings(self, options): self.toggle_math_mode(math_o) # To make auto-connection changes take place instantly - self.editor.apply_plugin_settings(options=[connect_n]) - self.ipyconsole.apply_plugin_settings(options=[connect_n]) + self.main.editor.apply_plugin_settings(options=[connect_n]) + self.main.ipyconsole.apply_plugin_settings(options=[connect_n]) #------ Public API (related to Help's source) ------------------------- def source_is_console(self): @@ -821,8 +817,8 @@ def __eventually_raise_help(self, text, force=False): (force or text != self._last_texts[index])): dockwidgets = self.main.tabifiedDockWidgets(self.dockwidget) if (self.console.dockwidget not in dockwidgets and - self.ipyconsole is not None and - self.ipyconsole.dockwidget not in dockwidgets): + self.main.ipyconsole is not None and + self.main.ipyconsole.dockwidget not in dockwidgets): self.dockwidget.show() self.dockwidget.raise_() self._last_texts[index] = text @@ -904,8 +900,8 @@ def get_shell(self): (hasattr(self.shell, 'is_running') and not self.shell.is_running())): self.shell = None - if self.ipyconsole is not None: - shell = self.ipyconsole.get_current_shellwidget() + if self.main.ipyconsole is not None: + shell = self.main.ipyconsole.get_current_shellwidget() if shell is not None and shell.kernel_client is not None: self.shell = shell if self.shell is None: @@ -915,8 +911,8 @@ def get_shell(self): def render_sphinx_doc(self, doc, context=None): """Transform doc string dictionary to HTML and show it""" # Math rendering option could have changed - if self.editor is not None: - fname = self.editor.get_current_filename() + if self.main.editor is not None: + fname = self.main.editor.get_current_filename() dname = osp.dirname(fname) else: dname = '' diff --git a/spyder/plugins/tests/test_help.py b/spyder/plugins/tests/test_help.py index aa3f81a01d3..91431154080 100644 --- a/spyder/plugins/tests/test_help.py +++ b/spyder/plugins/tests/test_help.py @@ -17,6 +17,7 @@ from mock import Mock, MagicMock # Python 2 # Third party imports +from qtpy.QtWidgets import QWidget from qtpy.QtWebEngineWidgets import WEBENGINE import pytest from flaky import flaky @@ -32,9 +33,17 @@ @pytest.fixture def help_plugin(qtbot): """Help plugin fixture""" - help_plugin = Help() - webview = help_plugin.rich_text.webview._webview + class MainMock(QWidget): + def __getattr__(self, attr): + if attr == 'ipyconsole' or attr == 'editor': + return None + else: + return Mock() + + help_plugin = Help(parent=MainMock()) + + webview = help_plugin.rich_text.webview._webview if WEBENGINE: help_plugin._webpage = webview.page() else: @@ -93,7 +102,7 @@ def test_no_further_docs_message(help_plugin, qtbot): timeout=3000) -def test_help_opens_when_show_tutorial_unit(help_plugin, qtbot,): +def test_help_opens_when_show_tutorial_unit(help_plugin, qtbot): """Test fix for #6317 : 'Show tutorial' opens the help plugin if closed.""" MockDockwidget = MagicMock() MockDockwidget.return_value.isVisible.return_value = False