From 11878230a70d31d230216549c04c4af473b5dc94 Mon Sep 17 00:00:00 2001 From: Hong Ge Date: Wed, 24 Jun 2026 08:44:40 +0100 Subject: [PATCH] Make the Colab notebook self-contained: download helper files, install all deps The trend-inflation example includes utilities.jl and reads data.csv, which aren't present on Colab. Add a notebook-only (#nb) block to script.jl that downloads them and points INFL_PATH at the working dir; the docs build keeps its hidden repo-relative setup. In the notebook postprocess, strip Literate `#hide` lines (which otherwise leak the docs-only repo paths into the notebook), and derive Pkg.add from the example's Project.toml deps so packages used only by included files (CSV, CairoMakie, ...) are installed too. Co-Authored-By: Claude Opus 4.8 (1M context) --- GeneralisedFilters/docs/literate.jl | 30 +++++++++---------- .../examples/trend-inflation/script.jl | 9 +++++- SSMProblems/docs/literate.jl | 30 +++++++++---------- 3 files changed, 36 insertions(+), 33 deletions(-) diff --git a/GeneralisedFilters/docs/literate.jl b/GeneralisedFilters/docs/literate.jl index 1fd8c921..abee89f3 100644 --- a/GeneralisedFilters/docs/literate.jl +++ b/GeneralisedFilters/docs/literate.jl @@ -55,29 +55,27 @@ end const SCRIPTJL = joinpath(EXAMPLEPATH, "script.jl") -# Top-level `using`/`import` package names, so the notebook can install them on Colab. -function script_packages(path) - pkgs = String[] - for line in eachline(path) - m = match(r"^\s*(?:using|import)\s+(.+)", line) - m === nothing && continue - for part in split(first(split(m.captures[1], ':')), ',') - token = first(split(strip(part), r"\s+as\s+")) - name = strip(first(split(token, '.'))) - isempty(name) || name in pkgs || push!(pkgs, String(name)) - end - end - return sort(pkgs) +# The example's declared dependencies (Literate is build-only), so the notebook can install +# everything it needs on Colab — including packages used only by included helper files. +function example_packages() + deps = get(Pkg.TOML.parsefile(joinpath(EXAMPLEPATH, "Project.toml")), "deps", Dict()) + return sort(filter(!=("Literate"), collect(keys(deps)))) end # Notebook postprocess: use a generic Julia kernel (so Colab picks its default Julia -# runtime, with no pinned version) and prepend a single Pkg.add for all imported packages -# so the notebook runs on a fresh Colab runtime. +# runtime, with no pinned version) and prepend a single Pkg.add for the example's +# dependencies so the notebook runs on a fresh Colab runtime. function prepare_notebook(nb) nb["metadata"]["kernelspec"] = Dict( "display_name" => "Julia", "language" => "julia", "name" => "julia" ) - packages = script_packages(SCRIPTJL) + # `#hide` is a Documenter-only directive that Literate leaves in the notebook; drop + # those lines (e.g. the repo-relative paths that only work during the docs build). + for cell in nb["cells"] + cell["cell_type"] == "code" || continue + cell["source"] = filter(line -> !endswith(rstrip(line), "#hide"), cell["source"]) + end + packages = example_packages() if !isempty(packages) setup = Dict( "cell_type" => "code", diff --git a/GeneralisedFilters/examples/trend-inflation/script.jl b/GeneralisedFilters/examples/trend-inflation/script.jl index 126db1db..966c8e44 100644 --- a/GeneralisedFilters/examples/trend-inflation/script.jl +++ b/GeneralisedFilters/examples/trend-inflation/script.jl @@ -15,8 +15,15 @@ using PDMats const GF = GeneralisedFilters INFL_PATH = joinpath(@__DIR__, "..", "..", "..", "examples", "trend-inflation"); #hide -# INFL_PATH = joinpath(@__DIR__) include(joinpath(INFL_PATH, "utilities.jl")); #hide +#nb # Download the helper script and data so the notebook is self-contained on Colab: +#nb using Downloads +#nb INFL_URL = "https://raw.githubusercontent.com/TuringLang/SSMProblems.jl/main/GeneralisedFilters/examples/trend-inflation" +#nb for f in ("utilities.jl", "data.csv") +#nb isfile(f) || Downloads.download("$(INFL_URL)/$(f)", f) +#nb end +#nb INFL_PATH = pwd() +#nb include(joinpath(INFL_PATH, "utilities.jl")) # ## Model Definition diff --git a/SSMProblems/docs/literate.jl b/SSMProblems/docs/literate.jl index f985ba18..cc1196b3 100644 --- a/SSMProblems/docs/literate.jl +++ b/SSMProblems/docs/literate.jl @@ -54,29 +54,27 @@ end const SCRIPTJL = joinpath(EXAMPLEPATH, "script.jl") -# Top-level `using`/`import` package names, so the notebook can install them on Colab. -function script_packages(path) - pkgs = String[] - for line in eachline(path) - m = match(r"^\s*(?:using|import)\s+(.+)", line) - m === nothing && continue - for part in split(first(split(m.captures[1], ':')), ',') - token = first(split(strip(part), r"\s+as\s+")) - name = strip(first(split(token, '.'))) - isempty(name) || name in pkgs || push!(pkgs, String(name)) - end - end - return sort(pkgs) +# The example's declared dependencies (Literate is build-only), so the notebook can install +# everything it needs on Colab — including packages used only by included helper files. +function example_packages() + deps = get(Pkg.TOML.parsefile(joinpath(EXAMPLEPATH, "Project.toml")), "deps", Dict()) + return sort(filter(!=("Literate"), collect(keys(deps)))) end # Notebook postprocess: use a generic Julia kernel (so Colab picks its default Julia -# runtime, with no pinned version) and prepend a single Pkg.add for all imported packages -# so the notebook runs on a fresh Colab runtime. +# runtime, with no pinned version) and prepend a single Pkg.add for the example's +# dependencies so the notebook runs on a fresh Colab runtime. function prepare_notebook(nb) nb["metadata"]["kernelspec"] = Dict( "display_name" => "Julia", "language" => "julia", "name" => "julia" ) - packages = script_packages(SCRIPTJL) + # `#hide` is a Documenter-only directive that Literate leaves in the notebook; drop + # those lines (e.g. the repo-relative paths that only work during the docs build). + for cell in nb["cells"] + cell["cell_type"] == "code" || continue + cell["source"] = filter(line -> !endswith(rstrip(line), "#hide"), cell["source"]) + end + packages = example_packages() if !isempty(packages) setup = Dict( "cell_type" => "code",