Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PR: Fix showing Spyder-kernels message on kernel restarts (IPython console) #20233

Merged
merged 2 commits into from
Dec 21, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/scripts/install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -67,11 +67,11 @@ python -bb -X dev -W error -m build
python -bb -X dev -W error -m pip install --no-deps dist/spyder*.whl

# Create environment for Jedi environments tests
mamba create -n jedi-test-env -q -y python=3.6 flask spyder-kernels
mamba create -n jedi-test-env -q -y python=3.9 flask spyder-kernels
mamba list -n jedi-test-env

# Create environment to test conda activation before launching a spyder kernel
mamba create -n spytest-ž -q -y python=3.6 spyder-kernels
mamba create -n spytest-ž -q -y python=3.9 spyder-kernels
mamba list -n spytest-ž

# Install pyenv in Posix systems
Expand Down
39 changes: 23 additions & 16 deletions spyder/plugins/ipythonconsole/tests/test_ipythonconsole.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,14 +44,15 @@
running_in_ci, running_in_ci_with_conda)
from spyder.config.gui import get_color_scheme
from spyder.config.manager import CONF
from spyder.config.utils import is_anaconda
from spyder.py3compat import PY2, to_text_string
from spyder.plugins.help.tests.test_plugin import check_text
from spyder.plugins.help.utils.sphinxify import CSS_PATH
from spyder.plugins.ipythonconsole.plugin import IPythonConsole
from spyder.plugins.ipythonconsole.utils.style import create_style_class
from spyder.plugins.ipythonconsole.widgets import ClientWidget
from spyder.utils.programs import get_temp_dir
from spyder.utils.conda import is_conda_env
from spyder.utils.conda import get_conda_root_prefix


# =============================================================================
Expand All @@ -78,8 +79,11 @@ def get_console_background_color(style_sheet):
return background_color


def get_conda_test_env(test_env_name=u'spytest-ž'):
"""Return the full prefix path of the given `test_env_name`."""
def get_conda_test_env(test_env_name='spytest-ž'):
"""
Return the full prefix path of the given `test_env_name` and its
executable.
"""
if 'envs' in sys.prefix:
root_prefix = os.path.dirname(os.path.dirname(sys.prefix))
else:
Expand All @@ -92,7 +96,7 @@ def get_conda_test_env(test_env_name=u'spytest-ž'):
else:
test_env_executable = os.path.join(test_env_prefix, 'bin', 'python')

return test_env_executable
return (test_env_prefix, test_env_executable)


