Skip to content

Commit dd24d1f

Browse files
authored
Merge pull request #12793 from quarto-dev/fix/keep-ipynb
Handle keep-ipynb correctly now that fileInformationCache is responsible for the cleaning
2 parents 7e98950 + f553f90 commit dd24d1f

File tree

13 files changed

+87
-21
lines changed

13 files changed

+87
-21
lines changed

news/changelog-1.8.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ All changes included in 1.8:
55
- ([#6607](https://github.com/quarto-dev/quarto-cli/issues/6607)): Add missing beamer template update for beamer theme options: `colorthemeoptions`, `fontthemeoptions`, `innerthemeoptions` and `outerthemeoptions`.
66
- ([#12625](https://github.com/quarto-dev/quarto-cli/pull/12625)): Fire resize event on window when light/dark toggle is clicked, to tell widgets to resize.
77
- ([#12657](https://github.com/quarto-dev/quarto-cli/pull/12657)): Load Giscus in generated script tag, to avoid wrong-theming in Chrome.
8+
- ([#12780](https://github.com/quarto-dev/quarto-cli/issues/12780)): `keep-ipynb: true` now works again correctly and intermediate `.quarto_ipynb` is not removed.
89

910
## Formats
1011

@@ -63,4 +64,4 @@ All changes included in 1.8:
6364
## Other fixes and improvements
6465

6566
- ([#11321](https://github.com/quarto-dev/quarto-cli/issues/11321)): Follow [recommendation from LaTeX project](https://latex-project.org/news/latex2e-news/ltnews40.pdf) and use `lualatex` instead of `xelatex` as the default PDF engine.
66-
- ([#12782](https://github.com/quarto-dev/quarto-cli/pull/12782)): fix bug on `safeRemoveDirSync`'s detection of safe directory boundaries.
67+
- ([#12782](https://github.com/quarto-dev/quarto-cli/pull/12782)): fix bug on `safeRemoveDirSync`'s detection of safe directory boundaries.

src/command/render/render-contexts.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -63,16 +63,13 @@ import { ExecutionEngine, ExecutionTarget } from "../../execute/types.ts";
6363
import {
6464
deleteProjectMetadata,
6565
directoryMetadataForInputFile,
66-
projectTypeIsWebsite,
6766
toInputRelativePaths,
6867
} from "../../project/project-shared.ts";
6968
import {
7069
kProjectLibDir,
7170
kProjectType,
7271
ProjectContext,
7372
} from "../../project/types.ts";
74-
import { isHtmlDashboardOutput, isHtmlOutput } from "../../config/format.ts";
75-
import { formatHasBootstrap } from "../../format/html/format-html-info.ts";
7673
import { warnOnce } from "../../core/log.ts";
7774
import { dirAndStem } from "../../core/path.ts";
7875
import { fileExecutionEngineAndTarget } from "../../execute/engine.ts";
@@ -298,7 +295,7 @@ export async function renderContexts(
298295

299296
// if this isn't for execute then cleanup context
300297
if (!forExecute && engine.executeTargetSkipped) {
301-
engine.executeTargetSkipped(target, formats[formatKey].format);
298+
engine.executeTargetSkipped(target, formats[formatKey].format, project);
302299
}
303300
}
304301
return contexts;

src/command/render/render-files.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,11 @@ export async function renderExecute(
200200

201201
// notify engine that we skipped execute
202202
if (context.engine.executeTargetSkipped) {
203-
context.engine.executeTargetSkipped(context.target, context.format);
203+
context.engine.executeTargetSkipped(
204+
context.target,
205+
context.format,
206+
context.project,
207+
);
204208
}
205209

206210
// return results

src/core/jupyter/jupyter-embed.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,13 @@ import {
4343
JupyterCellOutput,
4444
} from "../jupyter/types.ts";
4545

46-
import { dirname, extname, join, basename, isAbsolute } from "../../deno_ral/path.ts";
46+
import {
47+
basename,
48+
dirname,
49+
extname,
50+
isAbsolute,
51+
join,
52+
} from "../../deno_ral/path.ts";
4753
import { languages } from "../handlers/base.ts";
4854
import {
4955
extractJupyterWidgetDependencies,
@@ -596,6 +602,7 @@ async function getCachedNotebookInfo(
596602
quiet: flags.quiet,
597603
previewServer: context.options.previewServer,
598604
handledLanguages: languages(),
605+
project: context.project,
599606
};
600607

601608
const [dir, stem] = dirAndStem(nbAddress.path);

src/execute/jupyter/jupyter.ts

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import { readYamlFromMarkdown } from "../../core/yaml.ts";
1717
import { isInteractiveSession } from "../../core/platform.ts";
1818
import { partitionMarkdown } from "../../core/pandoc/pandoc-partition.ts";
1919

20-
import { dirAndStem, normalizePath, removeIfExists } from "../../core/path.ts";
20+
import { dirAndStem, normalizePath } from "../../core/path.ts";
2121
import { runningInCI } from "../../core/ci-info.ts";
2222

2323
import {
@@ -109,7 +109,10 @@ import {
109109
import { jupyterCapabilities } from "../../core/jupyter/capabilities.ts";
110110
import { runExternalPreviewServer } from "../../preview/preview-server.ts";
111111
import { onCleanup } from "../../core/cleanup.ts";
112-
import { projectOutputDir } from "../../project/project-shared.ts";
112+
import {
113+
ensureFileInformationCache,
114+
projectOutputDir,
115+
} from "../../project/project-shared.ts";
113116
import { assert } from "testing/asserts";
114117

115118
export const jupyterEngine: ExecutionEngine = {
@@ -436,7 +439,7 @@ export const jupyterEngine: ExecutionEngine = {
436439

437440
// if it's a transient notebook then remove it
438441
// (unless keep-ipynb was specified)
439-
cleanupNotebook(options.target, options.format);
442+
cleanupNotebook(options.target, options.format, options.project);
440443

441444
// Create markdown from the result
442445
const outputs = result.cellOutputs.map((output) => output.markdown);
@@ -713,12 +716,17 @@ async function disableDaemonForNotebook(target: ExecutionTarget) {
713716
return false;
714717
}
715718

716-
function cleanupNotebook(target: ExecutionTarget, format: Format) {
717-
// remove transient notebook if appropriate
719+
function cleanupNotebook(
720+
target: ExecutionTarget,
721+
format: Format,
722+
project: ProjectContext,
723+
) {
724+
// Make notebook non-transient when keep-ipynb is set
718725
const data = target.data as JupyterTargetData;
719-
if (data.transient) {
720-
if (!format.execute[kKeepIpynb]) {
721-
removeIfExists(target.input);
726+
const cached = ensureFileInformationCache(project, target.source);
727+
if (data.transient && format.execute[kKeepIpynb]) {
728+
if (cached.target && cached.target.data) {
729+
(cached.target.data as JupyterTargetData).transient = false;
722730
}
723731
}
724732
}

src/execute/types.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,11 @@ export interface ExecutionEngine {
4949
format: Format,
5050
) => Format;
5151
execute: (options: ExecuteOptions) => Promise<ExecuteResult>;
52-
executeTargetSkipped?: (target: ExecutionTarget, format: Format) => void;
52+
executeTargetSkipped?: (
53+
target: ExecutionTarget,
54+
format: Format,
55+
project: ProjectContext,
56+
) => void;
5357
dependencies: (options: DependenciesOptions) => Promise<DependenciesResult>;
5458
postprocess: (options: PostProcessOptions) => Promise<void>;
5559
canFreeze: boolean;
@@ -89,7 +93,7 @@ export interface ExecuteOptions {
8993
quiet?: boolean;
9094
previewServer?: boolean;
9195
handledLanguages: string[]; // list of languages handled by cell language handlers, after the execution engine
92-
project?: ProjectContext;
96+
project: ProjectContext;
9397
}
9498

9599
// result of execution

src/project/project-context.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ import { projectResourceFiles } from "./project-resources.ts";
7070

7171
import {
7272
cleanupFileInformationCache,
73+
FileInformationCacheMap,
7374
ignoreFieldsForProjectType,
7475
normalizeFormatYaml,
7576
projectConfigFile,
@@ -272,7 +273,7 @@ export async function projectContext(
272273
dir: join(dir, ".quarto"),
273274
prefix: "quarto-session-temp",
274275
});
275-
const fileInformationCache = new Map();
276+
const fileInformationCache = new FileInformationCacheMap();
276277
const result: ProjectContext = {
277278
resolveBrand: async (fileName?: string) =>
278279
projectResolveBrand(result, fileName),
@@ -368,7 +369,7 @@ export async function projectContext(
368369
dir: join(dir, ".quarto"),
369370
prefix: "quarto-session-temp",
370371
});
371-
const fileInformationCache = new Map();
372+
const fileInformationCache = new FileInformationCacheMap();
372373
const result: ProjectContext = {
373374
resolveBrand: async (fileName?: string) =>
374375
projectResolveBrand(result, fileName),
@@ -443,7 +444,7 @@ export async function projectContext(
443444
dir: join(originalDir, ".quarto"),
444445
prefix: "quarto-session-temp",
445446
});
446-
const fileInformationCache = new Map();
447+
const fileInformationCache = new FileInformationCacheMap();
447448
const context: ProjectContext = {
448449
resolveBrand: async (fileName?: string) =>
449450
projectResolveBrand(context, fileName),

src/project/project-shared.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ import { refSchema } from "../core/lib/yaml-schema/common.ts";
5050
import { Zod } from "../resources/types/zod/schema-types.ts";
5151
import { Brand } from "../core/brand/brand.ts";
5252
import { assert } from "testing/asserts";
53+
import { Cloneable } from "../core/safe-clone-deep.ts";
5354

5455
export function projectExcludeDirs(context: ProjectContext): string[] {
5556
const outputDir = projectOutputDir(context);
@@ -633,6 +634,15 @@ export async function projectResolveBrand(
633634
}
634635
}
635636

637+
// Create a class that extends Map and implements Cloneable
638+
export class FileInformationCacheMap extends Map<string, FileInformation>
639+
implements Cloneable<Map<string, FileInformation>> {
640+
clone(): Map<string, FileInformation> {
641+
// Return the same instance (reference) instead of creating a clone
642+
return this;
643+
}
644+
}
645+
636646
export function cleanupFileInformationCache(project: ProjectContext) {
637647
project.fileInformationCache.forEach((entry) => {
638648
if (entry?.target?.data) {

src/project/types/single-file/single-file.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import { MappedString } from "../../../core/mapped-text.ts";
2121
import { fileExecutionEngineAndTarget } from "../../../execute/engine.ts";
2222
import {
2323
cleanupFileInformationCache,
24+
FileInformationCacheMap,
2425
projectFileMetadata,
2526
projectResolveBrand,
2627
projectResolveFullMarkdownForFile,
@@ -49,7 +50,7 @@ export async function singleFileProjectContext(
4950
notebookContext,
5051
environment: () => environmentMemoizer(result),
5152
renderFormats,
52-
fileInformationCache: new Map(),
53+
fileInformationCache: new FileInformationCacheMap(),
5354
fileExecutionEngineAndTarget: (
5455
file: string,
5556
) => {
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/.quarto/
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
---
2+
format: html
3+
keep-ipynb: true
4+
_quarto:
5+
tests:
6+
html:
7+
fileExists:
8+
outputPath: 12780.quarto_ipynb
9+
postRenderCleanup:
10+
- ${input_stem}.quarto_ipynb
11+
---
12+
13+
```{python}
14+
1 + 1
15+
```
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
project:
2+
type: default
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
---
2+
format: html
3+
keep-ipynb: true
4+
_quarto:
5+
tests:
6+
html:
7+
fileExists:
8+
outputPath: 12780.quarto_ipynb
9+
postRenderCleanup:
10+
- ${input_stem}.quarto_ipynb
11+
---
12+
13+
```{python}
14+
1 + 1
15+
```

0 commit comments

Comments
 (0)