Skip to content

Commit 72c2360

Browse files
Support execute.cache frontmatter for notebook caching (#259)
Fixes #216.
1 parent cbdacc0 commit 72c2360

24 files changed

+334
-36
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,6 @@ Manifest.toml
88
*.jls
99
.DS_Store
1010
.CondaPkg
11+
.cache
1112
!/test/assets/*
1213
!/src/QuartoNotebookWorker/src/vendor/Manifest.toml

CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## Unreleased
99

10+
### Added
11+
12+
- Support for `execute.cache` frontmatter option, which allows notebooks to
13+
cache the output of cells and reuse them between runs. This is coarse-grained
14+
and the cache will be invalidated if any text within any executable cells is
15+
changed, if the frontmatter is changed, or if the `Project.toml` is changed.
16+
The cached output is stored in a `.cache` folder alongside the notebook where
17+
caching is enabled. Delete this folder to clear the cache. [#259]
18+
1019
## [v0.13.2] - 2025-02-24
1120

1221
### Fixed
@@ -386,5 +395,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
386395
[#253]: https://github.com/PumasAI/QuartoNotebookRunner.jl/issues/253
387396
[#255]: https://github.com/PumasAI/QuartoNotebookRunner.jl/issues/255
388397
[#257]: https://github.com/PumasAI/QuartoNotebookRunner.jl/issues/257
398+
[#259]: https://github.com/PumasAI/QuartoNotebookRunner.jl/issues/259
389399
[#262]: https://github.com/PumasAI/QuartoNotebookRunner.jl/issues/262
390400
[#265]: https://github.com/PumasAI/QuartoNotebookRunner.jl/issues/265

Project.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ BSON = "fbb218c0-5317-5bc6-957e-2ee96dd4b1f0"
88
Base64 = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f"
99
CommonMark = "a80b9123-70ca-4bc0-993e-6e3bcb318db6"
1010
Compat = "34da2185-b29b-5c13-b0c7-acf172513d20"
11+
Dates = "ade2ca70-3891-5945-98fb-dc099432e06a"
1112
IOCapture = "b5f81e59-6552-4d32-b1f0-c071b021bf89"
1213
InteractiveUtils = "b77e0a4c-d291-57a0-90e8-8db25a27a240"
1314
IterTools = "c8e1da08-722c-5040-9ed9-7db0dc04731e"
@@ -30,6 +31,7 @@ BSON = "0.3"
3031
Base64 = "1.6"
3132
CommonMark = "0.8"
3233
Compat = "4"
34+
Dates = "1.6"
3335
IOCapture = "0.2"
3436
InteractiveUtils = "1.6"
3537
IterTools = "1"

src/Malt.jl

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -81,8 +81,10 @@ mutable struct Worker <: AbstractWorker
8181
current_message_id::MsgID
8282
expected_replies::Dict{MsgID,Channel{WorkerResult}}
8383

84+
manifest_file::String
85+
8486
function Worker(; exe = Base.julia_cmd()[1], env = String[], exeflags = [])
85-
proc, port, manifest_error = mktempdir() do temp_dir
87+
proc, port, manifest_error, manifest_file = mktempdir() do temp_dir
8688
# The `errors.log` file is used by the worker process to pass back
8789
# any errors that occur during startup. This is used instead of
8890
# capturing the process's `stderr` via a pipe since we only need to
@@ -118,7 +120,7 @@ mutable struct Worker <: AbstractWorker
118120
# the worker is connected to the socket and if there is a mismatch
119121
# we call `stop` to gracefully close the worker. We cannot
120122
# gracefully close it until that point.
121-
manifest_error =
123+
manifest_file, manifest_error =
122124
_validate_worker_process_manifest(metadata_toml_file, errors_log_file)
123125

124126
if port === nothing
@@ -160,7 +162,7 @@ mutable struct Worker <: AbstractWorker
160162
end
161163
end
162164

163-
return proc, port, manifest_error
165+
return proc, port, manifest_error, manifest_file
164166
end
165167

166168
# Connect
@@ -178,6 +180,7 @@ mutable struct Worker <: AbstractWorker
178180
socket,
179181
MsgID(0),
180182
Dict{MsgID,Channel{WorkerResult}}(),
183+
manifest_file,
181184
),
182185
)
183186
atexit(() -> stop(w))
@@ -218,14 +221,15 @@ function _validate_worker_process_manifest(
218221

219222
# When there is no manifest file yet then we don't need to report any
220223
# issues since there will be no resolver issues.
221-
isfile(manifest_toml_file) || return nothing
224+
isfile(manifest_toml_file) || return "", nothing
222225

223226
manifest = TOML.parsefile(manifest_toml_file)
224227
expected_julia_version = get(manifest, "julia_version", "")
228+
project_hash = get(manifest, "project_hash", "")
225229

226230
# The older manifest format does not include the `julia_version`. For these
227231
# ones, just skip the check. To revisit if we encounter issues with this.
228-
isempty(expected_julia_version) && return nothing
232+
isempty(expected_julia_version) && return project_hash, nothing
229233

230234
if !_compare_versions(actual_julia_version, expected_julia_version)
231235
message = """
@@ -246,8 +250,9 @@ function _validate_worker_process_manifest(
246250
message *= "\nERROR: $error_output"
247251
end
248252

249-
return message
253+
return project_hash, message
250254
end
255+
return project_hash, nothing
251256
end
252257

253258
# This check needs to happen on the worker process since the hashing of the

src/QuartoNotebookRunner.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import BSON
2222
import Base64
2323
import CommonMark
2424
import Compat
25+
import Dates
2526
import InteractiveUtils
2627
import IterTools
2728
import JSON3

0 commit comments

Comments
 (0)