diff --git a/ipyparallel/client/client.py b/ipyparallel/client/client.py index b47e60c0..8fec6f11 100644 --- a/ipyparallel/client/client.py +++ b/ipyparallel/client/client.py @@ -49,6 +49,7 @@ from ipyparallel import error, serialize, util from ipyparallel.serialize import PrePickled, Reference from ipyparallel.util import _OutputProducingThread as Thread +from ipyparallel.util import _TermColors from .asyncresult import AsyncHubResult, AsyncResult from .futures import MessageFuture, multi_future @@ -161,11 +162,30 @@ def _plaintext(self) -> str: if not text_out: return '' + ip = get_ipython() + if ip is None: + colors = "NoColor" + else: + colors = ip.colors + + if colors.lower() == "nocolor": + out = normal = "" + else: + out = _TermColors.Red + normal = _TermColors.Normal + if '\n' in text_out and not text_out.startswith('\n'): # add newline for multiline reprs text_out = '\n' + text_out - return f"Out[{self.metadata['engine_id']}:{self.execution_count}]: {text_out}" + return ''.join( + [ + out, + f"Out[{self.metadata['engine_id']}:{self.execution_count}]: ", + normal, + text_out, + ] + ) def _repr_pretty_(self, p, cycle): p.text(self._plaintext()) diff --git a/ipyparallel/engine/app.py b/ipyparallel/engine/app.py index 7f27dcaa..9028f400 100755 --- a/ipyparallel/engine/app.py +++ b/ipyparallel/engine/app.py @@ -758,6 +758,8 @@ def send_with_metadata( if self.use_mpi and self.init_mpi: app.exec_lines.insert(0, self.init_mpi) app.init_profile_dir() + app.init_gui_pylab() + app.init_extensions() app.init_code() # redirect output at the end, only after start is called diff --git a/ipyparallel/tests/clienttest.py b/ipyparallel/tests/clienttest.py index 9f5fb96e..9ac2272d 100644 --- a/ipyparallel/tests/clienttest.py +++ b/ipyparallel/tests/clienttest.py @@ -55,7 +55,7 @@ def generate_output(): a rich displayable object. """ - from IPython.core.display import HTML, Math, display + from IPython.display import HTML, Math, display print("stdout") print("stderr", file=sys.stderr) diff --git a/ipyparallel/tests/test_magics.py b/ipyparallel/tests/test_magics.py index ca3588b7..7602250c 100644 --- a/ipyparallel/tests/test_magics.py +++ b/ipyparallel/tests/test_magics.py @@ -173,18 +173,18 @@ def test_cellpx_groupby_order(self): expected.extend( [ r'\[output:\d+\]', - 'IPython.core.display.HTML', + 'IPython..+.HTML', ] * len(v) ) expected.extend( [ r'\[output:\d+\]', - 'IPython.core.display.Math', + 'IPython..+.Math', ] * len(v) ) - expected.extend([r'Out\[\d+:\d+\]:.*IPython\.core\.display\.Math'] * len(v)) + expected.extend([r'Out\[\d+:\d+\]:.*IPython\..+\.Math'] * len(v)) assert len(lines), len(expected) == io.stdout for line, expect in zip(lines, expected): @@ -440,8 +440,8 @@ def test_result(self): ip.run_line_magic('pxresult', '') assert str(data[name]) in io.stdout - def test_px_pylab(self): - """%pylab works on engines""" + def test_px_matplotlib(self): + """%matplotlib inline works on engines""" pytest.importorskip('matplotlib') ip = get_ipython() v = self.client[-1] @@ -449,15 +449,19 @@ def test_px_pylab(self): v.activate() with capture_output() as io: - ip.run_line_magic("px", "%pylab inline") - - assert ( - "Populating the interactive namespace from numpy and matplotlib" - in io.stdout - ) + ip.run_line_magic( + "px", + "\n".join( + [ + "%matplotlib inline", + "import numpy as np", + "import matplotlib.pyplot as plt", + ] + ), + ) with capture_output(display=False) as io: - ip.run_line_magic("px", "plot(rand(100))") + ip.run_line_magic("px", "plt.plot(np.random.rand(100))") assert 'Out[' in io.stdout assert 'matplotlib.lines' in io.stdout diff --git a/ipyparallel/tests/test_view.py b/ipyparallel/tests/test_view.py index 87439015..e073ec44 100644 --- a/ipyparallel/tests/test_view.py +++ b/ipyparallel/tests/test_view.py @@ -614,7 +614,7 @@ def test_execute_magic(self): def test_execute_displaypub(self): """execute tracks display_pub output""" view = self.client[:] - view.execute("from IPython.core.display import *") + view.execute("from IPython.display import *") ar = view.execute("[ display(i) for i in range(5) ]", block=True) expected = [{'text/plain': str(j)} for j in range(5)] @@ -625,7 +625,7 @@ def test_execute_displaypub(self): def test_apply_displaypub(self): """apply tracks display_pub output""" view = self.client[:] - view.execute("from IPython.core.display import *") + view.execute("from IPython.display import *") @interactive def publish(): diff --git a/ipyparallel/util.py b/ipyparallel/util.py index d4a953f4..7a675980 100644 --- a/ipyparallel/util.py +++ b/ipyparallel/util.py @@ -836,3 +836,10 @@ def __init__(self, target, **kwargs): def _wrapped_target(self, target, *args, **kwargs): _detach_thread_output(self.ident) return target(*args, **kwargs) + + +# minimal subset of TermColors, removed from IPython +# not for public consumption +class _TermColors: + Normal = '\033[0m' + Red = '\033[0;31m'