Skip to content

Fix .quarto_ipynb files not cleaned up after render#14366

Open
cderv wants to merge 7 commits intomainfrom
fix/issue-14359
Open

Fix .quarto_ipynb files not cleaned up after render#14366
cderv wants to merge 7 commits intomainfrom
fix/issue-14359

Conversation

@cderv
Copy link
Copy Markdown
Collaborator

@cderv cderv commented Apr 15, 2026

When rendering a .qmd file with Jupyter execution, the intermediate .quarto_ipynb file is never deleted. Each subsequent preview creates numbered variants (_1, _2, etc.) that accumulate on disk.

Root Cause

PR #12793 added keep-ipynb: true support by integrating cleanupNotebook() with fileInformationCache. As a side effect, it dropped the immediate file deletion for the default keep-ipynb: false case. The function only flips a transient flag in the cache when keep-ipynb: true is set, but does nothing otherwise — the file just stays on disk.

Fix

Add an else if (data.transient) branch in cleanupNotebook() that calls safeRemoveSync(target.input) when keep-ipynb is false, restoring the original deletion behavior while preserving the cache integration for keep-ipynb: true.

This is safe because execute() already has a guard (lines 441-447) that recreates the notebook if it's missing, and safeRemoveSync tolerates missing files.

Also adds fileNotExists verification to the smoke-all test framework and a test that verifies the .quarto_ipynb file is cleaned up after render.

Fixes #14359

cderv added 4 commits April 16, 2026 11:52
- Add `fileNotExists` to verify.ts, mirroring `fileExists` but calling
  `verifyNoPath` instead of `verifyPath`
- Wire `fileNotExists` into smoke-all.test.ts verifyMap handling block
  alongside the existing `fileExists` block
- Add smoke-all test 14359.qmd that verifies the .quarto_ipynb intermediate
  file is cleaned up after render when keep-ipynb defaults to false
When keep-ipynb is false (the default), cleanupNotebook() now calls
safeRemoveSync() to delete the intermediate .quarto_ipynb file immediately
after execution, restoring the original behavior from 2021 that was
inadvertently dropped when keep-ipynb support was added in PR #12793.
@cderv cderv force-pushed the fix/issue-14359 branch from d47908c to 465bd81 Compare April 16, 2026 09:52
@cderv cderv marked this pull request as draft April 16, 2026 12:54
stageTypstPackages and collectPackageSources received the execution
target input path (which is the transient .quarto_ipynb for Jupyter
targets). These functions only need the directory for extension
discovery via inputExtensionDirs. Using the file path caused a
NotFound error when the transient notebook was already cleaned up.

Pass inputDir (already computed by dirAndStem) instead of input.
@cderv
Copy link
Copy Markdown
Collaborator Author

cderv commented Apr 16, 2026

CI failures were caused by a latent bug in stageTypstPackages() / collectPackageSources() in output-typst.ts. These functions received the execution target's input path (the transient .quarto_ipynb for Jupyter targets) but only need the input directory for extension discovery. When the .quarto_ipynb cleanup restored by this PR deleted the file before the typst complete() phase, inputDirName() crashed on Deno.statSync() of the missing file.

Fixed in 0cadc5e — pass inputDir (already computed by dirAndStem) instead of the file path. The typst/great-tables tests that were failing now pass locally.

@cderv cderv marked this pull request as ready for review April 16, 2026 13:53
cderv added 2 commits April 16, 2026 16:54
Restructure cleanupNotebook with early returns that separate three
concerns: non-transient notebooks, keep-ipynb preservation, and
transient deletion.

Previously, when keep-ipynb: true was set but the fileInformationCache
missed on target.source (e.g., path normalization mismatches or
preview re-render invalidation), the else-if branch would still
delete the file. The refactored logic checks keep-ipynb first and
short-circuits before the cache lookup, so the user's explicit
keep-ipynb: true is always honored regardless of cache state.

Cache update remains an internal optimization for later project-level
cleanup — not the authoritative signal for whether to delete.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

.quarto_ipynb files not cleaned up when preview is killed ungracefully

1 participant