Python deps: smart missing-package hint + switch to .vrf requirements file
Build and Deploy Verso / deploy (push) Successful in 9m46s

Option A: when a {python} cell fails with ModuleNotFoundError/ImportError, the
log now suggests the exact PyPI package to add (with a module->package map, e.g.
cv2 -> opencv-python, sklearn -> scikit-learn), names the Verso requirements
file, and notes it could instead be a local module — so the langmuirthermalstudy
case isn't mistaken for a PyPI package.

Switch the per-project requirements file from requirements.txt to a Verso-
specific requirements.vrf (so it won't be confused with arbitrary .txt files);
QuartoRunner now looks for requirements.vrf, and 'vrf' is registered as an
editable text extension. The dedicated in-UI editor (and hiding it from the
file tree) follows in a separate change.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
claude
2026-06-02 14:19:01 +00:00
co-authored by Claude Opus 4.8
parent 8530c5ebe0
commit c9727a26e4
4 changed files with 45 additions and 19 deletions
+1
View File
@@ -56,6 +56,7 @@ const defaultTextExtensions = [
'rmd',
'qmd',
'typ',
'vrf', // Verso requirements file (Python deps for Quarto venvs)
'lua',
'py',
'gv',
@@ -37,6 +37,25 @@ const R_QUITTING_REGEX = /^Quitting from lines? (\d+)(?:-\d+)?\s*(?:\(([^)]+)\))
// ImportError: No module named scipy
const PY_MODULE_REGEX =
/^(?:ModuleNotFoundError|ImportError): No module named ['"]?([\w.]+)['"]?/
// Import (module) name -> PyPI package name, for the common cases where they
// differ. Anything not listed defaults to the module name itself.
const PY_MODULE_TO_PACKAGE: Record<string, string> = {
cv2: 'opencv-python',
sklearn: 'scikit-learn',
skimage: 'scikit-image',
PIL: 'Pillow',
yaml: 'PyYAML',
bs4: 'beautifulsoup4',
Crypto: 'pycryptodome',
OpenSSL: 'pyOpenSSL',
dateutil: 'python-dateutil',
dotenv: 'python-dotenv',
serial: 'pyserial',
usb: 'pyusb',
cairo: 'pycairo',
gi: 'PyGObject',
win32com: 'pywin32',
}
// A typst diagnostic location line: ` ┌─ main.typ:5:10` / ` --> main.typ:5:10`
const TYPST_LOCATION_REGEX = /(?:[┌╭]─|-->)\s*(.+?):(\d+):(\d+)/
@@ -77,17 +96,23 @@ export default function parseQuartoLog(rawLog: string): ParseResult {
// through as an opaque error (or not be surfaced at all).
const pyModule = trimmed.match(PY_MODULE_REGEX)
if (pyModule) {
const pkg = pyModule[1]
const moduleName = pyModule[1]
// Suggest the PyPI package for the top-level module (cv2 -> opencv-python).
const topLevel = moduleName.split('.')[0]
const suggestion = PY_MODULE_TO_PACKAGE[topLevel] || topLevel
data.push({
line: pendingLocation.line ?? null,
file: pendingLocation.file,
level: 'error',
message: `Python package "${pkg}" is not installed on the server`,
message: `Python module "${moduleName}" is not available`,
content:
`${clean}\n\nThe Python package "${pkg}" is not available in the ` +
`compile environment. Common scientific packages (numpy, pandas, ` +
`scipy, matplotlib, seaborn, scikit-learn, sympy, plotly) are ` +
`pre-installed; others must be added to the server image.`,
`${clean}\n\n` +
`If "${topLevel}" is a PyPI package, add \`${suggestion}\` to your ` +
`Verso requirements file (requirements.vrf) and recompile as the ` +
`project owner or a collaborator. If it is your own module, add its ` +
`.py file(s) to the project instead.\n` +
`Pre-installed: numpy, pandas, scipy, matplotlib, seaborn, ` +
`scikit-learn, sympy, plotly, tabulate, opencv-python (cv2), tqdm.`,
raw: clean,
})
pendingLocation = {}