From b39935f6e6784154cb130c5746d6f54655a46431 Mon Sep 17 00:00:00 2001 From: Julia Silge Date: Tue, 8 Sep 2026 15:54:51 -0600 Subject: [PATCH 1/2] Respect `quarto.cells.useReticulate` setting in Positron --- apps/vscode/src/host/positron.ts | 17 ++++-- .../src/test/positron/execute-cell.test.ts | 61 +++++++++++++++++-- 2 files changed, 68 insertions(+), 10 deletions(-) diff --git a/apps/vscode/src/host/positron.ts b/apps/vscode/src/host/positron.ts index 7f85c6de..7ea3a30d 100644 --- a/apps/vscode/src/host/positron.ts +++ b/apps/vscode/src/host/positron.ts @@ -95,8 +95,13 @@ export function positronExtensionHost(outputChannel?: vscode.LogOutputChannel): return; } - if (language === "python" && isKnitrDocument(document, engine)) { - language = "r"; + let executionLanguage = language; + if ( + language === "python" && + isKnitrDocument(document, engine) && + vscode.workspace.getConfiguration("quarto").get("cells.useReticulate", true) + ) { + executionLanguage = "r"; blocks = blocks.map(pythonWithReticulate); } @@ -119,7 +124,7 @@ export function positronExtensionHost(outputChannel?: vscode.LogOutputChannel): try { await runtime.executeCode( - language, // The language ID + executionLanguage, // The language ID blocks[i], // The code string to execute false, // Whether to focus the console true, // Whether to allow incomplete code to run @@ -136,7 +141,7 @@ export function positronExtensionHost(outputChannel?: vscode.LogOutputChannel): if (!runtimeFailure) { // The code couldn't be submitted to the runtime. Log it // and let it propagate so the user finds out. - outputChannel?.error(`Failed to execute ${language} cell: ${message}`); + outputChannel?.error(`Failed to execute ${executionLanguage} cell: ${message}`); throw err; } @@ -145,7 +150,7 @@ export function positronExtensionHost(outputChannel?: vscode.LogOutputChannel): // record but don't let it propagate to the command handler, // which would surface it again as a notification popup. // https://github.com/posit-dev/positron/issues/9845 - outputChannel?.debug(`Error executing ${language} cell: ${message}`); + outputChannel?.debug(`Error executing ${executionLanguage} cell: ${message}`); // Stop executing any subsequent blocks since one failed. break; @@ -153,7 +158,7 @@ export function positronExtensionHost(outputChannel?: vscode.LogOutputChannel): } }; - await ExecuteQueue.instance.add(language, callback); + await ExecuteQueue.instance.add(executionLanguage, callback); }, executeSelection: async (): Promise => { await vscode.commands.executeCommand('workbench.action.positronConsole.executeCode', { languageId: language }); diff --git a/apps/vscode/src/test/positron/execute-cell.test.ts b/apps/vscode/src/test/positron/execute-cell.test.ts index 845c5fde..219c5972 100644 --- a/apps/vscode/src/test/positron/execute-cell.test.ts +++ b/apps/vscode/src/test/positron/execute-cell.test.ts @@ -38,7 +38,7 @@ suite("Positron: cell execution", function () { // `acquirePositronApi` is injected onto the global by Positron; we swap it for // a spy during each test and must restore it afterwards. - const globalWithApi = globalThis as { acquirePositronApi?: () => unknown }; + const globalWithApi = globalThis as { acquirePositronApi?: () => unknown; }; let originalAcquire: (() => unknown) | undefined; teardown(function () { @@ -73,7 +73,7 @@ suite("Positron: cell execution", function () { // which we record instead of dispatching to a kernel. const calls: RuntimeCall[] = []; originalAcquire = globalWithApi.acquirePositronApi; - const realApi = originalAcquire!() as { runtime: Record }; + const realApi = originalAcquire!() as { runtime: Record; }; const fakeRuntime = new Proxy(realApi.runtime, { get(target, prop, receiver) { if (prop === "executeCode") { @@ -134,7 +134,7 @@ suite("Positron: cell execution", function () { assert.ok( call, "Running the cell should call positron.runtime.executeCode('python', ...). " + - `Observed: ${describe(calls)}` + `Observed: ${describe(calls)}` ); const code = String(call!.args[1]); @@ -171,7 +171,7 @@ suite("Positron: cell execution", function () { assert.ok( call, "A knitr Python cell should be submitted to executeCode('r', ...). " + - `Observed: ${describe(calls)}` + `Observed: ${describe(calls)}` ); const code = String(call!.args[1]); @@ -184,6 +184,59 @@ suite("Positron: cell execution", function () { "the original Python code should be embedded in the reticulate call" ); }); + + test("submits a knitr Python cell as python when cells.useReticulate is false", async function () { + const config = vscode.workspace.getConfiguration("quarto"); + const previous = config.get("cells.useReticulate"); + await config.update( + "cells.useReticulate", + false, + vscode.ConfigurationTarget.Global + ); + try { + const marker = `qmd_marker_${Date.now()}`; + const qmd = [ + "---", + "engine: knitr", + "---", + "", + "```{python}", + `${marker} = 42`, + "```", + "", + ].join("\n"); + // Cursor on the statement (line 5). + const calls = await runCellAndCaptureCalls(qmd, 5); + + const rCall = calls.find( + (c) => c.method === "executeCode" && c.args[0] === "r" + ); + assert.ok( + !rCall, + "With cells.useReticulate=false, a knitr Python cell should not be " + + `submitted to the R runtime. Observed: ${describe(calls)}` + ); + + const pyCall = calls.find( + (c) => c.method === "executeCode" && c.args[0] === "python" + ); + assert.ok( + pyCall, + "With cells.useReticulate=false, a knitr Python cell should be " + + `submitted to executeCode('python', ...). Observed: ${describe(calls)}` + ); + assert.ok( + !String(pyCall!.args[1]).includes("reticulate::repl_python"), + "the code should not be wrapped in reticulate::repl_python(...)" + ); + } finally { + await config.update( + "cells.useReticulate", + previous, + vscode.ConfigurationTarget.Global + ); + } + }); }); /** Compact summary of observed runtime calls for assertion messages. */ From 0667ad3ac4cfd2f4e50933032bbf240c29dcabf7 Mon Sep 17 00:00:00 2001 From: Julia Silge Date: Tue, 8 Sep 2026 16:02:52 -0600 Subject: [PATCH 2/2] Update CHANGELOG --- apps/vscode/CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/vscode/CHANGELOG.md b/apps/vscode/CHANGELOG.md index 9132c277..a7e3592a 100644 --- a/apps/vscode/CHANGELOG.md +++ b/apps/vscode/CHANGELOG.md @@ -2,6 +2,7 @@ ## 1.138.0 (Unreleased) +- In Positron, running a Python cell in a knitr document now respects the `quarto.cells.useReticulate` setting, instead of always routing it through reticulate on the R console (). ## 1.137.0 (Release on 2026-09-04)