From c09931eaf9d99e791fb6241da62c49bca5404581 Mon Sep 17 00:00:00 2001 From: Carlos Cordoba Date: Sun, 4 Mar 2018 19:34:18 -0500 Subject: [PATCH 1/7] Testing: Don't open the "Connect to external kernel" dialog to avoid segfaults --- spyder/plugins/tests/test_ipythonconsole.py | 40 ++++++--------------- 1 file changed, 10 insertions(+), 30 deletions(-) diff --git a/spyder/plugins/tests/test_ipythonconsole.py b/spyder/plugins/tests/test_ipythonconsole.py index 1fb6c90393f..030f3283559 100644 --- a/spyder/plugins/tests/test_ipythonconsole.py +++ b/spyder/plugins/tests/test_ipythonconsole.py @@ -23,7 +23,7 @@ from spyder.config.gui import get_color_scheme from spyder.config.main import CONF -from spyder.py3compat import PY2, PY3 +from spyder.py3compat import PY2, PY3, to_text_string from spyder.plugins.ipythonconsole import (IPythonConsole, KernelConnectionDialog) from spyder.utils.environ import listdict2envdict @@ -44,24 +44,18 @@ #============================================================================== # Utillity Functions #============================================================================== -def open_client_from_connection_info(connection_info, qtbot): - top_level_widgets = QApplication.topLevelWidgets() - for w in top_level_widgets: - if isinstance(w, KernelConnectionDialog): - w.cf.setText(connection_info) - qtbot.keyClick(w, Qt.Key_Enter) - def get_console_font_color(syntax_style): styles = create_style_class(syntax_style).styles font_color = styles[Name] - return font_color + def get_console_background_color(style_sheet): background_color = style_sheet.split('background-color:')[1] background_color = background_color.split(';')[0] return background_color + #============================================================================== # Qt Test Fixtures #============================================================================== @@ -709,8 +703,6 @@ def test_restart_kernel(ipyconsole, qtbot): @pytest.mark.slow @flaky(max_runs=3) -@pytest.mark.skipif(os.name == 'nt' or PYQT4, - reason="It doesn't work on Windows and segfaults in PyQt4") def test_load_kernel_file_from_id(ipyconsole, qtbot): """ Test that a new client is created using its id @@ -722,9 +714,7 @@ def test_load_kernel_file_from_id(ipyconsole, qtbot): connection_file = osp.basename(client.connection_file) id_ = connection_file.split('kernel-')[-1].split('.json')[0] - QTimer.singleShot(2000, lambda: open_client_from_connection_info( - id_, qtbot)) - ipyconsole.create_client_for_kernel() + ipyconsole._create_client_for_kernel(id_, None, None, None) qtbot.wait(1000) new_client = ipyconsole.get_clients()[1] @@ -733,9 +723,7 @@ def test_load_kernel_file_from_id(ipyconsole, qtbot): @pytest.mark.slow @flaky(max_runs=3) -@pytest.mark.skipif(os.name == 'nt' or PYQT4, - reason="It segfaults frequently") -def test_load_kernel_file_from_location(ipyconsole, qtbot): +def test_load_kernel_file_from_location(ipyconsole, qtbot, tmpdir): """ Test that a new client is created using a connection file placed in a different location from jupyter_runtime_dir @@ -744,14 +732,11 @@ def test_load_kernel_file_from_location(ipyconsole, qtbot): client = ipyconsole.get_current_client() qtbot.waitUntil(lambda: shell._prompt_html is not None, timeout=SHELL_TIMEOUT) - connection_file = osp.join(tempfile.gettempdir(), - osp.basename(client.connection_file)) + fname = osp.basename(client.connection_file) + connection_file = to_text_string(tmpdir.join(fname)) shutil.copy2(client.connection_file, connection_file) - QTimer.singleShot(2000, lambda: open_client_from_connection_info( - connection_file, - qtbot)) - ipyconsole.create_client_for_kernel() + ipyconsole._create_client_for_kernel(connection_file, None, None, None) qtbot.wait(1000) assert len(ipyconsole.get_clients()) == 2 @@ -759,9 +744,7 @@ def test_load_kernel_file_from_location(ipyconsole, qtbot): @pytest.mark.slow @flaky(max_runs=3) -@pytest.mark.skipif(os.name == 'nt' or PYQT4, - reason="It segfaults frequently") -def test_load_kernel_file(ipyconsole, qtbot): +def test_load_kernel_file(ipyconsole, qtbot, tmpdir): """ Test that a new client is created using the connection file of an existing client @@ -770,10 +753,7 @@ def test_load_kernel_file(ipyconsole, qtbot): client = ipyconsole.get_current_client() qtbot.waitUntil(lambda: shell._prompt_html is not None, timeout=SHELL_TIMEOUT) - QTimer.singleShot(2000, lambda: open_client_from_connection_info( - client.connection_file, - qtbot)) - ipyconsole.create_client_for_kernel() + ipyconsole._create_client_for_kernel(client.connection_file, None, None, None) qtbot.wait(1000) new_client = ipyconsole.get_clients()[1] From 6085ba418759ca7b03fb85cf7cbf3408dfde563d Mon Sep 17 00:00:00 2001 From: Carlos Cordoba Date: Sun, 4 Mar 2018 19:40:46 -0500 Subject: [PATCH 2/7] Testing: Don't show syspath dialog to avoid segfaults --- spyder/plugins/tests/test_ipythonconsole.py | 24 ++++++--------------- 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/spyder/plugins/tests/test_ipythonconsole.py b/spyder/plugins/tests/test_ipythonconsole.py index 030f3283559..fbd553e60ec 100644 --- a/spyder/plugins/tests/test_ipythonconsole.py +++ b/spyder/plugins/tests/test_ipythonconsole.py @@ -348,38 +348,26 @@ def test_get_env(ipyconsole, qtbot): @pytest.mark.slow @flaky(max_runs=3) -@pytest.mark.skipif(os.name == 'nt' or PYQT4, - reason="It doesn't work on Windows and segfaults in PyQt4") -def test_get_syspath(ipyconsole, qtbot): +def test_get_syspath(ipyconsole, qtbot, tmpdir): """Test that showing sys.path contents is working as expected.""" shell = ipyconsole.get_current_shellwidget() qtbot.waitUntil(lambda: shell._prompt_html is not None, timeout=SHELL_TIMEOUT) # Add a new entry to sys.path with qtbot.waitSignal(shell.executed): - tmp_dir = tempfile.mkdtemp() - shell.execute("import sys, tempfile; sys.path.append('%s')" % tmp_dir) + tmp_dir = to_text_string(tmpdir) + shell.execute("import sys; sys.path.append('%s')" % tmp_dir) # Ask for sys.path contents - with qtbot.waitSignal(shell.sig_show_syspath): + with qtbot.waitSignal(shell.sig_show_syspath) as blocker: shell.get_syspath() - # Get sys.path contents from the generated widget - top_level_widgets = QApplication.topLevelWidgets() - for w in top_level_widgets: - if isinstance(w, CollectionsEditor): - syspath_contents = w.get_value() - qtbot.keyClick(w, Qt.Key_Enter) + # Get sys.path contents from the signal + syspath_contents = blocker.args[0] # Assert that our added entry is part of sys.path assert tmp_dir in syspath_contents - # Remove temporary directory - try: - os.rmdir(tmp_dir) - except: - pass - @pytest.mark.slow @flaky(max_runs=10) From 6e8288b66cf97712ab33051c98e37e30ba3de59e Mon Sep 17 00:00:00 2001 From: Carlos Cordoba Date: Sun, 4 Mar 2018 19:47:21 -0500 Subject: [PATCH 3/7] Testing: Don't show get env vars dialog to avoid segfaults --- spyder/plugins/tests/test_ipythonconsole.py | 30 ++++++++------------- 1 file changed, 11 insertions(+), 19 deletions(-) diff --git a/spyder/plugins/tests/test_ipythonconsole.py b/spyder/plugins/tests/test_ipythonconsole.py index fbd553e60ec..79645c81076 100644 --- a/spyder/plugins/tests/test_ipythonconsole.py +++ b/spyder/plugins/tests/test_ipythonconsole.py @@ -16,21 +16,17 @@ import ipykernel from pygments.token import Name import pytest -from qtpy import PYQT4, PYQT5, PYQT_VERSION +from qtpy import PYQT4, PYQT5 from qtpy.QtCore import Qt, QTimer -from qtpy.QtWidgets import QApplication import zmq from spyder.config.gui import get_color_scheme from spyder.config.main import CONF -from spyder.py3compat import PY2, PY3, to_text_string -from spyder.plugins.ipythonconsole import (IPythonConsole, - KernelConnectionDialog) -from spyder.utils.environ import listdict2envdict +from spyder.py3compat import PY2, to_text_string +from spyder.plugins.ipythonconsole import IPythonConsole from spyder.utils.ipython.style import create_style_class from spyder.utils.programs import TEMPDIR from spyder.utils.test import close_message_box -from spyder.widgets.variableexplorer.collectionseditor import CollectionsEditor #============================================================================== @@ -319,10 +315,8 @@ def test_console_coloring(ipyconsole, qtbot): @pytest.mark.slow @flaky(max_runs=3) -@pytest.mark.skipif(os.name == 'nt' or PYQT4, - reason="It doesn't work on Windows and segfaults in PyQt4") def test_get_env(ipyconsole, qtbot): - """Test that showing env var contents is working as expected.""" + """Test that getting env vars from the kernel is working as expected.""" shell = ipyconsole.get_current_shellwidget() qtbot.waitUntil(lambda: shell._prompt_html is not None, timeout=SHELL_TIMEOUT) @@ -331,25 +325,23 @@ def test_get_env(ipyconsole, qtbot): shell.execute("import os; os.environ['FOO'] = 'bar'" ) # Ask for os.environ contents - with qtbot.waitSignal(shell.sig_show_env): + with qtbot.waitSignal(shell.sig_show_env) as blocker: shell.get_env() - # Get env contents from the generated widget - top_level_widgets = QApplication.topLevelWidgets() - for w in top_level_widgets: - if isinstance(w, CollectionsEditor): - env_contents = w.get_value() - qtbot.keyClick(w, Qt.Key_Enter) + # Get env contents from the signal + env_contents = blocker.args[0] # Assert that our added entry is part of os.environ - env_contents = listdict2envdict(env_contents) assert env_contents['FOO'] == 'bar' @pytest.mark.slow @flaky(max_runs=3) def test_get_syspath(ipyconsole, qtbot, tmpdir): - """Test that showing sys.path contents is working as expected.""" + """ + Test that getting sys.path contents from the kernel is working as + expected. + """ shell = ipyconsole.get_current_shellwidget() qtbot.waitUntil(lambda: shell._prompt_html is not None, timeout=SHELL_TIMEOUT) From 2f6636c61e6ee54d1785c485f81db00fdec4bc92 Mon Sep 17 00:00:00 2001 From: Carlos Cordoba Date: Sun, 4 Mar 2018 20:15:34 -0500 Subject: [PATCH 4/7] Testing: Don't show dialog asking to restart a kernel to avoid segfaults --- spyder/plugins/tests/test_ipythonconsole.py | 7 ++----- spyder/widgets/ipythonconsole/client.py | 17 ++++++++++------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/spyder/plugins/tests/test_ipythonconsole.py b/spyder/plugins/tests/test_ipythonconsole.py index 79645c81076..2d45b5eac73 100644 --- a/spyder/plugins/tests/test_ipythonconsole.py +++ b/spyder/plugins/tests/test_ipythonconsole.py @@ -17,7 +17,7 @@ from pygments.token import Name import pytest from qtpy import PYQT4, PYQT5 -from qtpy.QtCore import Qt, QTimer +from qtpy.QtCore import Qt import zmq from spyder.config.gui import get_color_scheme @@ -26,7 +26,6 @@ from spyder.plugins.ipythonconsole import IPythonConsole from spyder.utils.ipython.style import create_style_class from spyder.utils.programs import TEMPDIR -from spyder.utils.test import close_message_box #============================================================================== @@ -658,8 +657,6 @@ def test_clear_and_reset_magics_dbg(ipyconsole, qtbot): @pytest.mark.slow @flaky(max_runs=3) -@pytest.mark.skipif(os.name == 'nt' or PYQT4, - reason="It doesn't work on Windows and segfaults in PyQt4") def test_restart_kernel(ipyconsole, qtbot): """ Test that kernel is restarted correctly @@ -674,10 +671,10 @@ def test_restart_kernel(ipyconsole, qtbot): # Restart kernel and wait until it's up again shell._prompt_html = None - QTimer.singleShot(1000, lambda: close_message_box(qtbot)) client.restart_kernel() qtbot.waitUntil(lambda: shell._prompt_html is not None, timeout=SHELL_TIMEOUT) + assert 'Restarting kernel...' in shell._control.toPlainText() assert not shell.is_defined('a') diff --git a/spyder/widgets/ipythonconsole/client.py b/spyder/widgets/ipythonconsole/client.py index 9c4e2becf92..281fdbbb905 100644 --- a/spyder/widgets/ipythonconsole/client.py +++ b/spyder/widgets/ipythonconsole/client.py @@ -27,13 +27,13 @@ QToolButton, QVBoxLayout, QWidget) # Local imports -from spyder.config.base import _, get_image_path, get_module_source_path +from spyder.config.base import (_, get_image_path, get_module_source_path, + running_under_pytest) from spyder.config.gui import get_font, get_shortcut from spyder.utils import icon_manager as ima from spyder.utils import sourcecode from spyder.utils.encoding import get_coding from spyder.utils.environ import RemoteEnvDialog -from spyder.utils.ipython.style import create_qss_style from spyder.utils.programs import TEMPDIR from spyder.utils.qthelpers import (add_actions, create_action, create_toolbutton, DialogManager, @@ -459,12 +459,15 @@ def restart_kernel(self): """ sw = self.shellwidget - message = _('Are you sure you want to restart the kernel?') - buttons = QMessageBox.Yes | QMessageBox.No - result = QMessageBox.question(self, _('Restart kernel?'), - message, buttons) + if not running_under_pytest(): + message = _('Are you sure you want to restart the kernel?') + buttons = QMessageBox.Yes | QMessageBox.No + result = QMessageBox.question(self, _('Restart kernel?'), + message, buttons) + else: + result = None - if result == QMessageBox.Yes: + if result == QMessageBox.Yes or running_under_pytest(): if sw.kernel_manager: if self.infowidget.isVisible(): self.infowidget.hide() From b73103da7aa85ddb973151bf2971edae362026b5 Mon Sep 17 00:00:00 2001 From: Carlos Cordoba Date: Sun, 4 Mar 2018 20:32:45 -0500 Subject: [PATCH 5/7] Testing: Wait until the console is up for several console tests --- spyder/plugins/tests/test_ipythonconsole.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/spyder/plugins/tests/test_ipythonconsole.py b/spyder/plugins/tests/test_ipythonconsole.py index 2d45b5eac73..8ac50d9e7eb 100644 --- a/spyder/plugins/tests/test_ipythonconsole.py +++ b/spyder/plugins/tests/test_ipythonconsole.py @@ -151,6 +151,9 @@ def test_tab_rename_for_slaves(ipyconsole, qtbot): @pytest.mark.skipif(os.name == 'nt', reason="It times out sometimes on Windows") def test_no_repeated_tabs_name(ipyconsole, qtbot): """Test that tabs can't have repeated given names.""" + shell = ipyconsole.get_current_shellwidget() + qtbot.waitUntil(lambda: shell._prompt_html is not None, timeout=SHELL_TIMEOUT) + # Rename first client ipyconsole.rename_tabs_after_change('foo') @@ -168,6 +171,9 @@ def test_no_repeated_tabs_name(ipyconsole, qtbot): @pytest.mark.skipif(os.name == 'nt', reason="It times out sometimes on Windows") def test_tabs_preserve_name_after_move(ipyconsole, qtbot): """Test that tabs preserve their names after they are moved.""" + shell = ipyconsole.get_current_shellwidget() + qtbot.waitUntil(lambda: shell._prompt_html is not None, timeout=SHELL_TIMEOUT) + # Create a new client ipyconsole.create_new_client() @@ -256,6 +262,9 @@ def test_console_import_namespace(ipyconsole, qtbot): @flaky(max_runs=3) def test_console_disambiguation(ipyconsole, qtbot): """Test the disambiguation of dedicated consoles.""" + shell = ipyconsole.get_current_shellwidget() + qtbot.waitUntil(lambda: shell._prompt_html is not None, timeout=SHELL_TIMEOUT) + # Create directories and file for TEMP_DIRECTORY/a/b/c.py # and TEMP_DIRECTORY/a/d/c.py dir_b = osp.join(TEMP_DIRECTORY, 'a', 'b') @@ -290,6 +299,9 @@ def test_console_disambiguation(ipyconsole, qtbot): @pytest.mark.slow @flaky(max_runs=3) def test_console_coloring(ipyconsole, qtbot): + """Test that console gets the same coloring present in the Editor.""" + shell = ipyconsole.get_current_shellwidget() + qtbot.waitUntil(lambda: shell._prompt_html is not None, timeout=SHELL_TIMEOUT) config_options = ipyconsole.config_options() From c3a3733a0dd47246be4ba32056823cb7657c6149 Mon Sep 17 00:00:00 2001 From: Carlos Cordoba Date: Sun, 4 Mar 2018 20:41:03 -0500 Subject: [PATCH 6/7] Testing: Skip test_get_syspath on Windows because it's failing --- spyder/plugins/tests/test_ipythonconsole.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/spyder/plugins/tests/test_ipythonconsole.py b/spyder/plugins/tests/test_ipythonconsole.py index 8ac50d9e7eb..b60b22631ac 100644 --- a/spyder/plugins/tests/test_ipythonconsole.py +++ b/spyder/plugins/tests/test_ipythonconsole.py @@ -348,6 +348,8 @@ def test_get_env(ipyconsole, qtbot): @pytest.mark.slow @flaky(max_runs=3) +@pytest.mark.skipif(os.name == 'nt', + reason="Fails due to differences in path handling") def test_get_syspath(ipyconsole, qtbot, tmpdir): """ Test that getting sys.path contents from the kernel is working as From baf086f836534e1f349d17271c48e3b72b76079d Mon Sep 17 00:00:00 2001 From: Carlos Cordoba Date: Sun, 4 Mar 2018 20:46:01 -0500 Subject: [PATCH 7/7] Testing: Remove several skipif's for Windows in the console tests --- spyder/plugins/tests/test_ipythonconsole.py | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/spyder/plugins/tests/test_ipythonconsole.py b/spyder/plugins/tests/test_ipythonconsole.py index b60b22631ac..6439f9608b8 100644 --- a/spyder/plugins/tests/test_ipythonconsole.py +++ b/spyder/plugins/tests/test_ipythonconsole.py @@ -126,7 +126,6 @@ def test_auto_backend(ipyconsole, qtbot): @pytest.mark.slow @flaky(max_runs=3) -@pytest.mark.skipif(os.name == 'nt', reason="It times out sometimes on Windows") def test_tab_rename_for_slaves(ipyconsole, qtbot): """Test slave clients are renamed correctly.""" # Wait until the window is fully up @@ -148,7 +147,6 @@ def test_tab_rename_for_slaves(ipyconsole, qtbot): @pytest.mark.slow @flaky(max_runs=3) -@pytest.mark.skipif(os.name == 'nt', reason="It times out sometimes on Windows") def test_no_repeated_tabs_name(ipyconsole, qtbot): """Test that tabs can't have repeated given names.""" shell = ipyconsole.get_current_shellwidget() @@ -168,7 +166,6 @@ def test_no_repeated_tabs_name(ipyconsole, qtbot): @pytest.mark.slow @flaky(max_runs=3) -@pytest.mark.skipif(os.name == 'nt', reason="It times out sometimes on Windows") def test_tabs_preserve_name_after_move(ipyconsole, qtbot): """Test that tabs preserve their names after they are moved.""" shell = ipyconsole.get_current_shellwidget() @@ -187,7 +184,6 @@ def test_tabs_preserve_name_after_move(ipyconsole, qtbot): @pytest.mark.slow @flaky(max_runs=3) -@pytest.mark.skipif(os.name == 'nt', reason="It times out sometimes on Windows") def test_conf_env_vars(ipyconsole, qtbot): """Test that kernels have env vars set by our kernel spec.""" # Wait until the window is fully up @@ -205,7 +201,6 @@ def test_conf_env_vars(ipyconsole, qtbot): @pytest.mark.slow @flaky(max_runs=3) -@pytest.mark.skipif(os.name == 'nt', reason="It times out sometimes on Windows") @pytest.mark.no_stderr_file def test_no_stderr_file(ipyconsole, qtbot): """Test that consoles can run without an stderr.""" @@ -225,7 +220,7 @@ def test_no_stderr_file(ipyconsole, qtbot): @pytest.mark.slow @pytest.mark.non_ascii_dir @flaky(max_runs=3) -@pytest.mark.skipif(os.name == 'nt', reason="It times out sometimes on Windows") +@pytest.mark.skipif(os.name == 'nt', reason="It fails on Windows") def test_non_ascii_stderr_file(ipyconsole, qtbot): """Test the creation of a console with a stderr file in a non-ascii dir.""" # Wait until the window is fully up @@ -243,7 +238,6 @@ def test_non_ascii_stderr_file(ipyconsole, qtbot): @pytest.mark.slow @flaky(max_runs=3) -@pytest.mark.skipif(os.name == 'nt', reason="It times out sometimes on Windows") def test_console_import_namespace(ipyconsole, qtbot): """Test an import of the form 'from foo import *'.""" # Wait until the window is fully up @@ -410,8 +404,7 @@ def test_browse_history_dbg(ipyconsole, qtbot): @pytest.mark.slow @flaky(max_runs=3) -@pytest.mark.skipif(os.name == 'nt' or PY2, - reason="It times out sometimes on Windows and doesn't work on PY2") +@pytest.mark.skipif(PY2, reason="It doesn't work on PY2") def test_unicode_vars(ipyconsole, qtbot): """ Test that the Variable Explorer Works with unicode variables. @@ -533,7 +526,6 @@ def test_plot_magic_dbg(ipyconsole, qtbot): @pytest.mark.slow @flaky(max_runs=3) -@pytest.mark.skipif(os.name == 'nt', reason="It times out on Windows") def test_run_doctest(ipyconsole, qtbot): """ Test that doctests can be run without problems @@ -758,7 +750,6 @@ def test_load_kernel_file(ipyconsole, qtbot, tmpdir): @pytest.mark.slow @flaky(max_runs=3) -@pytest.mark.skipif(os.name == 'nt', reason="It times out on Windows") def test_sys_argv_clear(ipyconsole, qtbot): """Test that sys.argv is cleared up correctly""" shell = ipyconsole.get_current_shellwidget()