Skip to content

Commit 8f22894

Browse files
authored
fix: Install kernel spec into venv instead of user directory (#29)
* fix: Install kernel spec into venv instead of user directory Previously, ipykernel specs were installed with --user flag, placing them in ~/Library/Jupyter/kernels/. This caused the Deepnote Jupyter server to fall back to generic Python kernels because it couldn't discover the venv-specific kernel spec. This resulted in a mismatch where: - Shell commands (!pip install) used the venv's Python (via PATH) - But the kernel interpreter used system Python - Leading to ModuleNotFoundError for packages installed in the venv Now installing kernel specs with --prefix into the venv itself at <venv>/share/jupyter/kernels/. Jupyter automatically discovers kernel specs in this location when started with the venv's Python, ensuring the correct interpreter is used. Each .deepnote file maintains its own isolated venv with its own kernel spec, preventing conflicts when multiple notebooks are open.
1 parent b2649a7 commit 8f22894

File tree

2 files changed

+14
-2
lines changed

2 files changed

+14
-2
lines changed

CLAUDE.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
## Code Style & Organization
22
- Order method, fields and properties, first by accessibility and then by alphabetical order.
33
- Don't add the Microsoft copyright header to new files.
4+
- Use `Uri.joinPath()` for constructing file paths to ensure platform-correct path separators (e.g., `Uri.joinPath(venvPath, 'share', 'jupyter', 'kernels')` instead of string concatenation with `/`)
45

56
## Testing
67
- Unit tests use Mocha/Chai framework with `.unit.test.ts` extension

src/kernels/deepnote/deepnoteToolkitInstaller.node.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@ export class DeepnoteToolkitInstaller implements IDeepnoteToolkitInstaller {
6565
const venvPath = this.getVenvPath(deepnoteFileUri);
6666
const venvKey = venvPath.fsPath;
6767

68+
logger.info(`Ensuring virtual environment at ${venvKey}`);
69+
6870
// Wait for any pending installation for this venv to complete
6971
const pendingInstall = this.pendingInstallations.get(venvKey);
7072
if (pendingInstall) {
@@ -210,6 +212,7 @@ export class DeepnoteToolkitInstaller implements IDeepnoteToolkitInstaller {
210212
logger.info('deepnote-toolkit installed successfully in venv');
211213

212214
// Install kernel spec so the kernel uses this venv's Python
215+
// Install into the venv itself (not --user) so the Deepnote server can discover it
213216
logger.info('Installing kernel spec for venv...');
214217
try {
215218
// Reuse the process service with system environment
@@ -219,15 +222,23 @@ export class DeepnoteToolkitInstaller implements IDeepnoteToolkitInstaller {
219222
'-m',
220223
'ipykernel',
221224
'install',
222-
'--user',
225+
'--prefix',
226+
venvPath.fsPath,
223227
'--name',
224228
`deepnote-venv-${this.getVenvHash(deepnoteFileUri)}`,
225229
'--display-name',
226230
`Deepnote (${this.getDisplayName(deepnoteFileUri)})`
227231
],
228232
{ throwOnStdErr: false }
229233
);
230-
logger.info('Kernel spec installed successfully');
234+
const kernelSpecPath = Uri.joinPath(
235+
venvPath,
236+
'share',
237+
'jupyter',
238+
'kernels',
239+
`deepnote-venv-${this.getVenvHash(deepnoteFileUri)}`
240+
);
241+
logger.info(`Kernel spec installed successfully to ${kernelSpecPath.fsPath}`);
231242
} catch (ex) {
232243
logger.warn(`Failed to install kernel spec: ${ex}`);
233244
// Don't fail the entire installation if kernel spec creation fails

0 commit comments

Comments
 (0)