Skip to content

Commit

Permalink
Merge from 3.1.x: PR #4246
Browse files Browse the repository at this point in the history
Fixes #4002
  • Loading branch information
ccordoba12 committed Mar 11, 2017
2 parents c16023a + 1aa683e commit f24d4d4
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 26 deletions.
48 changes: 40 additions & 8 deletions spyder/plugins/tests/test_ipythonconsole.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,37 @@ def close_widget():
#==============================================================================
# Tests
#==============================================================================
@flaky(max_runs=10)
@pytest.mark.skipif(os.name == 'nt', reason="It times out on Windows")
def test_mpl_backend_change(ipyconsole, qtbot):
"""
Test that Matplotlib backend is changed correctly when
using the %matplotlib magic
"""
shell = ipyconsole.get_current_shellwidget()
client = ipyconsole.get_current_client()
qtbot.waitUntil(lambda: shell._prompt_html is not None, timeout=SHELL_TIMEOUT)

# Import Matplotlib
with qtbot.waitSignal(shell.executed):
shell.execute('import matplotlib.pyplot as plt')

# Generate an inline plot
with qtbot.waitSignal(shell.executed):
shell.execute('plt.plot(range(10))')

# Change backends
with qtbot.waitSignal(shell.executed):
shell.execute('%matplotlib tk')

# Generate another plot
with qtbot.waitSignal(shell.executed):
shell.execute('plt.plot(range(10))')

# Assert that there's a single inline plot in the console
assert shell._control.toHtml().count('img src') == 1


@flaky(max_runs=10)
@pytest.mark.skipif(os.name == 'nt', reason="It times out on Windows")
def test_forced_restart_kernel(ipyconsole, qtbot):
Expand All @@ -71,12 +102,13 @@ def test_forced_restart_kernel(ipyconsole, qtbot):
qtbot.waitUntil(lambda: shell._prompt_html is not None, timeout=SHELL_TIMEOUT)

# Do an assigment to verify that it's not there after restarting
shell.execute('a = 10')
qtbot.wait(500)
with qtbot.waitSignal(shell.executed):
shell.execute('a = 10')

# Generate a traceback and enter debugging mode
shell.execute('1/0')
qtbot.wait(500)
with qtbot.waitSignal(shell.executed):
shell.execute('1/0')

shell.execute('%debug')
qtbot.wait(500)

Expand All @@ -99,8 +131,8 @@ def test_restart_kernel(ipyconsole, qtbot):
qtbot.waitUntil(lambda: shell._prompt_html is not None, timeout=SHELL_TIMEOUT)

# Do an assigment to verify that it's not there after restarting
shell.execute('a = 10')
qtbot.wait(500)
with qtbot.waitSignal(shell.executed):
shell.execute('a = 10')

# Restart kernel and wait until it's up again
shell._prompt_html = None
Expand Down Expand Up @@ -176,8 +208,8 @@ def test_load_kernel_file(ipyconsole, qtbot):

new_client = ipyconsole.get_clients()[1]
new_shell = new_client.shellwidget
new_shell.execute('a = 10')
qtbot.wait(500)
with qtbot.waitSignal(new_shell.executed):
new_shell.execute('a = 10')

assert new_client.name == '1/B'
assert shell.get_value('a') == new_shell.get_value('a')
Expand Down
24 changes: 6 additions & 18 deletions spyder/widgets/ipythonconsole/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,8 @@ def configure_shellwidget(self, give_focus=True):
self.shellwidget.executing.connect(self.add_to_history)

# For Mayavi to run correctly
self.shellwidget.executing.connect(self.set_backend_for_mayavi)
self.shellwidget.executing.connect(
self.shellwidget.set_backend_for_mayavi)

# To update history after execution
self.shellwidget.executed.connect(self.update_history)
Expand All @@ -182,6 +183,10 @@ def configure_shellwidget(self, give_focus=True):
self.shellwidget.sig_dbg_kernel_restart.connect(
self.restart_kernel)

# To correctly change Matplotlib backend interactively
self.shellwidget.executing.connect(
self.shellwidget.change_mpl_backend)

def enable_stop_button(self):
self.stop_button.setEnabled(True)

Expand Down Expand Up @@ -405,23 +410,6 @@ def reset_namespace(self):
def update_history(self):
self.history = self.shellwidget._history

def set_backend_for_mayavi(self, command):
"""
Mayavi plots require the Qt backend, so we try to detect if one is
generated to change backends
"""
calling_mayavi = False
lines = command.splitlines()
for l in lines:
if not l.startswith('#'):
if 'import mayavi' in l or 'from mayavi' in l:
calling_mayavi = True
break
if calling_mayavi:
message = _("Changing backend to Qt for Mayavi")
self.shellwidget._append_plain_text(message + '\n')
self.shellwidget.execute("%gui inline\n%gui qt")

#------ Private API -------------------------------------------------------
def _create_loading_page(self):
"""Create html page to show while the kernel is starting"""
Expand Down
29 changes: 29 additions & 0 deletions spyder/widgets/ipythonconsole/shell.py
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,35 @@ def handle_exec_method(self, msg):
# Remove method after being processed
self._kernel_methods.pop(expression)

def set_backend_for_mayavi(self, command):
"""
Mayavi plots require the Qt backend, so we try to detect if one is
generated to change backends
"""
calling_mayavi = False
lines = command.splitlines()
for l in lines:
if not l.startswith('#'):
if 'import mayavi' in l or 'from mayavi' in l:
calling_mayavi = True
break
if calling_mayavi:
message = _("Changing backend to Qt for Mayavi")
self._append_plain_text(message + '\n')
self.silent_execute("%gui inline\n%gui qt")

def change_mpl_backend(self, command):
"""
If the user is trying to change Matplotlib backends with
%matplotlib, send the same command again to the kernel to
correctly change it.
Fixes issue 4002
"""
if command.startswith('%matplotlib') and \
len(command.splitlines()) == 1:
self.silent_execute(command)

#---- Private methods (overrode by us) ---------------------------------
def _context_menu_make(self, pos):
"""Reimplement the IPython context menu"""
Expand Down

0 comments on commit f24d4d4

Please sign in to comment.