Skip to content

Commit 267bf07

Browse files
authored
On Kernel Creation (#323)
* fix: headless * fix: viewer * example: on kernel creation * fix: html * chore: pyodide kernels * chore: notebook adapter to use lite
1 parent b1402bc commit 267bf07

23 files changed

+629
-111
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,5 +172,6 @@ packages/react/.vscode/launch.json
172172
!.storybook
173173
!.vscode
174174
!.licenserc.yaml
175-
!packages/react/jupyter_react/static/README.md
175+
!dev/notebooks/.datalayer
176176
!docs/static/img
177+
!packages/react/jupyter_react/static/README.md

dev/config/jupyter_server_config.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,14 +76,16 @@
7676
}
7777

7878
#################
79-
# Content
79+
# Contents
8080
#################
8181

82-
# c.FileContentsManager.delete_to_trash = False
8382
content_dir = os.path.dirname(os.path.realpath(__file__)) + '/../notebooks'
8483
c.ServerApp.root_dir = content_dir
8584
c.ServerApp.preferred_dir = content_dir
8685

86+
# c.FileContentsManager.delete_to_trash = False
87+
c.ContentsManager.allow_hidden = True
88+
8789
#################
8890
# URLs
8991
#################

dev/notebooks/.datalayer/ping.ipynb

Lines changed: 185 additions & 0 deletions
Large diffs are not rendered by default.

