Skip to content

Commit 94da334

Browse files
authored
Update cell output and metadata using Edit API (#13737)
1 parent 12de21d commit 94da334

25 files changed

+920
-963
lines changed

.vscode/launch.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@
143143
"--extensionTestsPath=${workspaceFolder}/out/test"
144144
],
145145
"env": {
146-
"VSC_PYTHON_CI_TEST_GREP": "Language Server:"
146+
"VSC_PYTHON_CI_TEST_GREP": "Language Server:"
147147
},
148148
"stopOnEntry": false,
149149
"sourceMaps": true,
@@ -166,6 +166,7 @@
166166
"env": {
167167
"VSC_PYTHON_CI_TEST_GREP": "", // Modify this to run a subset of the single workspace tests
168168
"VSC_PYTHON_CI_TEST_INVERT_GREP": "", // Initialize this to invert the grep (exclude tests with value defined in grep).
169+
"CI_PYTHON_PATH": "<PythonPath>", // Initialize this to invert the grep (exclude tests with value defined in grep).
169170

170171
"VSC_PYTHON_LOAD_EXPERIMENTS_FROM_FILE": "true",
171172
"TEST_FILES_SUFFIX": "ds.test"

src/client/common/utils/decorators.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -178,11 +178,11 @@ export function cache(expiryDurationMs: number) {
178178
* @param {string} [scopeName] Scope for the error message to be logged along with the error.
179179
* @returns void
180180
*/
181-
export function swallowExceptions(scopeName: string) {
181+
export function swallowExceptions(scopeName?: string) {
182182
// tslint:disable-next-line:no-any no-function-expression
183183
return function (_target: any, propertyName: string, descriptor: TypedPropertyDescriptor<any>) {
184184
const originalMethod = descriptor.value!;
185-
const errorMessage = `Python Extension (Error in ${scopeName}, method:${propertyName}):`;
185+
const errorMessage = `Python Extension (Error in ${scopeName || propertyName}, method:${propertyName}):`;
186186
// tslint:disable-next-line:no-any no-function-expression
187187
descriptor.value = function (...args: any[]) {
188188
try {

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

Lines changed: 182 additions & 114 deletions
Large diffs are not rendered by default.

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

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import {
1717
Uri
1818
} from 'vscode';
1919
import { ServerStatus } from '../../../../datascience-ui/interactive-common/mainState';
20-
import { IApplicationShell, ICommandManager } from '../../../common/application/types';
20+
import { IApplicationShell, ICommandManager, IVSCodeNotebook } from '../../../common/application/types';
2121
import { traceError } from '../../../common/logger';
2222
import { IDisposableRegistry } from '../../../common/types';
2323
import { createDeferred, Deferred } from '../../../common/utils/async';
@@ -86,7 +86,8 @@ export class Kernel implements IKernel {
8686
editorProvider: INotebookEditorProvider,
8787
private readonly kernelProvider: IKernelProvider,
8888
private readonly kernelSelectionUsage: IKernelSelectionUsage,
89-
appShell: IApplicationShell
89+
appShell: IApplicationShell,
90+
vscNotebook: IVSCodeNotebook
9091
) {
9192
this.kernelExecution = new KernelExecution(
9293
kernelProvider,
@@ -96,7 +97,8 @@ export class Kernel implements IKernel {
9697
contentProvider,
9798
editorProvider,
9899
kernelSelectionUsage,
99-
appShell
100+
appShell,
101+
vscNotebook
100102
);
101103
}
102104
public async executeCell(cell: NotebookCell): Promise<void> {
@@ -107,11 +109,11 @@ export class Kernel implements IKernel {
107109
await this.start({ disableUI: false, token: this.startCancellation.token });
108110
await this.kernelExecution.executeAllCells(document);
109111
}
110-
public cancelCell(cell: NotebookCell) {
112+
public async cancelCell(cell: NotebookCell) {
111113
this.startCancellation.cancel();
112-
this.kernelExecution.cancelCell(cell);
114+
await this.kernelExecution.cancelCell(cell);
113115
}
114-
public cancelAllCells(document: NotebookDocument) {
116+
public async cancelAllCells(document: NotebookDocument) {
115117
this.startCancellation.cancel();
116118
this.kernelExecution.cancelAllCells(document);
117119
}

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

Lines changed: 43 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
import { KernelMessage } from '@jupyterlab/services';
77
import { NotebookCell, NotebookCellRunState, NotebookDocument } from 'vscode';
8-
import { IApplicationShell, ICommandManager } from '../../../common/application/types';
8+
import { IApplicationShell, ICommandManager, IVSCodeNotebook } from '../../../common/application/types';
99
import { IDisposable } from '../../../common/types';
1010
import { noop } from '../../../common/utils/misc';
1111
import { IInterpreterService } from '../../../interpreter/contracts';
@@ -43,9 +43,16 @@ export class KernelExecution implements IDisposable {
4343
private readonly contentProvider: INotebookContentProvider,
4444
editorProvider: INotebookEditorProvider,
4545
readonly kernelSelectionUsage: IKernelSelectionUsage,
46-
readonly appShell: IApplicationShell
46+
readonly appShell: IApplicationShell,
47+
readonly vscNotebook: IVSCodeNotebook
4748
) {
48-
this.executionFactory = new CellExecutionFactory(this.contentProvider, errorHandler, editorProvider, appShell);
49+
this.executionFactory = new CellExecutionFactory(
50+
this.contentProvider,
51+
errorHandler,
52+
editorProvider,
53+
appShell,
54+
vscNotebook
55+
);
4956
}
5057

5158
@captureTelemetry(Telemetry.ExecuteNativeCell, undefined, true)
@@ -78,11 +85,17 @@ export class KernelExecution implements IDisposable {
7885
if (this.documentExecutions.has(document)) {
7986
return;
8087
}
88+
const editor = this.vscNotebook.notebookEditors.find((item) => item.document === document);
89+
if (!editor) {
90+
return;
91+
}
8192
const cancelTokenSource = new MultiCancellationTokenSource();
8293
this.documentExecutions.set(document, cancelTokenSource);
8394
const kernel = this.getKernel(document);
84-
document.metadata.runState = vscodeNotebookEnums.NotebookRunState.Running;
8595

96+
await editor.edit((edit) =>
97+
edit.replaceMetadata({ ...document.metadata, runState: vscodeNotebookEnums.NotebookRunState.Running })
98+
);
8699
const codeCellsToExecute = document.cells
87100
.filter((cell) => cell.cellKind === vscodeNotebookEnums.CellKind.Code)
88101
.filter((cell) => cell.document.getText().trim().length > 0)
@@ -98,35 +111,31 @@ export class KernelExecution implements IDisposable {
98111
);
99112

100113
try {
101-
let executingAPreviousCellHasFailed = false;
102-
await codeCellsToExecute.reduce(
103-
(previousPromise, cellToExecute) =>
104-
previousPromise.then((previousCellState) => {
105-
// If a previous cell has failed or execution cancelled, the get out.
106-
if (
107-
executingAPreviousCellHasFailed ||
108-
cancelTokenSource.token.isCancellationRequested ||
109-
previousCellState === vscodeNotebookEnums.NotebookCellRunState.Error
110-
) {
111-
executingAPreviousCellHasFailed = true;
112-
codeCellsToExecute.forEach((cell) => cell.cancel()); // Cancel pending cells.
113-
return;
114-
}
115-
const result = this.executeIndividualCell(kernel, cellToExecute);
116-
result.finally(() => this.cellExecutions.delete(cellToExecute.cell)).catch(noop);
117-
return result;
118-
}),
119-
Promise.resolve<NotebookCellRunState | undefined>(undefined)
120-
);
114+
for (const cellToExecute of codeCellsToExecute) {
115+
const result = this.executeIndividualCell(kernel, cellToExecute);
116+
result.finally(() => this.cellExecutions.delete(cellToExecute.cell)).catch(noop);
117+
const executionResult = await result;
118+
// If a cell has failed or execution cancelled, the get out.
119+
if (
120+
cancelTokenSource.token.isCancellationRequested ||
121+
executionResult === vscodeNotebookEnums.NotebookCellRunState.Error
122+
) {
123+
await Promise.all(codeCellsToExecute.map((cell) => cell.cancel())); // Cancel pending cells.
124+
break;
125+
}
126+
}
121127
} finally {
128+
await Promise.all(codeCellsToExecute.map((cell) => cell.cancel())); // Cancel pending cells.
122129
this.documentExecutions.delete(document);
123-
document.metadata.runState = vscodeNotebookEnums.NotebookRunState.Idle;
130+
await editor.edit((edit) =>
131+
edit.replaceMetadata({ ...document.metadata, runState: vscodeNotebookEnums.NotebookRunState.Idle })
132+
);
124133
}
125134
}
126135

127-
public cancelCell(cell: NotebookCell): void {
136+
public async cancelCell(cell: NotebookCell) {
128137
if (this.cellExecutions.get(cell)) {
129-
this.cellExecutions.get(cell)!.cancel();
138+
await this.cellExecutions.get(cell)!.cancel();
130139
}
131140
}
132141

@@ -160,11 +169,14 @@ export class KernelExecution implements IDisposable {
160169
return kernel;
161170
}
162171

163-
private onIoPubMessage(document: NotebookDocument, msg: KernelMessage.IIOPubMessage) {
172+
private async onIoPubMessage(document: NotebookDocument, msg: KernelMessage.IIOPubMessage) {
164173
// tslint:disable-next-line:no-require-imports
165174
const jupyterLab = require('@jupyterlab/services') as typeof import('@jupyterlab/services');
166-
if (jupyterLab.KernelMessage.isUpdateDisplayDataMsg(msg) && handleUpdateDisplayDataMessage(msg, document)) {
167-
this.contentProvider.notifyChangesToDocument(document);
175+
const editor = this.vscNotebook.notebookEditors.find((e) => e.document === document);
176+
if (jupyterLab.KernelMessage.isUpdateDisplayDataMsg(msg) && editor) {
177+
if (await handleUpdateDisplayDataMessage(msg, editor)) {
178+
this.contentProvider.notifyChangesToDocument(document);
179+
}
168180
}
169181
}
170182

@@ -195,7 +207,7 @@ export class KernelExecution implements IDisposable {
195207
);
196208

197209
// Start execution
198-
cellExecution.start(kernelPromise, this.notebook);
210+
await cellExecution.start(kernelPromise, this.notebook);
199211

200212
// The result promise will resolve when complete.
201213
try {

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

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import * as fastDeepEqual from 'fast-deep-equal';
77
import { inject, injectable } from 'inversify';
88
import { Uri } from 'vscode';
9-
import { IApplicationShell, ICommandManager } from '../../../common/application/types';
9+
import { IApplicationShell, ICommandManager, IVSCodeNotebook } from '../../../common/application/types';
1010
import { traceInfo, traceWarning } from '../../../common/logger';
1111
import { IAsyncDisposableRegistry, IConfigurationService, IDisposableRegistry } from '../../../common/types';
1212
import { IInterpreterService } from '../../../interpreter/contracts';
@@ -30,7 +30,8 @@ export class KernelProvider implements IKernelProvider {
3030
@inject(INotebookContentProvider) private readonly contentProvider: INotebookContentProvider,
3131
@inject(INotebookEditorProvider) private readonly editorProvider: INotebookEditorProvider,
3232
@inject(KernelSelector) private readonly kernelSelectionUsage: IKernelSelectionUsage,
33-
@inject(IApplicationShell) private readonly appShell: IApplicationShell
33+
@inject(IApplicationShell) private readonly appShell: IApplicationShell,
34+
@inject(IVSCodeNotebook) private readonly vscNotebook: IVSCodeNotebook
3435
) {}
3536
public get(uri: Uri): IKernel | undefined {
3637
return this.kernelsByUri.get(uri.toString())?.kernel;
@@ -57,7 +58,8 @@ export class KernelProvider implements IKernelProvider {
5758
this.editorProvider,
5859
this,
5960
this.kernelSelectionUsage,
60-
this.appShell
61+
this.appShell,
62+
this.vscNotebook
6163
);
6264
this.asyncDisposables.push(kernel);
6365
this.kernelsByUri.set(uri.toString(), { options, kernel });

src/client/datascience/notebook/contentProvider.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,8 @@ export class NotebookContentProvider implements INotebookContentProvider {
4545
@inject(NotebookEditorCompatibilitySupport)
4646
private readonly compatibilitySupport: NotebookEditorCompatibilitySupport
4747
) {}
48-
public notifyChangesToDocument(document: NotebookDocument) {
49-
this.notebookChanged.fire({ document });
48+
public notifyChangesToDocument(_document: NotebookDocument) {
49+
// this.notebookChanged.fire({ document });
5050
}
5151
public async resolveNotebook(_document: NotebookDocument, _webview: NotebookCommunication): Promise<void> {
5252
// Later

0 commit comments

Comments
 (0)