Skip to content
Merged
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
46ab116
feat(block-execution): use deepnote kernel in venv
saltenasl Oct 1, 2025
8b17edd
fix: usage of any
saltenasl Oct 1, 2025
635de8d
feat: isolated venv for every .deepnote file
saltenasl Oct 1, 2025
dc03549
fix: registered kernel is now recognized in ui
saltenasl Oct 1, 2025
c4e6bb0
feat: notebooks now run on deepnote kernel
saltenasl Oct 1, 2025
15280c6
chore: code review comments from src/kernels/deepnote/deepnoteToolkit…
saltenasl Oct 2, 2025
28c1f2d
chore: second part of code review comments
saltenasl Oct 2, 2025
6e01551
fix: allow multiple block runs in a row by simplifying call flow
saltenasl Oct 2, 2025
1be1eab
feat: respect venv when runing shell commands
saltenasl Oct 2, 2025
e32d9ec
feat: correct cwd to load files
saltenasl Oct 2, 2025
263f04e
feat: progress indicators
saltenasl Oct 2, 2025
f9376b5
chore: code review comments
saltenasl Oct 2, 2025
d72c7ba
chore: bring back toolkit version constant
saltenasl Oct 2, 2025
3b564ba
fix: hash venv name
saltenasl Oct 2, 2025
81b5d7b
fix: cleanup server on cancellation
saltenasl Oct 2, 2025
c284ff0
fix: clarify kernel spec strategy
saltenasl Oct 2, 2025
d54e69e
feat: better windows support
saltenasl Oct 2, 2025
fb6c201
fix: increase timeout for deepnote kernel instantiation
saltenasl Oct 2, 2025
82ad53c
fix: rm broken venv dir recursively
saltenasl Oct 2, 2025
36c134b
fix: throw on std err during toolkit installation
saltenasl Oct 2, 2025
77e899b
Revert "feat: better windows support"
saltenasl Oct 2, 2025
e10470b
fix: venv paths
saltenasl Oct 2, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
391 changes: 391 additions & 0 deletions DEEPNOTE_KERNEL_IMPLEMENTATION.md

Large diffs are not rendered by default.