packages/react/public/index-local.html

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,14 @@
1515
"jupyterServerToken": "60c1661cc408f978c309d04157af55c9588ff9557c9380e4fb50785750703da6",
1616
"runUrl": "https://oss.datalayer.run",
1717
"token": "",
18-
"cpuEnvironment": "python-simple-env",
19-
"gpuEnvironment": "pytorch-cuda-env"
18+
"cpuEnvironment": "python-cpu-env",
19+
"gpuEnvironment": "pytorch-cuda-env",
20+
"credits": 1
2021
}
2122
</script>
2223
<script id="jupyter-config-data" type="application/json">
2324
{
25+
"appName": "Jupyter React",
2426
"baseUrl": "http://localhost:8686/api/jupyter-server",
2527
"wsUrl": "ws://localhost:8686/api/jupyter-server",
2628
"token": "60c1661cc408f978c309d04157af55c9588ff9557c9380e4fb50785750703da6",

packages/react/public/index.html

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,14 @@
1515
"jupyterServerToken": "60c1661cc408f978c309d04157af55c9588ff9557c9380e4fb50785750703da6",
1616
"runUrl": "https://prod1.datalayer.run",
1717
"token": "",
18-
"cpuEnvironment": "python-simple-env",
18+
"cpuEnvironment": "python-cpu-env",
1919
"gpuEnvironment": "pytorch-cuda-env",
2020
"credits": 1
2121
}
2222
</script>
2323
<script id="jupyter-config-data" type="application/json">
2424
{
25+
"appName": "Jupyter React",
2526
"baseUrl": "https://oss.datalayer.run/api/jupyter-server",
2627
"wsUrl": "wss://oss.datalayer.run/api/jupyter-server",
2728
"token": "60c1661cc408f978c309d04157af55c9588ff9557c9380e4fb50785750703da6",

packages/react/src/components/cell/CellAdapter.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,7 @@ export class CellAdapter {
255255
this._sessionContext.kernelChanged.connect(
256256
(_, arg: Session.ISessionConnection.IKernelChangedArgs) => {
257257
const kernelConnection = arg.newValue;
258-
console.log('Current Jupyter Kernel connection', kernelConnection);
258+
console.log('Current Jupyter Kernel Connection', kernelConnection);
259259
if (kernelConnection && !kernelConnection.handleComms) {
260260
console.warn(
261261
'Jupyter Kernel Connection does not handle Comms',

packages/react/src/components/notebook/Notebook.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import { CellMetadataEditor } from './cell/metadata/CellMetadataEditor';
1717
import { ICellSidebarProps } from './cell/sidebar/CellSidebarWidget';
1818
import { INotebookToolbarProps } from './toolbar/NotebookToolbar';
1919
import { newUuid } from '../../utils';
20+
import { OnKernelConnection } from '../../state';
2021
import { useNotebookStore } from './NotebookState';
2122
import { NotebookAdapter } from './NotebookAdapter';
2223

@@ -43,14 +44,15 @@ export type INotebookProps = {
4344
maxHeight?: string;
4445
nbformat?: INotebookContent;
4546
nbgrader: boolean;
47+
onKernelConnection?: OnKernelConnection;
4648
path?: string;
4749
readonly: boolean;
4850
renderers: IRenderMime.IRendererFactory[];
4951
serverless: boolean,
5052
serviceManager?: ServiceManager.IManager,
5153
url?: string;
5254
/**
53-
* The Kernel Id to use, as defined in the Kernel API
55+
* The Kernel Id to use, as defined in the Kernel API.
5456
*/
5557
useRunningKernelId?: string;
5658
/**
@@ -91,7 +93,7 @@ export const Notebook = (props: INotebookProps) => {
9193
const kernel = props.kernel ?? defaultKernel;
9294
const notebookStore = useNotebookStore();
9395
const portals = notebookStore.selectNotebookPortals(id);
94-
//
96+
// Bootstrap the Notebook Adapter.
9597
const bootstrapAdapter = (serviceManager?: ServiceManager.IManager, kernel?: Kernel) => {
9698
const adapter = new NotebookAdapter({
9799
...props,
@@ -100,7 +102,6 @@ export const Notebook = (props: INotebookProps) => {
100102
kernel,
101103
serviceManager,
102104
});
103-
console.log('Notebook Adapter is bootstraping...', adapter.serviceManager);
104105
// Update the local state.
105106
setAdapter(adapter);
106107
// Update the global state.

packages/react/src/components/notebook/NotebookAdapter.ts

Lines changed: 90 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -8,22 +8,23 @@ import { find } from '@lumino/algorithm';
88
import { CommandRegistry } from '@lumino/commands';
99
import { BoxPanel, Widget } from '@lumino/widgets';
1010
import { IChangedArgs } from '@jupyterlab/coreutils';
11-
import { Cell, ICellModel, MarkdownCell } from '@jupyterlab/cells';
1211
import { Contents, ServiceManager, Kernel as JupyterKernel, SessionManager } from '@jupyterlab/services';
1312
import { DocumentRegistry, Context } from '@jupyterlab/docregistry';
14-
import { IRenderMime } from '@jupyterlab/rendermime-interfaces';
15-
import { standardRendererFactories, RenderMimeRegistry } from '@jupyterlab/rendermime';
16-
import { rendererFactory as jsonRendererFactory } from '@jupyterlab/json-extension';
17-
import { rendererFactory as javascriptRendererFactory } from '@jupyterlab/javascript-extension';
18-
import { Notebook, NotebookPanel, NotebookWidgetFactory, NotebookTracker, INotebookModel } from '@jupyterlab/notebook';
1913
import { ybinding, CodeMirrorEditorFactory, CodeMirrorMimeTypeService, EditorLanguageRegistry, EditorExtensionRegistry, EditorThemeRegistry } from '@jupyterlab/codemirror';
2014
import { IEditorServices } from '@jupyterlab/codeeditor';
15+
import { standardRendererFactories, RenderMimeRegistry } from '@jupyterlab/rendermime';
16+
import { IRenderMime } from '@jupyterlab/rendermime-interfaces';
17+
import { ISharedAttachmentsCell, IYText } from '@jupyter/ydoc';
18+
import { INotebookContent, CellType, IAttachments } from '@jupyterlab/nbformat';
2119
import { Completer, CompleterModel, CompletionHandler, ProviderReconciliator, KernelCompleterProvider } from '@jupyterlab/completer';
20+
import { Notebook, NotebookPanel, NotebookWidgetFactory, NotebookTracker, INotebookModel } from '@jupyterlab/notebook';
21+
import { Cell, ICellModel, MarkdownCell } from '@jupyterlab/cells';
22+
import { rendererFactory as jsonRendererFactory } from '@jupyterlab/json-extension';
23+
import { rendererFactory as javascriptRendererFactory } from '@jupyterlab/javascript-extension';
2224
import { MathJaxTypesetter } from '@jupyterlab/mathjax-extension';
23-
import { INotebookContent, CellType, IAttachments } from '@jupyterlab/nbformat';
24-
import { ISharedAttachmentsCell, IYText } from '@jupyter/ydoc';
2525
import { WIDGET_MIMETYPE } from '@jupyter-widgets/html-manager/lib/output_renderers';
2626
import { Lite, Kernel, WidgetManager, WidgetLabRenderer } from '../../jupyter';
27+
import { OnKernelConnection } from '../../state';
2728
import { ICellSidebarProps } from './cell/sidebar/CellSidebarWidget';
2829
import { JupyterReactContentFactory } from './content/JupyterReactContentFactory';
2930
import { JupyterReactNotebookModelFactory } from './model/JupyterReactNotebookModelFactory';
@@ -48,17 +49,22 @@ export class NotebookAdapter {
4849
private _nbgrader: boolean;
4950
private _notebookModelFactory?: JupyterReactNotebookModelFactory;
5051
private _notebookPanel?: NotebookPanel;
51-
private _url?: string;
52+
private _onKernelConnection?: OnKernelConnection;
5253
private _path?: string;
5354
private _readonly: boolean;
5455
private _renderers: IRenderMime.IRendererFactory[];
5556
private _rendermime?: RenderMimeRegistry;
5657
private _serverless: boolean;
5758
private _serviceManager: ServiceManager.IManager;
5859
private _tracker?: NotebookTracker;
60+
private _url?: string;
5961

6062
constructor(props: INotebookProps) {
63+
64+
console.log('A new Notebook Adapter is being created...');
65+
6166
this._CellSidebar = props.CellSidebar;
67+
6268
this._id = props.id;
6369
this._kernel = props.kernel;
6470
this._lite = props.lite;
@@ -71,6 +77,8 @@ export class NotebookAdapter {
7177
this._serviceManager = props.serviceManager!;
7278
this._url = props.url;
7379

80+
this._onKernelConnection = props.onKernelConnection;
81+
7482
this._boxPanel = new BoxPanel();
7583
this._boxPanel.addClass('dla-Jupyter-Notebook');
7684
this._boxPanel.spacing = 0;
@@ -149,6 +157,8 @@ export class NotebookAdapter {
149157

150158
initializeContext() {
151159

160+
const isNbFormat = this._path !== undefined && this._path !== '' ? false : true;
161+
152162
this._context = new Context({
153163
manager: this._serviceManager,
154164
factory: this._notebookModelFactory!,
@@ -177,10 +187,7 @@ export class NotebookAdapter {
177187
},
178188
1
179189
);
180-
*/
181-
/*
182-
// This code block was causing https://github.com/datalayer/jupyter-ui/issues/195
183-
// TODO Double check there is not side effect.
190+
// This code block is causing https://github.com/datalayer/jupyter-ui/issues/195
184191
this._context?.sessionContext
185192
.changeKernel({id: this._kernel.id })
186193
.then(() => {
@@ -189,53 +196,56 @@ export class NotebookAdapter {
189196
);
190197
});
191198
*/
199+
192200
// These are fixes to have more control on the kernel launch.
193-
(this._context.sessionContext as any)._initialize =
194-
async (): Promise<boolean> => {
195-
const manager = (this._context!.sessionContext as any)
196-
.sessionManager as SessionManager;
197-
await manager.ready;
198-
await manager.refreshRunning();
199-
const model = find(manager.running(), model => {
200-
return model.kernel?.id === this._kernel?.id;
201-
});
202-
if (model) {
203-
try {
204-
const session = manager.connectTo({
205-
model: {
206-
...model,
207-
path: this._path ?? model.path,
208-
name: this._path ?? model.name,
209-
},
210-
kernelConnectionOptions: {
211-
handleComms: true,
212-
},
213-
});
214-
(this._context!.sessionContext as any)._handleNewSession(session);
215-
} catch (err) {
216-
void (this._context!.sessionContext as any)._handleSessionError(
217-
err
218-
);
219-
return Promise.reject(err);
220-
}
201+
(this._context.sessionContext as any)._initialize = async (): Promise<boolean> => {
202+
const manager = (this._context!.sessionContext as any).sessionManager as SessionManager;
203+
await manager.ready;
204+
await manager.refreshRunning();
205+
const model = find(manager.running(), model => {
206+
return model.kernel?.id === this._kernel?.id;
207+
});
208+
if (model) {
209+
try {
210+
const session = manager.connectTo({
211+
model: {
212+
...model,
213+
path: this._path ?? model.path,
214+
name: this._path ?? model.name,
215+
},
216+
kernelConnectionOptions: {
217+
handleComms: true,
218+
},
219+
});
220+
(this._context!.sessionContext as any)._handleNewSession(session);
221+
} catch (err) {
222+
void (this._context!.sessionContext as any)._handleSessionError(
223+
err
224+
);
225+
return Promise.reject(err);
221226
}
222-
return await (this._context!.sessionContext as any)._startIfNecessary();
223-
};
227+
}
228+
return await (this._context!.sessionContext as any)._startIfNecessary();
229+
};
230+
231+
this._context.sessionContext.ready.then(() => {
232+
if (this._onKernelConnection) {
233+
const kernelConnection = this._context?.sessionContext.session?.kernel;
234+
this._onKernelConnection(kernelConnection);
235+
}
236+
});
224237

225238
this._context.sessionContext.kernelChanged.connect((_, args) => {
226-
console.log('Previous Jupyter Kernel connection', args.oldValue);
239+
console.log('Previous Jupyter Kernel Connection.', args.oldValue);
227240
const kernelConnection = args.newValue;
228-
console.log('Current Jupyter Kernel connection', kernelConnection);
241+
console.log('Current Jupyter Kernel Connection.', kernelConnection);
229242
if (kernelConnection && !kernelConnection.handleComms) {
230-
console.warn(
231-
'The current Kernel Connection does not handle Comms',
232-
kernelConnection.id
233-
);
243+
console.warn('The current Kernel Connection does not handle Comms...', kernelConnection.id);
234244
(kernelConnection as any).handleComms = true;
235-
console.log(
236-
'The current Kernel Connection is updated to enforce Comms support',
237-
kernelConnection.handleComms
238-
);
245+
console.log('The current Kernel Connection is updated to enforce Comms support!', kernelConnection.handleComms);
246+
}
247+
if (this._onKernelConnection) {
248+
this._onKernelConnection(kernelConnection);
239249
}
240250
});
241251

@@ -302,10 +312,35 @@ export class NotebookAdapter {
302312
this._notebookPanel?.update();
303313
});
304314

305-
const isNbFormat = (this._path !== undefined && this._path !== '') ? false : true;
306-
307315
if (isNbFormat) {
308316
// If nbformat is provided and we don't want to interact with the content manager.
317+
(this._context as any)._populate = async (): Promise<void> => {
318+
(this._context as any)._isPopulated = true;
319+
(this._context as any)._isReady = true;
320+
(this._context as any)._populatedPromise.resolve(void 0);
321+
// Add a checkpoint if none exists and the file is writable.
322+
// Force skip this step for nbformat notebooks.
323+
// await (this._context as any)._maybeCheckpoint(false);
324+
if ((this._context as any).isDisposed) {
325+
return;
326+
}
327+
// Update the kernel preference.
328+
const name = (this._context as any)._model.defaultKernelName ||
329+
(this._context as any).sessionContext.kernelPreference.name;
330+
(this._context as any).sessionContext.kernelPreference = {
331+
...(this._context as any).sessionContext.kernelPreference,
332+
name,
333+
language: (this._context as any)._model.defaultKernelLanguage
334+
};
335+
// Note: we don't wait on the session to initialize
336+
// so that the user can be shown the content before
337+
// any kernel has started.
338+
void (this._context as any).sessionContext.initialize().then((shouldSelect: boolean) => {
339+
if (shouldSelect) {
340+
void (this._context as any)._dialogs.selectKernel((this._context!.sessionContext as any).sessionContext);
341+
}
342+
});
343+
};
309344
(this._context as any).initialize = async (isNew: boolean): Promise<void> => {
310345
(this._context as Context<INotebookModel>).model.dirty = false;
311346
const now = new Date().toISOString();

packages/react/src/components/viewer/Viewer.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,11 @@ export const Viewer = (props: IViewerProps) => {
2929
return response.text();
3030
})
3131
.then(nbformat => {
32-
// const nbformat = nb.replaceAll('\\n', '');
32+
// const nbformat = nb.replaceAll('\\n', '');
3333
setModel(JSON.parse(nbformat));
3434
});
3535
}
36-
}, [nbformat]);
36+
}, [nbformat, nbformatUrl]);
3737
return (
3838
<>
3939
{model?.cells.map(cell => {

packages/react/src/examples/JupyterLabApp.tsx

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

77
import { createRoot } from 'react-dom/client';
88
import { NotebookPanel } from '@jupyterlab/notebook';
9-
import { Jupyter } from '../jupyter/Jupyter';
9+
import { JupyterReactTheme } from '../theme';
1010
import { JupyterLabApp, JupyterLabAppAdapter } from '../components/jupyterlab';
1111

1212
import * as lightThemePlugins from '@jupyterlab/theme-light-extension';
@@ -48,8 +48,8 @@ document.body.appendChild(div);
4848
const root = createRoot(div);
4949

5050
root.render(
51-
<Jupyter startDefaultKernel={false} disableCssLoading>
51+
<JupyterReactTheme>
5252
<h1>JupyterLab Application</h1>
5353
<JupyterLabAppExample />
54-
</Jupyter>
54+
</JupyterReactTheme>
5555
);

0 commit comments

Comments
 (0)