Skip to content

Commit 82d52fc

Browse files
sok82Sergey Kadnikov
andauthored
Handling uncaught runtime error in promise when executing code in output (#302)
* 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 * Fixed uncaught runtime exception in promise when code execution error occurs in Output --------- Co-authored-by: Sergey Kadnikov <skadnikov@seeneco.ru>
1 parent a5e1157 commit 82d52fc

File tree

3 files changed

+48
-20
lines changed

3 files changed

+48
-20
lines changed

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

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
/* eslint-disable prettier/prettier */
12
/*
23
* Copyright (c) 2021-2023 Datalayer, Inc.
34
*
@@ -40,7 +41,8 @@ export type IOutputProps = {
4041
showEditor: boolean;
4142
showKernelProgressBar?: boolean;
4243
toolbarPosition: 'up' | 'middle' | 'none';
43-
notifyOnComplete? : boolean;
44+
notifyOnComplete?: boolean;
45+
onCodeExecutionError?: (err : any) => void;
4446
};
4547

4648
export const Output = (props: IOutputProps) => {
@@ -64,6 +66,7 @@ export const Output = (props: IOutputProps) => {
6466
showEditor,
6567
showKernelProgressBar = true,
6668
notifyOnComplete = false,
69+
onCodeExecutionError,
6770
id: sourceId,
6871
toolbarPosition,
6972
} = props;
@@ -123,7 +126,7 @@ export const Output = (props: IOutputProps) => {
123126
useEffect(() => {
124127
if (adapter) {
125128
if (autoRun) {
126-
adapter.execute(code, notifyOnComplete);
129+
adapter.execute(code, notifyOnComplete,onCodeExecutionError);
127130
}
128131
}
129132
}, [adapter]);
@@ -143,12 +146,12 @@ export const Output = (props: IOutputProps) => {
143146
const executeRequest = outputStore.getExecuteRequest(sourceId);
144147
useEffect(() => {
145148
if (adapter && executeRequest && executeRequest === id) {
146-
adapter.execute(code, notifyOnComplete);
149+
adapter.execute(code, notifyOnComplete,onCodeExecutionError);
147150
}
148151
}, [executeRequest, adapter]);
149152
useEffect(() => {
150153
if (adapter && executeTrigger > 0) {
151-
adapter.execute(code, notifyOnComplete);
154+
adapter.execute(code, notifyOnComplete,onCodeExecutionError);
152155
}
153156
}, [executeTrigger]);
154157
useEffect(() => {

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

Lines changed: 35 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,22 @@
66

77
import { IOutput } from '@jupyterlab/nbformat';
88
import { JSONObject } from '@lumino/coreutils';
9-
import { IOutputAreaModel, OutputArea, OutputAreaModel } from '@jupyterlab/outputarea';
10-
import { IRenderMime, RenderMimeRegistry, standardRendererFactories } from '@jupyterlab/rendermime';
9+
import {
10+
IOutputAreaModel,
11+
OutputArea,
12+
OutputAreaModel,
13+
} from '@jupyterlab/outputarea';
14+
import {
15+
IRenderMime,
16+
RenderMimeRegistry,
17+
standardRendererFactories,
18+
} from '@jupyterlab/rendermime';
1119
import { rendererFactory as jsonRendererFactory } from '@jupyterlab/json-extension';
1220
import { rendererFactory as javascriptRendererFactory } from '@jupyterlab/javascript-extension';
13-
import { WIDGET_MIMETYPE, WidgetRenderer } from '@jupyter-widgets/html-manager/lib/output_renderers';
21+
import {
22+
WIDGET_MIMETYPE,
23+
WidgetRenderer,
24+
} from '@jupyter-widgets/html-manager/lib/output_renderers';
1425
import { requireLoader as loader } from '../../jupyter/ipywidgets/libembed-amd';
1526
import { ClassicWidgetManager } from '../../jupyter/ipywidgets/classic/manager';
1627
import { Kernel } from '../../jupyter/kernel/Kernel';
@@ -80,12 +91,29 @@ export class OutputAdapter {
8091
this.initKernel();
8192
}
8293

83-
public async execute(code: string, notifyOnComplete? : boolean) {
94+
public async execute(
95+
code: string,
96+
notifyOnComplete?: boolean,
97+
onCodeExecutionError?: (err: any) => void
98+
) {
8499
if (this._kernel) {
85100
this.clear();
86-
const metadata : JSONObject = {};
87-
const done = execute(this._id, code, this._outputArea, this._kernel, metadata, notifyOnComplete);
88-
await done;
101+
const metadata: JSONObject = {};
102+
const done = execute(
103+
this._id,
104+
code,
105+
this._outputArea,
106+
this._kernel,
107+
metadata,
108+
notifyOnComplete
109+
);
110+
if (onCodeExecutionError) {
111+
await done.catch(onCodeExecutionError);
112+
} else {
113+
await done.catch(err => {
114+
console.error(err);
115+
});
116+
}
89117
}
90118
}
91119

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

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ export async function execute(
1818
output: OutputArea,
1919
kernel: Kernel,
2020
metadata?: JSONObject,
21-
notifyOnComplete? : boolean
21+
notifyOnComplete?: boolean
2222
): Promise<KernelMessage.IExecuteReplyMsg | undefined> {
2323
// Override the default for `stop_on_error`.
2424
let stopOnError = true;
@@ -29,14 +29,11 @@ export async function execute(
2929
) {
3030
stopOnError = false;
3131
}
32-
const kernelExecutor = kernel.execute(
33-
code,
34-
{
35-
model: output.model,
36-
stopOnError,
37-
notifyOnComplete : notifyOnComplete
38-
}
39-
);
32+
const kernelExecutor = kernel.execute(code, {
33+
model: output.model,
34+
stopOnError,
35+
notifyOnComplete: notifyOnComplete,
36+
});
4037
const future = kernelExecutor!.future;
4138
// TODO fix in upstream jupyterlab if possible...
4239
(output as any)._onIOPub = future!.onIOPub;

0 commit comments

Comments
 (0)