30 changes: 15 additions & 15 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -710,80 +710,80 @@
{
"command": "jupyter.restartkernel",
"group": "navigation/execute@5",
"when": "notebookKernel =~ /^ms-toolsai.jupyter\\// && notebookType == 'jupyter-notebook' && isWorkspaceTrusted && jupyter.kernel.isjupyter"
"when": "notebookKernel =~ /^ms-toolsai.jupyter\\// && notebookType == 'jupyter-notebook' && notebookType != 'deepnote' && isWorkspaceTrusted && jupyter.kernel.isjupyter"
},
{
"command": "jupyter.openVariableView",
"group": "navigation@1",
"when": "notebookKernel =~ /^ms-toolsai.jupyter\\// && notebookType == 'jupyter-notebook' && isWorkspaceTrusted && jupyter.ispythonnotebook && jupyter.kernel.isjupyter"
"when": "notebookKernel =~ /^ms-toolsai.jupyter\\// && notebookType == 'jupyter-notebook' && notebookType != 'deepnote' && isWorkspaceTrusted && jupyter.ispythonnotebook && jupyter.kernel.isjupyter"
},
{
"command": "jupyter.openOutlineView",
"group": "navigation@2",
"when": "notebookType == 'jupyter-notebook' && config.jupyter.showOutlineButtonInNotebookToolbar"
"when": "notebookType == 'jupyter-notebook' && notebookType != 'deepnote' && config.jupyter.showOutlineButtonInNotebookToolbar"
},
{
"command": "jupyter.continueEditSessionInCodespace",
"group": "navigation@3",
"when": "notebookType == 'jupyter-notebook' && jupyter.kernelSource == 'github-codespaces'"
"when": "notebookType == 'jupyter-notebook' && notebookType != 'deepnote' && jupyter.kernelSource == 'github-codespaces'"
},
{
"command": "jupyter.notebookeditor.export",
"group": "Jupyter",
"when": "notebookType == 'jupyter-notebook' && isWorkspaceTrusted"
"when": "notebookType == 'jupyter-notebook' && notebookType != 'deepnote' && isWorkspaceTrusted"
},
{
"command": "jupyter.replayPylanceLogStep",
"group": "navigation@1",
"when": "notebookType == 'jupyter-notebook' && isWorkspaceTrusted && jupyter.replayLogLoaded"
"when": "notebookType == 'jupyter-notebook' && notebookType != 'deepnote' && isWorkspaceTrusted && jupyter.replayLogLoaded"
}
],
"notebook/cell/title": [
{
"command": "jupyter.runByLine",
"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",
"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",
"group": "inline/cell@0"
},
{
"command": "jupyter.runByLineNext",
"when": "notebookCellResource in jupyter.notebookeditor.runByLineCells",
"when": "notebookCellResource in jupyter.notebookeditor.runByLineCells && notebookType != deepnote",
"group": "inline/cell@0"
},
{
"command": "jupyter.runByLineStop",
"when": "notebookCellResource in jupyter.notebookeditor.runByLineCells && notebookCellToolbarLocation == left",
"when": "notebookCellResource in jupyter.notebookeditor.runByLineCells && notebookType != deepnote && notebookCellToolbarLocation == left",
"group": "inline/cell@1"
},
{
"command": "jupyter.runByLineStop",
"when": "notebookCellResource in jupyter.notebookeditor.runByLineCells && notebookCellToolbarLocation == right",
"when": "notebookCellResource in jupyter.notebookeditor.runByLineCells && notebookType != deepnote && notebookCellToolbarLocation == right",
"group": "inline/cell@0"
},
{
"command": "jupyter.selectPrecedentCells",
"when": "notebookType == 'jupyter-notebook' && isWorkspaceTrusted && config.jupyter.executionAnalysis.enabled",
"when": "notebookType == 'jupyter-notebook' && notebookType != 'deepnote' && isWorkspaceTrusted && config.jupyter.executionAnalysis.enabled",
"group": "executionAnalysis@0"
},
{
"command": "jupyter.selectDependentCells",
"when": "notebookType == 'jupyter-notebook' && isWorkspaceTrusted && config.jupyter.executionAnalysis.enabled",
"when": "notebookType == 'jupyter-notebook' && notebookType != 'deepnote' && isWorkspaceTrusted && config.jupyter.executionAnalysis.enabled",
"group": "executionAnalysis@1"
}
],
"notebook/cell/execute": [
{
"command": "jupyter.runAndDebugCell",
"when": "notebookKernel =~ /^ms-toolsai.jupyter\\// && jupyter.ispythonnotebook && notebookCellType == code && isWorkspaceTrusted && resource not in jupyter.notebookeditor.debugDocuments || !notebookKernel && jupyter.ispythonnotebook && notebookCellType == code && isWorkspaceTrusted",
"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",
"group": "jupyterCellExecute@0"
},
{
"command": "jupyter.runPrecedentCells",
"when": "notebookKernel =~ /^ms-toolsai.jupyter\\// && jupyter.ispythonnotebook && notebookCellType == code && isWorkspaceTrusted && config.jupyter.executionAnalysis.enabled",
"when": "notebookKernel =~ /^ms-toolsai.jupyter\\// && jupyter.ispythonnotebook && notebookType != deepnote && notebookCellType == code && isWorkspaceTrusted && config.jupyter.executionAnalysis.enabled",
"group": "jupyterCellExecute@1"
},
{
"command": "jupyter.runDependentCells",
"when": "notebookKernel =~ /^ms-toolsai.jupyter\\// && jupyter.ispythonnotebook && notebookCellType == code && isWorkspaceTrusted && config.jupyter.executionAnalysis.enabled",
"when": "notebookKernel =~ /^ms-toolsai.jupyter\\// && jupyter.ispythonnotebook && notebookType != deepnote && notebookCellType == code && isWorkspaceTrusted && config.jupyter.executionAnalysis.enabled",
"group": "jupyterCellExecute@2"
}
],
Expand Down
119 changes: 119 additions & 0 deletions src/kernels/deepnote/deepnoteServerProvider.node.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

