Skip to content

Commit 8e0e622

Browse files
authored
Fixes to streamed output in native notebooks (microsoft#14158)
For #13611 * Fixes to streamed output * added tests
1 parent b685ef3 commit 8e0e622

File tree

2 files changed

+97
-14
lines changed

2 files changed

+97
-14
lines changed

src/client/datascience/jupyter/kernels/cellExecution.ts

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55

66
import { nbformat } from '@jupyterlab/coreutils';
77
import type { KernelMessage } from '@jupyterlab/services/lib/kernel/messages';
8-
import { CancellationToken, CellOutputKind, CellStreamOutput, NotebookCell, NotebookCellRunState } from 'vscode';
9-
import type { NotebookEditor as VSCNotebookEditor } from '../../../../../types/vscode-proposed';
8+
import { CancellationToken, CellOutputKind, NotebookCell, NotebookCellRunState } from 'vscode';
9+
import type { CellDisplayOutput, NotebookEditor as VSCNotebookEditor } from '../../../../../types/vscode-proposed';
1010
import { concatMultilineString, formatStreamText } from '../../../../datascience-ui/common';
1111
import { IApplicationShell, IVSCodeNotebook } from '../../../common/application/types';
1212
import { traceInfo, traceWarning } from '../../../common/logger';
@@ -531,13 +531,17 @@ export class CellExecution {
531531
}
532532

533533
// Might already have a stream message. If so, just add on to it.
534+
// We use Rich output for text streams (not CellStreamOutput, known VSC Issues).
535+
// https://github.com/microsoft/vscode-python/issues/14156
534536
const lastOutput =
535537
exitingCellOutput.length > 0 ? exitingCellOutput[exitingCellOutput.length - 1] : undefined;
536-
const existing: CellStreamOutput | undefined =
537-
lastOutput && lastOutput.outputKind === CellOutputKind.Text ? lastOutput : undefined;
538-
if (existing) {
538+
const existing: CellDisplayOutput | undefined =
539+
lastOutput && lastOutput.outputKind === CellOutputKind.Rich ? lastOutput : undefined;
540+
if (existing && 'text/plain' in existing.data) {
539541
// tslint:disable-next-line:restrict-plus-operands
540-
existing.text = formatStreamText(concatMultilineString(existing.text + escape(msg.content.text)));
542+
existing.data['text/plain'] = formatStreamText(
543+
concatMultilineString(`${existing.data['text/plain']}${escape(msg.content.text)}`)
544+
);
541545
edit.replaceCellOutput(this.cellIndex, [...exitingCellOutput]); // This is necessary to get VS code to update (for now)
542546
} else {
543547
const originalText = formatStreamText(concatMultilineString(escape(msg.content.text)));

src/test/datascience/notebook/executionService.ds.test.ts

Lines changed: 87 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -221,9 +221,7 @@ suite('DataScience - VSCode Notebook - (Execution) (slow)', function () {
221221
expect(displayCell.metadata.lastRunDuration).to.be.greaterThan(0, 'Duration should be > 0');
222222
expect(markdownOutput.data['text/markdown']).to.be.equal('foo', 'Display cell did not update');
223223
});
224-
test('Clearing output while executing will ensure output is cleared', async function () {
225-
// https://github.com/microsoft/vscode-python/issues/12302
226-
return this.skip();
224+
test('Clearing output while executing will ensure output is cleared', async () => {
227225
// Assume you are executing a cell that prints numbers 1-100.
228226
// When printing number 50, you click clear.
229227
// Cell output should now start printing output from 51 onwards, & not 1.
@@ -235,24 +233,35 @@ suite('DataScience - VSCode Notebook - (Execution) (slow)', function () {
235233
time.sleep(0.1)
236234
print(i)
237235
238-
print("End")`
236+
print("End")`,
237+
0
239238
);
240239
const cell = vscodeNotebook.activeNotebookEditor?.document.cells![0]!;
241240

242241
await executeActiveDocument();
243242

244-
// Wait till execution count changes and status is error.
243+
// Wait till we get the desired output.
245244
await waitForCondition(
246-
async () => assertHasTextOutputInVSCode(cell, 'Start', 0, false),
245+
async () =>
246+
assertHasTextOutputInVSCode(cell, 'Start', 0, false) &&
247+
assertHasTextOutputInVSCode(cell, '0', 0, false) &&
248+
assertHasTextOutputInVSCode(cell, '1', 0, false) &&
249+
assertHasTextOutputInVSCode(cell, '2', 0, false) &&
250+
assertHasTextOutputInVSCode(cell, '3', 0, false) &&
251+
assertHasTextOutputInVSCode(cell, '4', 0, false),
247252
15_000,
248253
'Cell did not get executed'
249254
);
250255

251256
// Clear the cells
252257
await commands.executeCommand('notebook.clearAllCellsOutputs');
253-
// Wait till execution count changes and status is error.
258+
259+
// Wait till previous output gets cleared & we have new output.
254260
await waitForCondition(
255-
async () => assertNotHasTextOutputInVSCode(cell, 'Start', 0, false),
261+
async () =>
262+
assertNotHasTextOutputInVSCode(cell, 'Start', 0, false) &&
263+
cell.outputs.length > 0 &&
264+
cell.outputs[0].outputKind === vscodeNotebookEnums.CellOutputKind.Rich,
256265
5_000,
257266
'Cell did not get cleared'
258267
);
@@ -264,4 +273,74 @@ suite('DataScience - VSCode Notebook - (Execution) (slow)', function () {
264273
// Verify that it hasn't got added (even after interrupting).
265274
assertNotHasTextOutputInVSCode(cell, 'Start', 0, false);
266275
});
276+
test('Clearing output via code', async () => {
277+
// Assume you are executing a cell that prints numbers 1-100.
278+
// When printing number 50, you click clear.
279+
// Cell output should now start printing output from 51 onwards, & not 1.
280+
await insertPythonCellAndWait(
281+
dedent`
282+
from IPython.display import display, clear_output
283+
import time
284+
print('foo')
285+
display('foo')
286+
time.sleep(2)
287+
clear_output(True)
288+
print('bar')
289+
display('bar')`,
290+
0
291+
);
292+
const cell = vscodeNotebook.activeNotebookEditor?.document.cells![0]!;
293+
294+
await executeActiveDocument();
295+
296+
// Wait for foo to be printed
297+
await waitForCondition(
298+
async () =>
299+
assertHasTextOutputInVSCode(cell, 'foo', 0, false) &&
300+
assertHasTextOutputInVSCode(cell, 'foo', 1, false),
301+
15_000,
302+
'Incorrect output'
303+
);
304+
305+
// Wait for bar to be printed
306+
await waitForCondition(
307+
async () =>
308+
assertHasTextOutputInVSCode(cell, 'bar', 0, false) &&
309+
assertHasTextOutputInVSCode(cell, 'bar', 1, false),
310+
15_000,
311+
'Incorrect output'
312+
);
313+
});
314+
test('Testing streamed output', async () => {
315+
// Assume you are executing a cell that prints numbers 1-100.
316+
// When printing number 50, you click clear.
317+
// Cell output should now start printing output from 51 onwards, & not 1.
318+
await insertPythonCellAndWait(
319+
dedent`
320+
print("Start")
321+
import time
322+
for i in range(5):
323+
time.sleep(0.5)
324+
print(i)
325+
326+
print("End")`,
327+
0
328+
);
329+
const cell = vscodeNotebook.activeNotebookEditor?.document.cells![0]!;
330+
331+
await executeActiveDocument();
332+
333+
await waitForCondition(
334+
async () =>
335+
assertHasTextOutputInVSCode(cell, 'Start', 0, false) &&
336+
assertHasTextOutputInVSCode(cell, '0', 0, false) &&
337+
assertHasTextOutputInVSCode(cell, '1', 0, false) &&
338+
assertHasTextOutputInVSCode(cell, '2', 0, false) &&
339+
assertHasTextOutputInVSCode(cell, '3', 0, false) &&
340+
assertHasTextOutputInVSCode(cell, '4', 0, false) &&
341+
assertHasTextOutputInVSCode(cell, 'End', 0, false),
342+
15_000,
343+
'Incorrect output'
344+
);
345+
});
267346
});

0 commit comments

Comments
 (0)