Skip to content

Commit c35f414

Browse files
authored
feat(block-execution): use deepnote kernel in venv (#16)
* feat(block-execution): use deepnote kernel in venv * fix: usage of any * feat: isolated venv for every .deepnote file * fix: registered kernel is now recognized in ui * feat: notebooks now run on deepnote kernel * chore: code review comments from src/kernels/deepnote/deepnoteToolkitInstaller.node.ts * chore: second part of code review comments * fix: allow multiple block runs in a row by simplifying call flow * feat: respect venv when runing shell commands * feat: correct cwd to load files * feat: progress indicators * chore: code review comments * chore: bring back toolkit version constant * fix: hash venv name * fix: cleanup server on cancellation * fix: clarify kernel spec strategy * feat: better windows support * fix: increase timeout for deepnote kernel instantiation * fix: rm broken venv dir recursively * fix: throw on std err during toolkit installation * Revert "feat: better windows support" This reverts commit d54e69e. * fix: venv paths
1 parent e7b121e commit c35f414

19 files changed

+1982
-26
lines changed

DEEPNOTE_KERNEL_IMPLEMENTATION.md

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

package.json

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -710,80 +710,80 @@
710710
{
711711
"command": "jupyter.restartkernel",
712712
"group": "navigation/execute@5",
713-
"when": "notebookKernel =~ /^ms-toolsai.jupyter\\// && notebookType == 'jupyter-notebook' && isWorkspaceTrusted && jupyter.kernel.isjupyter"
713+
"when": "notebookKernel =~ /^ms-toolsai.jupyter\\// && notebookType == 'jupyter-notebook' && notebookType != 'deepnote' && isWorkspaceTrusted && jupyter.kernel.isjupyter"
714714
},
715715
{
716716
"command": "jupyter.openVariableView",
717717
"group": "navigation@1",
718-
"when": "notebookKernel =~ /^ms-toolsai.jupyter\\// && notebookType == 'jupyter-notebook' && isWorkspaceTrusted && jupyter.ispythonnotebook && jupyter.kernel.isjupyter"
718+
"when": "notebookKernel =~ /^ms-toolsai.jupyter\\// && notebookType == 'jupyter-notebook' && notebookType != 'deepnote' && isWorkspaceTrusted && jupyter.ispythonnotebook && jupyter.kernel.isjupyter"
719719
},
720720
{
721721
"command": "jupyter.openOutlineView",
722722
"group": "navigation@2",
723-
"when": "notebookType == 'jupyter-notebook' && config.jupyter.showOutlineButtonInNotebookToolbar"
723+
"when": "notebookType == 'jupyter-notebook' && notebookType != 'deepnote' && config.jupyter.showOutlineButtonInNotebookToolbar"
724724
},
725725
{
726726
"command": "jupyter.continueEditSessionInCodespace",
727727
"group": "navigation@3",
728-
"when": "notebookType == 'jupyter-notebook' && jupyter.kernelSource == 'github-codespaces'"
728+
"when": "notebookType == 'jupyter-notebook' && notebookType != 'deepnote' && jupyter.kernelSource == 'github-codespaces'"
729729
},
730730
{
731731
"command": "jupyter.notebookeditor.export",
732732
"group": "Jupyter",
733-
"when": "notebookType == 'jupyter-notebook' && isWorkspaceTrusted"
733+
"when": "notebookType == 'jupyter-notebook' && notebookType != 'deepnote' && isWorkspaceTrusted"
734734
},
735735
{
736736
"command": "jupyter.replayPylanceLogStep",
737737
"group": "navigation@1",
738-
"when": "notebookType == 'jupyter-notebook' && isWorkspaceTrusted && jupyter.replayLogLoaded"
738+
"when": "notebookType == 'jupyter-notebook' && notebookType != 'deepnote' && isWorkspaceTrusted && jupyter.replayLogLoaded"
739739
}
740740
],
741741
"notebook/cell/title": [
742742
{
743743
"command": "jupyter.runByLine",
744-
"when": "notebookKernel =~ /^ms-toolsai.jupyter\\// && notebookType == jupyter-notebook && jupyter.ispythonnotebook && notebookCellType == code && isWorkspaceTrusted && resource not in jupyter.notebookeditor.runByLineDocuments || !notebookKernel && notebookType == jupyter-notebook && jupyter.ispythonnotebook && notebookCellType == code && isWorkspaceTrusted",
744+
"when": "notebookKernel =~ /^ms-toolsai.jupyter\\// && notebookType == jupyter-notebook && notebookType != deepnote && jupyter.ispythonnotebook && notebookCellType == code && isWorkspaceTrusted && resource not in jupyter.notebookeditor.runByLineDocuments || !notebookKernel && notebookType == jupyter-notebook && notebookType != deepnote && jupyter.ispythonnotebook && notebookCellType == code && isWorkspaceTrusted",
745745
"group": "inline/cell@0"
746746
},
747747
{
748748
"command": "jupyter.runByLineNext",
749-
"when": "notebookCellResource in jupyter.notebookeditor.runByLineCells",
749+
"when": "notebookCellResource in jupyter.notebookeditor.runByLineCells && notebookType != deepnote",
750750
"group": "inline/cell@0"
751751
},
752752
{
753753
"command": "jupyter.runByLineStop",
754-
"when": "notebookCellResource in jupyter.notebookeditor.runByLineCells && notebookCellToolbarLocation == left",
754+
"when": "notebookCellResource in jupyter.notebookeditor.runByLineCells && notebookType != deepnote && notebookCellToolbarLocation == left",
755755
"group": "inline/cell@1"
756756
},
757757
{
758758
"command": "jupyter.runByLineStop",
759-
"when": "notebookCellResource in jupyter.notebookeditor.runByLineCells && notebookCellToolbarLocation == right",
759+
"when": "notebookCellResource in jupyter.notebookeditor.runByLineCells && notebookType != deepnote && notebookCellToolbarLocation == right",
760760
"group": "inline/cell@0"
761761
},
762762
{
763763
"command": "jupyter.selectPrecedentCells",
764-
"when": "notebookType == 'jupyter-notebook' && isWorkspaceTrusted && config.jupyter.executionAnalysis.enabled",
764+
"when": "notebookType == 'jupyter-notebook' && notebookType != 'deepnote' && isWorkspaceTrusted && config.jupyter.executionAnalysis.enabled",
765765
"group": "executionAnalysis@0"
766766
},
767767
{
768768
"command": "jupyter.selectDependentCells",
769-
"when": "notebookType == 'jupyter-notebook' && isWorkspaceTrusted && config.jupyter.executionAnalysis.enabled",
769+
"when": "notebookType == 'jupyter-notebook' && notebookType != 'deepnote' && isWorkspaceTrusted && config.jupyter.executionAnalysis.enabled",
770770
"group": "executionAnalysis@1"
771771
}
772772
],
773773
"notebook/cell/execute": [
774774
{
775775
"command": "jupyter.runAndDebugCell",
776-
"when": "notebookKernel =~ /^ms-toolsai.jupyter\\// && jupyter.ispythonnotebook && notebookCellType == code && isWorkspaceTrusted && resource not in jupyter.notebookeditor.debugDocuments || !notebookKernel && jupyter.ispythonnotebook && notebookCellType == code && isWorkspaceTrusted",
776+
"when": "notebookKernel =~ /^ms-toolsai.jupyter\\// && jupyter.ispythonnotebook && notebookType != deepnote && notebookCellType == code && isWorkspaceTrusted && resource not in jupyter.notebookeditor.debugDocuments || !notebookKernel && jupyter.ispythonnotebook && notebookType != deepnote && notebookCellType == code && isWorkspaceTrusted",
777777
"group": "jupyterCellExecute@0"
778778
},
779779
{
780780
"command": "jupyter.runPrecedentCells",
781-
"when": "notebookKernel =~ /^ms-toolsai.jupyter\\// && jupyter.ispythonnotebook && notebookCellType == code && isWorkspaceTrusted && config.jupyter.executionAnalysis.enabled",
781+
"when": "notebookKernel =~ /^ms-toolsai.jupyter\\// && jupyter.ispythonnotebook && notebookType != deepnote && notebookCellType == code && isWorkspaceTrusted && config.jupyter.executionAnalysis.enabled",
782782
"group": "jupyterCellExecute@1"
783783
},
784784
{
785785
"command": "jupyter.runDependentCells",
786-
"when": "notebookKernel =~ /^ms-toolsai.jupyter\\// && jupyter.ispythonnotebook && notebookCellType == code && isWorkspaceTrusted && config.jupyter.executionAnalysis.enabled",
786+
"when": "notebookKernel =~ /^ms-toolsai.jupyter\\// && jupyter.ispythonnotebook && notebookType != deepnote && notebookCellType == code && isWorkspaceTrusted && config.jupyter.executionAnalysis.enabled",
787787
"group": "jupyterCellExecute@2"
788788
}
789789
],
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT License.
3+
4+
import { inject, injectable } from 'inversify';
5+
import { CancellationToken, Uri, Event, EventEmitter } from 'vscode';
6+
import { JupyterServer, JupyterServerProvider } from '../../api';
7+
import { IExtensionSyncActivationService } from '../../platform/activation/types';
8+
import { IDisposableRegistry } from '../../platform/common/types';
9+
import { IJupyterServerProviderRegistry } from '../jupyter/types';
10+
import { JVSC_EXTENSION_ID } from '../../platform/common/constants';
11+
import { logger } from '../../platform/logging';
12+
import { DeepnoteServerNotFoundError } from '../../platform/errors/deepnoteServerNotFoundError';
13+
import { DeepnoteServerInfo, IDeepnoteServerProvider } from './types';
14+
15+
/**
16+
* Jupyter Server Provider for Deepnote kernels.
17+
* This provider resolves server connections for Deepnote kernels.
18+
*/
19+
@injectable()
20+
export class DeepnoteServerProvider
21+
implements IDeepnoteServerProvider, IExtensionSyncActivationService, JupyterServerProvider
22+
{
23+
public readonly id = 'deepnote-server';
24+
private readonly _onDidChangeServers = new EventEmitter<void>();
25+
public readonly onDidChangeServers: Event<void> = this._onDidChangeServers.event;
26+
27+
// Map of server handles to server info
28+
private servers = new Map<string, DeepnoteServerInfo>();
29+
30+
constructor(
31+
@inject(IJupyterServerProviderRegistry)
32+
private readonly jupyterServerProviderRegistry: IJupyterServerProviderRegistry,
33+
@inject(IDisposableRegistry) private readonly disposables: IDisposableRegistry
34+
) {}
35+
36+
public activate() {
37+
// Register this server provider
38+
const collection = this.jupyterServerProviderRegistry.createJupyterServerCollection(
39+
JVSC_EXTENSION_ID,
40+
this.id,
41+
'Deepnote Toolkit Server',
42+
this
43+
);
44+
this.disposables.push(collection);
45+
logger.info('Deepnote server provider registered');
46+
}
47+
48+
/**
49+
* Register a server for a specific handle.
50+
* Called by DeepnoteKernelAutoSelector when a server is started.
51+
*/
52+
public registerServer(handle: string, serverInfo: DeepnoteServerInfo): void {
53+
logger.info(`Registering Deepnote server: ${handle} -> ${serverInfo.url}`);
54+
this.servers.set(handle, serverInfo);
55+
this._onDidChangeServers.fire();
56+
}
57+
58+
/**
59+
* Unregister a server for a specific handle.
60+
* Called when the server is no longer needed or notebook is closed.
61+
* No-op if the handle doesn't exist.
62+
*/
63+
public unregisterServer(handle: string): void {
64+
if (this.servers.has(handle)) {
65+
logger.info(`Unregistering Deepnote server: ${handle}`);
66+
this.servers.delete(handle);
67+
this._onDidChangeServers.fire();
68+
}
69+
}
70+
71+
/**
72+
* Dispose of all servers and resources.
73+
*/
74+
public dispose(): void {
75+
logger.info('Disposing Deepnote server provider, clearing all registered servers');
76+
this.servers.clear();
77+
this._onDidChangeServers.dispose();
78+
}
79+
80+
/**
81+
* Provides the list of available Deepnote servers.
82+
*/
83+
public async provideJupyterServers(_token: CancellationToken): Promise<JupyterServer[]> {
84+
const servers: JupyterServer[] = [];
85+
for (const [handle, info] of this.servers.entries()) {
86+
servers.push({
87+
id: handle,
88+
label: `Deepnote Toolkit (${info.port})`,
89+
connectionInformation: {
90+
baseUrl: Uri.parse(info.url),
91+
token: info.token || ''
92+
}
93+
});
94+
}
95+
return servers;
96+
}
97+
98+
/**
99+
* Resolves a Jupyter server by its handle.
100+
* This is called by the kernel infrastructure when starting a kernel.
101+
*/
102+
public async resolveJupyterServer(server: JupyterServer, _token: CancellationToken): Promise<JupyterServer> {
103+
logger.info(`Resolving Deepnote server: ${server.id}`);
104+
const serverInfo = this.servers.get(server.id);
105+
106+
if (!serverInfo) {
107+
throw new DeepnoteServerNotFoundError(server.id);
108+
}
109+
110+
return {
111+
id: server.id,
112+
label: server.label,
113+
connectionInformation: {
114+
baseUrl: Uri.parse(serverInfo.url),
115+
token: serverInfo.token || ''
116+
}
117+
};
118+
}
119+
}

0 commit comments

Comments
 (0)