Skip to content

Commit 1626cf9

Browse files
authored
Update other cells in cell execution (#14240)
* Update other cells in cell execution * Add tests
1 parent 7e1d105 commit 1626cf9

File tree

10 files changed

+83
-82
lines changed

10 files changed

+83
-82
lines changed

src/client/datascience/baseJupyterSession.ts

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,9 +68,6 @@ export abstract class BaseJupyterSession implements IJupyterSession {
6868
public get isConnected(): boolean {
6969
return this.connected;
7070
}
71-
public get onIoPubMessage() {
72-
return this.ioPubEventEmitter.event;
73-
}
7471
protected onStatusChangedEvent: EventEmitter<ServerStatus> = new EventEmitter<ServerStatus>();
7572
protected statusHandler: Slot<ISessionWithSocket, Kernel.Status>;
7673
protected connected: boolean = false;

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

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,11 @@ import { noop } from '../../../common/utils/misc';
1818
import { StopWatch } from '../../../common/utils/stopWatch';
1919
import { sendTelemetryEvent } from '../../../telemetry';
2020
import { Telemetry } from '../../constants';
21-
import { updateCellExecutionCount, updateCellWithErrorStatus } from '../../notebook/helpers/executionHelpers';
21+
import {
22+
handleUpdateDisplayDataMessage,
23+
updateCellExecutionCount,
24+
updateCellWithErrorStatus
25+
} from '../../notebook/helpers/executionHelpers';
2226
import {
2327
cellOutputToVSCCellOutput,
2428
clearCellForExecution,
@@ -365,12 +369,12 @@ export class CellExecution {
365369
await this.handleStreamMessage(msg as KernelMessage.IStreamMsg, clearState);
366370
} else if (jupyterLab.KernelMessage.isDisplayDataMsg(msg)) {
367371
await this.handleDisplayData(msg as KernelMessage.IDisplayDataMsg, clearState);
372+
} else if (jupyterLab.KernelMessage.isUpdateDisplayDataMsg(msg)) {
373+
await handleUpdateDisplayDataMessage(msg, this.editor);
368374
} else if (jupyterLab.KernelMessage.isClearOutputMsg(msg)) {
369375
await this.handleClearOutput(msg as KernelMessage.IClearOutputMsg, clearState);
370376
} else if (jupyterLab.KernelMessage.isErrorMsg(msg)) {
371377
await this.handleError(msg as KernelMessage.IErrorMsg, clearState);
372-
} else if (jupyterLab.KernelMessage.isUpdateDisplayDataMsg(msg)) {
373-
// Noop.
374378
} else if (jupyterLab.KernelMessage.isCommOpenMsg(msg)) {
375379
// Noop.
376380
} else if (jupyterLab.KernelMessage.isCommMsgMsg(msg)) {

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

Lines changed: 3 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,13 @@
33

44
'use strict';
55

6-
import { KernelMessage } from '@jupyterlab/services';
76
import { NotebookCell, NotebookCellRunState, NotebookDocument } from 'vscode';
87
import { IApplicationShell, ICommandManager, IVSCodeNotebook } from '../../../common/application/types';
98
import { IDisposable } from '../../../common/types';
109
import { noop } from '../../../common/utils/misc';
1110
import { IInterpreterService } from '../../../interpreter/contracts';
1211
import { captureTelemetry } from '../../../telemetry';
1312
import { Commands, Telemetry, VSCodeNativeTelemetry } from '../../constants';
14-
import { handleUpdateDisplayDataMessage } from '../../notebook/helpers/executionHelpers';
1513
import { MultiCancellationTokenSource } from '../../notebook/helpers/multiCancellationToken';
1614
import { IDataScienceErrorHandler, INotebook, INotebookEditorProvider } from '../../types';
1715
import { CellExecution, CellExecutionFactory } from './cellExecution';
@@ -161,15 +159,6 @@ export class KernelExecution implements IDisposable {
161159
return kernel;
162160
}
163161

164-
private async onIoPubMessage(document: NotebookDocument, msg: KernelMessage.IIOPubMessage) {
165-
// tslint:disable-next-line:no-require-imports
166-
const jupyterLab = require('@jupyterlab/services') as typeof import('@jupyterlab/services');
167-
const editor = this.vscNotebook.notebookEditors.find((e) => e.document === document);
168-
if (jupyterLab.KernelMessage.isUpdateDisplayDataMsg(msg) && editor) {
169-
await handleUpdateDisplayDataMessage(msg, editor);
170-
}
171-
}
172-
173162
private async executeIndividualCell(
174163
kernelPromise: Promise<IKernel>,
175164
cellExecution: CellExecution
@@ -178,20 +167,9 @@ export class KernelExecution implements IDisposable {
178167
throw new Error('No notebook object');
179168
}
180169

181-
// Register for IO pub messages
182-
const ioRegistration = this.notebook.session.onIoPubMessage(
183-
this.onIoPubMessage.bind(this, cellExecution.cell.notebook)
184-
);
185170
cellExecution.token.onCancellationRequested(
186-
() => {
187-
ioRegistration.dispose();
188-
if (cellExecution.completed) {
189-
return;
190-
}
191-
192-
// Interrupt kernel only if we need to cancel a cell execution.
193-
this.commandManager.executeCommand(Commands.NotebookEditorInterruptKernel).then(noop, noop);
194-
},
171+
// Interrupt kernel only if we need to cancel a cell execution.
172+
() => this.commandManager.executeCommand(Commands.NotebookEditorInterruptKernel).then(noop, noop),
195173
this,
196174
this.disposables
197175
);
@@ -200,11 +178,7 @@ export class KernelExecution implements IDisposable {
200178
await cellExecution.start(kernelPromise, this.notebook);
201179

202180
// The result promise will resolve when complete.
203-
try {
204-
return await cellExecution.result;
205-
} finally {
206-
ioRegistration.dispose();
207-
}
181+
return cellExecution.result;
208182
}
209183

210184
private async validateKernel(document: NotebookDocument): Promise<void> {

src/client/datascience/types.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -320,7 +320,6 @@ export interface IJupyterPasswordConnect {
320320
export const IJupyterSession = Symbol('IJupyterSession');
321321
export interface IJupyterSession extends IAsyncDisposable {
322322
onSessionStatusChanged: Event<ServerStatus>;
323-
onIoPubMessage: Event<KernelMessage.IIOPubMessage>;
324323
readonly status: ServerStatus;
325324
readonly workingDirectory: string;
326325
readonly kernelSocket: Observable<KernelSocketInformation | undefined>;

src/test/datascience/mockJupyterSession.ts

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,6 @@ export class MockJupyterSession implements IJupyterSession {
2525
private dict: Record<string, ICell>;
2626
private restartedEvent: EventEmitter<void> = new EventEmitter<void>();
2727
private onStatusChangedEvent: EventEmitter<ServerStatus> = new EventEmitter<ServerStatus>();
28-
private onIoPubMessageEvent: EventEmitter<KernelMessage.IIOPubMessage> = new EventEmitter<
29-
KernelMessage.IIOPubMessage
30-
>();
3128
private timedelay: number;
3229
private executionCount: number = 0;
3330
private outstandingRequestTokenSources: CancellationTokenSource[] = [];
@@ -58,10 +55,6 @@ export class MockJupyterSession implements IJupyterSession {
5855
}
5956
return this.onStatusChangedEvent.event;
6057
}
61-
public get onIoPubMessage(): Event<KernelMessage.IIOPubMessage> {
62-
return this.onIoPubMessageEvent.event;
63-
}
64-
6558
public get status(): ServerStatus {
6659
return this._status;
6760
}

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

Lines changed: 61 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ import {
2525
deleteAllCellsAndWait,
2626
executeActiveDocument,
2727
executeCell,
28-
insertPythonCellAndWait,
28+
insertPythonCell,
2929
startJupyter,
3030
trustAllNotebooks
3131
} from './helper';
@@ -56,7 +56,7 @@ suite('DataScience - VSCode Notebook - (Execution) (slow)', function () {
5656
setup(deleteAllCellsAndWait);
5757
suiteTeardown(() => closeNotebooksAndCleanUpAfterTests(disposables));
5858
test('Execute cell using VSCode Kernel', async () => {
59-
await insertPythonCellAndWait('print("Hello World")');
59+
await insertPythonCell('print("Hello World")');
6060
const cell = vscodeNotebook.activeNotebookEditor?.document.cells![0]!;
6161

6262
await executeCell(cell);
@@ -69,7 +69,7 @@ suite('DataScience - VSCode Notebook - (Execution) (slow)', function () {
6969
);
7070
});
7171
test('Executed events are triggered', async () => {
72-
await insertPythonCellAndWait('print("Hello World")');
72+
await insertPythonCell('print("Hello World")');
7373
const cell = vscodeNotebook.activeNotebookEditor?.document.cells![0]!;
7474

7575
const executed = createEventHandler(editorProvider.activeEditor!, 'executed', disposables);
@@ -87,7 +87,7 @@ suite('DataScience - VSCode Notebook - (Execution) (slow)', function () {
8787
await codeExecuted.assertFired(1_000);
8888
});
8989
test('Empty cell will not get executed', async () => {
90-
await insertPythonCellAndWait('');
90+
await insertPythonCell('');
9191
const cell = vscodeNotebook.activeNotebookEditor?.document.cells![0]!;
9292
await executeCell(cell);
9393

@@ -96,8 +96,8 @@ suite('DataScience - VSCode Notebook - (Execution) (slow)', function () {
9696
assert.isUndefined(cell?.metadata.runState);
9797
});
9898
test('Empty cells will not get executed when running whole document', async () => {
99-
await insertPythonCellAndWait('');
100-
await insertPythonCellAndWait('print("Hello World")');
99+
await insertPythonCell('');
100+
await insertPythonCell('print("Hello World")');
101101
const cells = vscodeNotebook.activeNotebookEditor?.document.cells!;
102102

103103
await executeActiveDocument();
@@ -111,7 +111,7 @@ suite('DataScience - VSCode Notebook - (Execution) (slow)', function () {
111111
assert.isUndefined(cells[0].metadata.runState);
112112
});
113113
test('Verify Cell output, execution count and status', async () => {
114-
await insertPythonCellAndWait('print("Hello World")');
114+
await insertPythonCell('print("Hello World")');
115115
const cell = vscodeNotebook.activeNotebookEditor?.document.cells![0]!;
116116

117117
await executeActiveDocument();
@@ -130,8 +130,8 @@ suite('DataScience - VSCode Notebook - (Execution) (slow)', function () {
130130
assert.ok(cell.metadata.executionOrder, 'Execution count should be > 0');
131131
});
132132
test('Verify multiple cells get executed', async () => {
133-
await insertPythonCellAndWait('print("Foo Bar")');
134-
await insertPythonCellAndWait('print("Hello World")');
133+
await insertPythonCell('print("Foo Bar")');
134+
await insertPythonCell('print("Hello World")');
135135
const cells = vscodeNotebook.activeNotebookEditor?.document.cells!;
136136

137137
await executeActiveDocument();
@@ -153,7 +153,7 @@ suite('DataScience - VSCode Notebook - (Execution) (slow)', function () {
153153
assert.equal(cells[1].metadata.executionOrder! - 1, cells[0].metadata.executionOrder!);
154154
});
155155
test('Verify metadata for successfully executed cell', async () => {
156-
await insertPythonCellAndWait('print("Foo Bar")');
156+
await insertPythonCell('print("Foo Bar")');
157157
const cell = vscodeNotebook.activeNotebookEditor?.document.cells![0]!;
158158

159159
await executeActiveDocument();
@@ -172,7 +172,7 @@ suite('DataScience - VSCode Notebook - (Execution) (slow)', function () {
172172
assert.equal(cell.metadata.statusMessage, '', 'Incorrect Status message');
173173
});
174174
test('Verify output & metadata for executed cell with errors', async () => {
175-
await insertPythonCellAndWait('print(abcd)');
175+
await insertPythonCell('print(abcd)');
176176
const cell = vscodeNotebook.activeNotebookEditor?.document.cells![0]!;
177177

178178
await executeActiveDocument();
@@ -198,9 +198,9 @@ suite('DataScience - VSCode Notebook - (Execution) (slow)', function () {
198198
assert.include(cell.metadata.statusMessage!, 'abcd', 'Must contain error message');
199199
});
200200
test('Updating display data', async () => {
201-
await insertPythonCellAndWait('from IPython.display import Markdown\n');
202-
await insertPythonCellAndWait('dh = display(display_id=True)\n');
203-
await insertPythonCellAndWait('dh.update(Markdown("foo"))\n');
201+
await insertPythonCell('from IPython.display import Markdown\n');
202+
await insertPythonCell('dh = display(display_id=True)\n');
203+
await insertPythonCell('dh.update(Markdown("foo"))\n');
204204
const displayCell = vscodeNotebook.activeNotebookEditor?.document.cells![1]!;
205205
const updateCell = vscodeNotebook.activeNotebookEditor?.document.cells![2]!;
206206

@@ -225,7 +225,7 @@ suite('DataScience - VSCode Notebook - (Execution) (slow)', function () {
225225
// Assume you are executing a cell that prints numbers 1-100.
226226
// When printing number 50, you click clear.
227227
// Cell output should now start printing output from 51 onwards, & not 1.
228-
await insertPythonCellAndWait(
228+
await insertPythonCell(
229229
dedent`
230230
print("Start")
231231
import time
@@ -277,7 +277,7 @@ suite('DataScience - VSCode Notebook - (Execution) (slow)', function () {
277277
// Assume you are executing a cell that prints numbers 1-100.
278278
// When printing number 50, you click clear.
279279
// Cell output should now start printing output from 51 onwards, & not 1.
280-
await insertPythonCellAndWait(
280+
await insertPythonCell(
281281
dedent`
282282
from IPython.display import display, clear_output
283283
import time
@@ -315,7 +315,7 @@ suite('DataScience - VSCode Notebook - (Execution) (slow)', function () {
315315
// Assume you are executing a cell that prints numbers 1-100.
316316
// When printing number 50, you click clear.
317317
// Cell output should now start printing output from 51 onwards, & not 1.
318-
await insertPythonCellAndWait(
318+
await insertPythonCell(
319319
dedent`
320320
print("Start")
321321
import time
@@ -344,14 +344,14 @@ suite('DataScience - VSCode Notebook - (Execution) (slow)', function () {
344344
);
345345
});
346346
test('Verify escaping of output', async () => {
347-
await insertPythonCellAndWait('1');
348-
await insertPythonCellAndWait(dedent`
347+
await insertPythonCell('1');
348+
await insertPythonCell(dedent`
349349
a="<a href=f>"
350350
a`);
351-
await insertPythonCellAndWait(dedent`
351+
await insertPythonCell(dedent`
352352
a="<a href=f>"
353353
print(a)`);
354-
await insertPythonCellAndWait('raise Exception("<whatever>")');
354+
await insertPythonCell('raise Exception("<whatever>")');
355355
const cells = vscodeNotebook.activeNotebookEditor?.document.cells!;
356356

357357
await executeActiveDocument();
@@ -391,4 +391,44 @@ suite('DataScience - VSCode Notebook - (Execution) (slow)', function () {
391391
assert.isNotEmpty(errorOutput.traceback, 'Incorrect traceback');
392392
assert.include(errorOutput.traceback.join(''), '<whatever>');
393393
});
394+
test('Verify display updates', async () => {
395+
await insertPythonCell('from IPython.display import Markdown', 0);
396+
await insertPythonCell('dh = display(Markdown("foo"), display_id=True)', 1);
397+
let cells = vscodeNotebook.activeNotebookEditor?.document.cells!;
398+
399+
await executeActiveDocument();
400+
await waitForCondition(
401+
async () => assertHasExecutionCompletedSuccessfully(cells[1]),
402+
15_000,
403+
'Cell did not get executed'
404+
);
405+
406+
assert.equal(cells[0].outputs.length, 0, 'Incorrect number of output');
407+
assert.equal(cells[1].outputs.length, 1, 'Incorrect number of output');
408+
assert.equal(cells[1].outputs[0].outputKind, vscodeNotebookEnums.CellOutputKind.Rich, 'Incorrect output type');
409+
assert.equal((cells[1].outputs[0] as CellDisplayOutput).data['text/markdown'], 'foo', 'Incorrect output value');
410+
const displayId = (cells[1].outputs[0] as CellDisplayOutput).metadata?.custom?.transient?.display_id;
411+
assert.ok(displayId, 'Display id not present in metadata');
412+
413+
await insertPythonCell(
414+
dedent`
415+
dh.update(Markdown("bar"))
416+
print('hello')`,
417+
2
418+
);
419+
await executeActiveDocument();
420+
cells = vscodeNotebook.activeNotebookEditor?.document.cells!;
421+
await waitForCondition(
422+
async () => assertHasExecutionCompletedSuccessfully(cells[2]),
423+
15_000,
424+
'Cell did not get executed'
425+
);
426+
427+
assert.equal(cells[0].outputs.length, 0, 'Incorrect number of output');
428+
assert.equal(cells[1].outputs.length, 1, 'Incorrect number of output');
429+
assert.equal(cells[2].outputs.length, 1, 'Incorrect number of output');
430+
assert.equal(cells[1].outputs[0].outputKind, vscodeNotebookEnums.CellOutputKind.Rich, 'Incorrect output type');
431+
assert.equal((cells[1].outputs[0] as CellDisplayOutput).data['text/markdown'], 'bar', 'Incorrect output value');
432+
assertHasTextOutputInVSCode(cells[2], 'hello', 0, false);
433+
});
394434
});

src/test/datascience/notebook/helper.ts

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -90,12 +90,6 @@ export async function insertPythonCell(source: string, index?: number) {
9090
])
9191
);
9292
}
93-
export async function insertPythonCellAndWait(source: string, index?: number) {
94-
await insertPythonCell(source, index);
95-
}
96-
export async function insertMarkdownCellAndWait(source: string) {
97-
await insertMarkdownCell(source);
98-
}
9993
export async function deleteCell(index: number = 0) {
10094
const { vscodeNotebook } = await getServices();
10195
const activeEditor = vscodeNotebook.activeNotebookEditor;

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import {
2222
closeNotebooks,
2323
closeNotebooksAndCleanUpAfterTests,
2424
executeActiveDocument,
25-
insertPythonCellAndWait,
25+
insertPythonCell,
2626
startJupyter,
2727
trustAllNotebooks,
2828
waitForTextOutputInVSCode
@@ -82,7 +82,7 @@ suite('DataScience - VSCode Notebook - Restart/Interrupt/Cancel/Errors (slow)',
8282
});
8383

8484
test('Cancelling token will cancel cell execution', async () => {
85-
await insertPythonCellAndWait('import time\nfor i in range(10000):\n print(i)\n time.sleep(0.1)', 0);
85+
await insertPythonCell('import time\nfor i in range(10000):\n print(i)\n time.sleep(0.1)', 0);
8686
const cell = vscEditor.document.cells[0];
8787
const appShell = api.serviceContainer.get<IApplicationShell>(IApplicationShell);
8888
const showInformationMessage = sinon.stub(appShell, 'showInformationMessage');
@@ -116,7 +116,7 @@ suite('DataScience - VSCode Notebook - Restart/Interrupt/Cancel/Errors (slow)',
116116
}
117117
});
118118
test('Restarting kernel will cancel cell execution & we can re-run a cell', async () => {
119-
await insertPythonCellAndWait('import time\nfor i in range(10000):\n print(i)\n time.sleep(0.1)', 0);
119+
await insertPythonCell('import time\nfor i in range(10000):\n print(i)\n time.sleep(0.1)', 0);
120120
const cell = vscEditor.document.cells[0];
121121

122122
await executeActiveDocument();

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import {
1919
canRunTests,
2020
closeNotebooksAndCleanUpAfterTests,
2121
createTemporaryNotebook,
22-
insertMarkdownCellAndWait,
22+
insertMarkdownCell,
2323
trustAllNotebooks
2424
} from './helper';
2525

@@ -147,7 +147,7 @@ suite('DataScience - VSCode Notebook (Editor Provider)', function () {
147147
const notebookClosed = createEventHandler(editorProvider, 'onDidCloseNotebookEditor', disposables);
148148

149149
const notebookEditor = await editorProvider.open(testIPynb);
150-
await insertMarkdownCellAndWait('1'); // Make the file dirty (so it gets pinned).
150+
await insertMarkdownCell('1'); // Make the file dirty (so it gets pinned).
151151
await notebookOpened.assertFired();
152152
await activeNotebookChanged.assertFired();
153153
assert.equal(activeNotebookChanged.first, notebookEditor);
@@ -194,7 +194,7 @@ suite('DataScience - VSCode Notebook (Editor Provider)', function () {
194194
const notebookClosed = createEventHandler(editorProvider, 'onDidCloseNotebookEditor', disposables);
195195

196196
const editor1 = await editorProvider.open(testIPynb);
197-
await insertMarkdownCellAndWait('1'); // Make the file dirty (so it gets pinned).
197+
await insertMarkdownCell('1'); // Make the file dirty (so it gets pinned).
198198
await notebookOpened.assertFired();
199199
await activeNotebookChanged.assertFired();
200200
assert.equal(activeNotebookChanged.first, editor1);
@@ -203,7 +203,7 @@ suite('DataScience - VSCode Notebook (Editor Provider)', function () {
203203
// Open another notebook.
204204
const testIPynb2 = Uri.file(await createTemporaryNotebook(templateIPynb, disposables));
205205
const editor2 = await editorProvider.open(testIPynb2);
206-
await insertMarkdownCellAndWait('1'); // Make the file dirty (so it gets pinned).
206+
await insertMarkdownCell('1'); // Make the file dirty (so it gets pinned).
207207

208208
await notebookOpened.assertFiredExactly(2);
209209
await activeNotebookChanged.assertFiredAtLeast(2);

0 commit comments

Comments
 (0)