import { inject, injectable } from 'inversify';
import { CancellationToken, Uri, Event, EventEmitter } from 'vscode';
import { JupyterServer, JupyterServerProvider } from '../../api';
import { IExtensionSyncActivationService } from '../../platform/activation/types';
import { IDisposableRegistry } from '../../platform/common/types';
import { IJupyterServerProviderRegistry } from '../jupyter/types';
import { JVSC_EXTENSION_ID } from '../../platform/common/constants';
import { logger } from '../../platform/logging';
import { DeepnoteServerNotFoundError } from '../../platform/errors/deepnoteServerNotFoundError';
import { DeepnoteServerInfo, IDeepnoteServerProvider } from './types';

/**
* Jupyter Server Provider for Deepnote kernels.
* This provider resolves server connections for Deepnote kernels.
*/
@injectable()
export class DeepnoteServerProvider
implements IDeepnoteServerProvider, IExtensionSyncActivationService, JupyterServerProvider
{
public readonly id = 'deepnote-server';
private readonly _onDidChangeServers = new EventEmitter<void>();
public readonly onDidChangeServers: Event<void> = this._onDidChangeServers.event;

// Map of server handles to server info
private servers = new Map<string, DeepnoteServerInfo>();

constructor(
@inject(IJupyterServerProviderRegistry)
private readonly jupyterServerProviderRegistry: IJupyterServerProviderRegistry,
@inject(IDisposableRegistry) private readonly disposables: IDisposableRegistry
) {}

public activate() {
// Register this server provider
const collection = this.jupyterServerProviderRegistry.createJupyterServerCollection(
JVSC_EXTENSION_ID,
this.id,
'Deepnote Toolkit Server',
this
);
this.disposables.push(collection);
logger.info('Deepnote server provider registered');
}

/**
* Register a server for a specific handle.
* Called by DeepnoteKernelAutoSelector when a server is started.
*/
public registerServer(handle: string, serverInfo: DeepnoteServerInfo): void {
logger.info(`Registering Deepnote server: ${handle} -> ${serverInfo.url}`);
this.servers.set(handle, serverInfo);
this._onDidChangeServers.fire();
}

/**
* Unregister a server for a specific handle.
* Called when the server is no longer needed or notebook is closed.
* No-op if the handle doesn't exist.
*/
public unregisterServer(handle: string): void {
if (this.servers.has(handle)) {
logger.info(`Unregistering Deepnote server: ${handle}`);
this.servers.delete(handle);
this._onDidChangeServers.fire();
}
}

/**
* Dispose of all servers and resources.
*/
public dispose(): void {
logger.info('Disposing Deepnote server provider, clearing all registered servers');
this.servers.clear();
this._onDidChangeServers.dispose();
}

/**
* Provides the list of available Deepnote servers.
*/
public async provideJupyterServers(_token: CancellationToken): Promise<JupyterServer[]> {
const servers: JupyterServer[] = [];
for (const [handle, info] of this.servers.entries()) {
servers.push({
id: handle,
label: `Deepnote Toolkit (${info.port})`,
connectionInformation: {
baseUrl: Uri.parse(info.url),
token: info.token || ''
}
});
}
return servers;
}

/**
* Resolves a Jupyter server by its handle.
* This is called by the kernel infrastructure when starting a kernel.
*/
public async resolveJupyterServer(server: JupyterServer, _token: CancellationToken): Promise<JupyterServer> {
logger.info(`Resolving Deepnote server: ${server.id}`);
const serverInfo = this.servers.get(server.id);

if (!serverInfo) {
throw new DeepnoteServerNotFoundError(server.id);
}

return {
id: server.id,
label: server.label,
connectionInformation: {
baseUrl: Uri.parse(serverInfo.url),
token: serverInfo.token || ''
}
};
}
}
Loading