Skip to content

Commit e02dca3

Browse files
committed
Check marimo version in py venv before execution
1 parent 44c6525 commit e02dca3

File tree

5 files changed

+100
-18
lines changed

5 files changed

+100
-18
lines changed

extension/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@
104104
"@biomejs/biome": "^2.2.2",
105105
"@marimo-team/frontend": "link:../../marimo/frontend/",
106106
"@marimo-team/openapi": "link:../../marimo/packages/openapi/",
107+
"@std/semver": "jsr:^1.0.5",
107108
"@tailwindcss/vite": "^4.1.11",
108109
"@types/node": "^22.13.10",
109110
"@types/react": "^19.1.9",

extension/pnpm-lock.yaml

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

extension/src/notebookControllerManager.ts

Lines changed: 76 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,19 @@
1-
import * as py from "@vscode/python-extension";
1+
import { execFile } from "node:child_process";
2+
import * as semver from "@std/semver";
3+
import type * as py from "@vscode/python-extension";
24
import * as vscode from "vscode";
35
import type * as lsp from "vscode-languageclient";
6+
47
import * as cmds from "./commands.ts";
58
import { Logger } from "./logging.ts";
9+
import { getPythonApi } from "./python.ts";
610
import { notebookType } from "./types.ts";
711

812
export function createNotebookControllerManager(
913
client: lsp.BaseLanguageClient,
1014
options: { signal: AbortSignal },
1115
) {
16+
// Single map for both controller and environment
1217
const controllers = new Map<string, vscode.NotebookController>();
1318
const selectedControllers = new WeakMap<
1419
vscode.NotebookDocument,
@@ -28,9 +33,9 @@ export function createNotebookControllerManager(
2833

2934
{
3035
// Just update the controller if it exists
31-
const controller = controllers.get(controllerId);
32-
if (controller) {
33-
controller.label = controllerLabel;
36+
const existing = controllers.get(controllerId);
37+
if (existing) {
38+
existing.label = controllerLabel;
3439
Logger.trace(
3540
"Controller.Update",
3641
"Updated controller:",
@@ -51,6 +56,37 @@ export function createNotebookControllerManager(
5156
cellCount: cells.length,
5257
notebook: notebook.uri.toString(),
5358
});
59+
60+
const version = await tryGetMarimoVersion(env, options);
61+
62+
if (!version) {
63+
const envName = resolvePythonEnvironmentName(env);
64+
const envLabel = envName
65+
? `"${envName}"`
66+
: "the selected environment";
67+
await vscode.window.showErrorMessage(
68+
`Could not find marimo in ${envLabel}. Please ensure marimo is installed.`,
69+
{ modal: true },
70+
);
71+
72+
return;
73+
}
74+
75+
if (
76+
!semver.greaterOrEqual(version, { major: 0, minor: 14, patch: 0 })
77+
) {
78+
const envName = resolvePythonEnvironmentName(env);
79+
const envLabel = envName
80+
? `"${envName}"`
81+
: "the selected environment";
82+
await vscode.window.showWarningMessage(
83+
`marimo version in ${envLabel} is outdated (v${semver.format(version)}). Please update to v0.14.0 or later.`,
84+
{ modal: true },
85+
);
86+
87+
return;
88+
}
89+
5490
await cmds.executeCommand(client, {
5591
command: "marimo.run",
5692
params: {
@@ -136,7 +172,7 @@ export function createNotebookControllerManager(
136172
}
137173

138174
// TODO: await this somewhere?
139-
py.PythonExtension.api()
175+
getPythonApi()
140176
.then((api) => initialize(api))
141177
.catch((error) => {
142178
Logger.error(
@@ -158,18 +194,6 @@ export function createNotebookControllerManager(
158194
};
159195
}
160196

161-
function resolvePythonEnvironmentName(env: py.Environment): string | undefined {
162-
if (env.environment?.name) {
163-
return env.environment.name;
164-
}
165-
if (env.environment?.folderUri) {
166-
return vscode.Uri.parse(env.environment.folderUri.toString())
167-
.path.split("/")
168-
.pop();
169-
}
170-
return undefined;
171-
}
172-
173197
/**
174198
* Format a {@link py.Environment} similar to vscode-jupyter
175199
*
@@ -198,3 +222,38 @@ function formatControllerLabel(env: py.Environment): string {
198222
}
199223
return formatted;
200224
}
225+
226+
async function tryGetMarimoVersion(
227+
env: py.Environment,
228+
options: {
229+
signal?: AbortSignal;
230+
},
231+
): Promise<semver.SemVer | undefined> {
232+
return new Promise((resolve) => {
233+
execFile(
234+
env.path,
235+
["-c", "import marimo; print(marimo.__version__)"],
236+
{ signal: options.signal },
237+
(error, stdout) => {
238+
resolve(error ? undefined : semver.tryParse(stdout.trim()));
239+
},
240+
);
241+
});
242+
}
243+
244+
/**
245+
* A human readable name for a {@link py.Environment}
246+
*/
247+
export function resolvePythonEnvironmentName(
248+
env: py.Environment,
249+
): string | undefined {
250+
if (env.environment?.name) {
251+
return env.environment.name;
252+
}
253+
if (env.environment?.folderUri) {
254+
return vscode.Uri.parse(env.environment.folderUri.toString())
255+
.path.split("/")
256+
.pop();
257+
}
258+
return undefined;
259+
}

extension/src/python.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import * as py from "@vscode/python-extension";
2+
3+
let api: py.PythonExtension | undefined;
4+
5+
/**
6+
* Get cached Python Extension API.
7+
*/
8+
export async function getPythonApi(): Promise<py.PythonExtension> {
9+
if (!api) {
10+
api = await py.PythonExtension.api();
11+
}
12+
return api;
13+
}

src/marimo_lsp/session_manager.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
from __future__ import annotations
44

5+
import sys
56
import typing
67
from uuid import uuid4
78

@@ -69,7 +70,7 @@ def create_session(self, *, server: LanguageServer, notebook_uri: str) -> Sessio
6970

7071
kernel_manager = LspKernelManager(
7172
# TODO: Get executable
72-
executable="/Users/manzt/demos/marimo-lsp-test/.venv/bin/python",
73+
executable=sys.executable,
7374
queue_manager=queue_manager,
7475
app_file_manager=app_file_manager,
7576
config_manager=config_manager,

0 commit comments

Comments
 (0)