diff --git a/IPython/core/history.py b/IPython/core/history.py index abb434407c9..929b472bd44 100644 --- a/IPython/core/history.py +++ b/IPython/core/history.py @@ -590,7 +590,7 @@ class HistoryOutput: output_type: typing.Literal[ "out_stream", "err_stream", "display_data", "execute_result" ] - bundle: typing.Dict[str, str] + bundle: typing.Dict[str, str | list[str]] class HistoryManager(HistoryAccessor): diff --git a/IPython/core/interactiveshell.py b/IPython/core/interactiveshell.py index ec85e2d3ad9..1176537079d 100644 --- a/IPython/core/interactiveshell.py +++ b/IPython/core/interactiveshell.py @@ -3063,11 +3063,11 @@ def write(data, *args, **kwargs): output_stream = outputs[-1] if output_stream is None: output_stream = HistoryOutput( - output_type=output_type, bundle={"stream": ""} + output_type=output_type, bundle={"stream": []} ) outputs_by_counter[execution_count].append(output_stream) - output_stream.bundle["stream"] += data # Append to existing stream + output_stream.bundle["stream"].append(data) # Append to existing stream return result stream.write = write diff --git a/IPython/core/magics/basic.py b/IPython/core/magics/basic.py index ec1ab532337..386707d236e 100644 --- a/IPython/core/magics/basic.py +++ b/IPython/core/magics/basic.py @@ -571,9 +571,11 @@ def notebook(self, s): for output in outputs[execution_count]: for mime_type, data in output.bundle.items(): if output.output_type == "out_stream": - cell.outputs.append(v4.new_output("stream", text=[data])) + text = data if isinstance(data, list) else [data] + cell.outputs.append(v4.new_output("stream", text=text)) elif output.output_type == "err_stream": - err_output = v4.new_output("stream", text=[data]) + text = data if isinstance(data, list) else [data] + err_output = v4.new_output("stream", text=text) err_output.name = "stderr" cell.outputs.append(err_output) elif output.output_type == "execute_result": diff --git a/tests/test_interactiveshell.py b/tests/test_interactiveshell.py index b16882265b4..be07aa127a4 100644 --- a/tests/test_interactiveshell.py +++ b/tests/test_interactiveshell.py @@ -16,6 +16,7 @@ import shutil import sys import tempfile +import time import unittest import pytest from unittest import mock @@ -84,6 +85,15 @@ def test_run_cell_multiline(self): self.assertEqual(res.success, True) self.assertEqual(res.result, None) + def test_stream_performance(self): + """It should be fast to execute.""" + src = "for i in range(250_000): print(i)" + start = time.perf_counter() + ip.run_cell(src) + end = time.perf_counter() + duration = end - start + assert duration < 10 + def test_multiline_string_cells(self): "Code sprinkled with multiline strings should execute (GH-306)" ip.run_cell("tmp=0")