# =============================================================================
Expand Down Expand Up @@ -196,7 +200,7 @@ def __getattr__(self, attr):
if test_environment_interpreter:
configuration.set('main_interpreter', 'default', False)
configuration.set(
'main_interpreter', 'executable', get_conda_test_env())
'main_interpreter', 'executable', get_conda_test_env()[1])
else:
configuration.set('main_interpreter', 'default', True)
configuration.set('main_interpreter', 'executable', '')
Expand Down Expand Up @@ -1657,6 +1661,8 @@ def test_calltip(ipyconsole, qtbot):
@flaky(max_runs=3)
@pytest.mark.order(1)
@pytest.mark.test_environment_interpreter
@pytest.mark.skipif(not is_anaconda(), reason='Only works with Anaconda')
@pytest.mark.skipif(not running_in_ci(), reason='Only works on CIs')
def test_conda_env_activation(ipyconsole, qtbot):
"""
Test that the conda environment associated with an external interpreter
Expand All @@ -1668,12 +1674,12 @@ def test_conda_env_activation(ipyconsole, qtbot):
# Get conda activation environment variable
with qtbot.waitSignal(shell.executed):
shell.execute(
"import os; conda_prefix = os.environ.get('CONDA_PREFIX')")
"import os; conda_prefix = os.environ.get('CONDA_PREFIX')"
)

expected_output = get_conda_test_env().replace('\\', '/')
if is_conda_env(expected_output):
output = shell.get_value('conda_prefix').replace('\\', '/')
assert expected_output == output
expected_output = get_conda_test_env()[0].replace('\\', '/')
output = shell.get_value('conda_prefix').replace('\\', '/')
assert expected_output == output


@flaky(max_runs=3)
Expand Down Expand Up @@ -2438,8 +2444,7 @@ def test_run_script(ipyconsole, qtbot, tmp_path):


@pytest.mark.skipif(
not sys.platform.startswith('linux'),
reason="Only runs on Linux")
not is_anaconda(), reason="Only works with Anaconda")
def test_show_spyder_kernels_error_on_restart(ipyconsole, qtbot):
"""Test that we show Spyder-kernels error message on restarts."""
# Wait until the window is fully up
Expand All @@ -2449,11 +2454,13 @@ def test_show_spyder_kernels_error_on_restart(ipyconsole, qtbot):

# Point to an interpreter without Spyder-kernels
ipyconsole.set_conf('default', False, section='main_interpreter')
ipyconsole.set_conf('executable', '/usr/bin/python3',
section='main_interpreter')
if os.name == 'nt':
pyexec = osp.join(get_conda_root_prefix(), 'python.exe')
else:
pyexec = osp.join(get_conda_root_prefix(), 'bin', 'python')
ipyconsole.set_conf('executable', pyexec, section='main_interpreter')

# Restart kernel
os.environ['SPY_TEST_SHOW_RESTART_MESSAGE'] = 'true'
ipyconsole.restart_kernel()

# Assert we show a kernel error
Expand All @@ -2467,7 +2474,7 @@ def test_show_spyder_kernels_error_on_restart(ipyconsole, qtbot):
timeout=6000
)

# To check kernel error visually
# To check the kernel error visually
qtbot.wait(500)

# Check kernel related actions are disabled
Expand Down
54 changes: 24 additions & 30 deletions spyder/plugins/ipythonconsole/widgets/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -833,38 +833,32 @@ def has_spyder_kernels(self):
interpreter=pyexec,
version=SPYDER_KERNELS_VERSION)

if (
not has_spyder_kernels
# This is necessary to show this message for some tests and not
# do it for others.
and os.environ.get('SPY_TEST_SHOW_RESTART_MESSAGE')
):
self.show_kernel_error(
_("The Python environment or installation whose "
"interpreter is located at"
"<pre>"
" <tt>{0}</tt>"
"</pre>"
"doesn't have the <tt>spyder-kernels</tt> module or the "
"right version of it installed ({1}). "
"Without this module is not possible for Spyder to "
"create a console for you.<br><br>"
"You can install it by activating your environment (if "
"necessary) and then running in a system terminal:"
"<pre>"
" <tt>{2}</tt>"
"</pre>"
"or"
"<pre>"
" <tt>{3}</tt>"
"</pre>").format(
pyexec,
SPYDER_KERNELS_VERSION_MSG,
SPYDER_KERNELS_CONDA,
SPYDER_KERNELS_PIP
)
msg = _(
"The Python environment or installation whose interpreter is "
"located at"
"<pre>"
" <tt>{0}</tt>"
"</pre>"
"doesn't have the <tt>spyder-kernels</tt> module or the right "
"version of it installed ({1}). Without this module is not "
"possible for Spyder to create a console for you.<br><br>"
"You can install it by activating your environment first (if "
"necessary) and then running in a system terminal:"
"<pre>"
" <tt>{2}</tt>"
"</pre>"
"or"
"<pre>"
" <tt>{3}</tt>"
"</pre>").format(
pyexec,
SPYDER_KERNELS_VERSION_MSG,
SPYDER_KERNELS_CONDA,
SPYDER_KERNELS_PIP
)

if not has_spyder_kernels:
self.show_kernel_error(msg)
return False
else:
return True
Expand Down
5 changes: 3 additions & 2 deletions spyder/plugins/ipythonconsole/widgets/shell.py
Original file line number Diff line number Diff line change
Expand Up @@ -264,8 +264,9 @@ def interrupt_kernel(self):
super(ShellWidget, self).interrupt_kernel()
else:
self._append_html(
_("The kernel appears to be dead, so it can't be interrupted. "
"Please open a new console to keep working.")
_("<br><br>The kernel appears to be dead, so it can't be "
"interrupted. Please open a new console to keep "
"working.<br>")
)

def execute(self, source=None, hidden=False, interactive=False):
Expand Down