Skip to content

Commit a7afb26

Browse files
authored
Added notifyOnComplete parameter for KernelExecutor (#291)
* Added notifyOnComplete paramater for code execution enabling to send model notifications only when all code execution completed * Fixed missing metadata parameter for OutputExecutor * Fixed JSONObject initialization
1 parent bf4f3ab commit a7afb26

File tree

6 files changed

+40
-10
lines changed

6 files changed

+40
-10
lines changed

.vscode/settings.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,7 @@
1111
"[typescriptreact]": {
1212
"editor.defaultFormatter": "esbenp.prettier-vscode",
1313
},
14+
"githubPullRequests.ignoredPullRequestBranches": [
15+
"main"
16+
],
1417
}

packages/react/src/components/output/Output.tsx

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ export type IOutputProps = {
4040
showEditor: boolean;
4141
showKernelProgressBar?: boolean;
4242
toolbarPosition: 'up' | 'middle' | 'none';
43+
notifyOnComplete? : boolean;
4344
};
4445

4546
export const Output = (props: IOutputProps) => {
@@ -62,6 +63,7 @@ export const Output = (props: IOutputProps) => {
6263
showControl,
6364
showEditor,
6465
showKernelProgressBar = true,
66+
notifyOnComplete = false,
6567
id: sourceId,
6668
toolbarPosition,
6769
} = props;
@@ -121,7 +123,7 @@ export const Output = (props: IOutputProps) => {
121123
useEffect(() => {
122124
if (adapter) {
123125
if (autoRun) {
124-
adapter.execute(code);
126+
adapter.execute(code, notifyOnComplete);
125127
}
126128
}
127129
}, [adapter]);
@@ -141,12 +143,12 @@ export const Output = (props: IOutputProps) => {
141143
const executeRequest = outputStore.getExecuteRequest(sourceId);
142144
useEffect(() => {
143145
if (adapter && executeRequest && executeRequest === id) {
144-
adapter.execute(code);
146+
adapter.execute(code, notifyOnComplete);
145147
}
146148
}, [executeRequest, adapter]);
147149
useEffect(() => {
148150
if (adapter && executeTrigger > 0) {
149-
adapter.execute(code);
151+
adapter.execute(code, notifyOnComplete);
150152
}
151153
}, [executeTrigger]);
152154
useEffect(() => {
@@ -244,6 +246,7 @@ Output.defaultProps = {
244246
metadata: {},
245247
},
246248
],
249+
notifyOnComplete : false,
247250
toolbarPosition: 'up',
248251
} as Partial<IOutputProps>;
249252

packages/react/src/components/output/OutputAdapter.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
*/
66

77
import { IOutput } from '@jupyterlab/nbformat';
8+
import { JSONObject } from '@lumino/coreutils';
89
import { IOutputAreaModel, OutputArea, OutputAreaModel } from '@jupyterlab/outputarea';
910
import { IRenderMime, RenderMimeRegistry, standardRendererFactories } from '@jupyterlab/rendermime';
1011
import { rendererFactory as jsonRendererFactory } from '@jupyterlab/json-extension';
@@ -79,10 +80,11 @@ export class OutputAdapter {
7980
this.initKernel();
8081
}
8182

82-
public async execute(code: string) {
83+
public async execute(code: string, notifyOnComplete? : boolean) {
8384
if (this._kernel) {
8485
this.clear();
85-
const done = execute(this._id, code, this._outputArea, this._kernel);
86+
const metadata : JSONObject = {};
87+
const done = execute(this._id, code, this._outputArea, this._kernel, metadata, notifyOnComplete);
8688
await done;
8789
}
8890
}

packages/react/src/components/output/OutputExecutor.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ export async function execute(
1717
code: string,
1818
output: OutputArea,
1919
kernel: Kernel,
20-
metadata?: JSONObject
20+
metadata?: JSONObject,
21+
notifyOnComplete? : boolean
2122
): Promise<KernelMessage.IExecuteReplyMsg | undefined> {
2223
// Override the default for `stop_on_error`.
2324
let stopOnError = true;
@@ -33,6 +34,7 @@ export async function execute(
3334
{
3435
model: output.model,
3536
stopOnError,
37+
notifyOnComplete : notifyOnComplete
3638
}
3739
);
3840
const future = kernelExecutor!.future;

packages/react/src/jupyter/kernel/Kernel.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,7 @@ export class Kernel {
194194
stopOnError,
195195
storeHistory,
196196
allowStdin,
197+
notifyOnComplete = false
197198
}: {
198199
model?: IOutputAreaModel;
199200
iopubMessageHooks?: IOPubMessageHook[];
@@ -202,12 +203,14 @@ export class Kernel {
202203
stopOnError?: boolean;
203204
storeHistory?: boolean;
204205
allowStdin?: boolean;
206+
notifyOnComplete? : boolean
205207
} = {}
206208
): KernelExecutor | undefined {
207209
if (this._kernelConnection) {
208210
const kernelExecutor = new KernelExecutor({
209211
connection: this._kernelConnection,
210212
model,
213+
notifyOnComplete,
211214
});
212215
kernelExecutor.execute(code, {
213216
iopubMessageHooks,

packages/react/src/jupyter/kernel/KernelExecutor.ts

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,11 @@ export type IKernelExecutorOptions = {
4141
* Outputs model to populate with the execution results.
4242
*/
4343
model?: IOutputAreaModel;
44+
/**
45+
* Flag defining if notification about model changes
46+
* must only be made when execution complete
47+
*/
48+
notifyOnComplete? : boolean;
4449
}
4550

4651
export class KernelExecutor {
@@ -54,13 +59,15 @@ export class KernelExecutor {
5459
private _outputsChanged = new Signal<KernelExecutor, IOutput[]>(this);
5560
private _future?: JupyterKernel.IFuture<KernelMessage.IExecuteRequestMsg, KernelMessage.IExecuteReplyMsg>;
5661
private _shellMessageHooks = new Array<ShellMessageHook>();
62+
private _notifyOnComplete : boolean = false;
5763

58-
public constructor({ connection, model }: IKernelExecutorOptions) {
64+
public constructor({ connection, model, notifyOnComplete }: IKernelExecutorOptions) {
5965
this._executed = new PromiseDelegate<IOutputAreaModel>();
6066
this._kernelConnection = connection;
6167
this._model = model ?? new OutputAreaModel();
6268
this._outputs = [];
6369
this._kernelState = kernelsStore.getState();
70+
this._notifyOnComplete = !!notifyOnComplete;
6471
}
6572

6673
/**
@@ -118,6 +125,10 @@ export class KernelExecutor {
118125
// Wait for future to be done before resolving the exectud promise.
119126
this._future.done.then(() => {
120127
kernelsStore.getState().setExecutionPhase(this._kernelConnection.id, ExecutionPhase.completed);
128+
// We emit model changes only when execution completed
129+
if (this._notifyOnComplete) {
130+
this._modelChanged.emit(this._model);
131+
}
121132
this._executed.resolve(this._model);
122133
});
123134
return this._executed.promise;
@@ -205,13 +216,17 @@ export class KernelExecutor {
205216
this._outputs.push(message.content as IExecuteResult);
206217
this._outputsChanged.emit(this._outputs);
207218
this._model.add(output);
208-
this._modelChanged.emit(this._model);
219+
if (!this._notifyOnComplete) {
220+
this._modelChanged.emit(this._model);
221+
}
209222
break;
210223
case 'display_data':
211224
this._outputs.push(message.content as IDisplayData);
212225
this._outputsChanged.emit(this._outputs);
213226
this._model.add(output);
214-
this._modelChanged.emit(this._model);
227+
if (!this._notifyOnComplete) {
228+
this._modelChanged.emit(this._model);
229+
}
215230
break;
216231
case 'stream':
217232
case 'error':
@@ -232,7 +247,9 @@ export class KernelExecutor {
232247
this._outputsChanged.emit(this._outputs);
233248
// FIXME this needs more advanced analysis see OutputArea
234249
this._model.add(output);
235-
this._modelChanged.emit(this._model);
250+
if (!this._notifyOnComplete) {
251+
this._modelChanged.emit(this._model);
252+
}
236253
break;
237254
case 'status':
238255
const executionState = (message.content as any).execution_state as KernelMessage.Status;

0 commit comments

Comments
 (0)