I noticed that JupyterLab notebook uses wrong buffering (for interactive output) for stdout and stderr. For example this cell:
for i in range(2): print(f'stdout: {i}'); print(f'stderr: {i}', file=sys.stderr)
produces the output below. Notice that first the whole stdout is printed, then the whole stderr is printed. As a result the order of the lines is incorrect:
stdout: 0
stdout: 1
stderr: 0
stderr: 1
In the plain IPython (the same version as used by Jupyter) I get the expected result. Probably the streams use line buffering or no buffering:
In [2]: for i in range(2): print(f'stdout: {i}'); print(f'stderr: {i}', file=sys.stderr)
stdout: 0
stderr: 0
stdout: 1
stderr: 1
In JupyterLab if I flush the stream buffer after every print I get the expected output too:
for i in range(2): print(f'stdout: {i}', flush=True); print(f'stderr: {i}', file=sys.stderr, flush=True)
stdout: 0
stderr: 0
stdout: 1
stderr: 1
This suggests that there is no fundamental problem like stdout and stderr being printed only after the execution of the cell finishes. This rather points to a wrong buffering mode of the two streams.
Unfortunately I am not able to change the buffering mode of the streams the usual way because they are instances of a special type ipykernel.iostream.OutStream
which does not have the standard interface method io.TextIOWrapper.reconfigure()
.
How can I fix this unexpected behaviour?
I am using: Python 3.10.4, IPython 8.4.0, ipykernel 6.13.0, jupyter_core 4.10.0.
I noticed this bug report for IPython (from 2015!): buffering problem(?) with print_traceback in the qtconsole