Fredrik Ekre 2 years ago committed by GitHub
parent
commit
361763ddee
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      .github/workflows/ci.yml
  2. 16
      CHANGELOG.md
  3. 8
      Project.toml
  4. 2
      docs/Manifest.toml
  5. 22
      src/Literate.jl
  6. 42
      test/runtests.jl

2
.github/workflows/ci.yml

@ -15,7 +15,7 @@ jobs:
strategy: strategy:
matrix: matrix:
version: version:
- '1.0' - '1.6'
- '1' - '1'
- 'nightly' - 'nightly'
os: os:

16
CHANGELOG.md

@ -7,6 +7,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
<!-- ## [Unreleased] --> <!-- ## [Unreleased] -->
## [2.16.0] - 2023-11-08
### Added
- "Soft" scoping rules (see e.g. https://github.com/JuliaLang/SoftGlobalScope.jl) are now
available for code execution (markdown and notebook output). This is enabled by default
for Jupyter notebook output (to mimic how the IJulia kernel works), and disabled
otherwise. Soft scope rules can be enabled/disabled with the `softscope :: Bool`
configuration variable. ([#227][github-227], [#230][github-230])
### Changed
- The minimum Julia version requirement for Literate >= 2.16.0 is now 1.6.0 (from 1.0.0).
([#230][github-230])
## [2.15.1] - 2023-11-08 ## [2.15.1] - 2023-11-08
### Fixed ### Fixed
- Fix a bug where `Literate.markdown` with `execute=true` would (try to) output images in - Fix a bug where `Literate.markdown` with `execute=true` would (try to) output images in
@ -266,10 +277,13 @@ https://discourse.julialang.org/t/ann-literate-jl/10651 for release announcement
[github-221]: https://github.com/fredrikekre/Literate.jl/pull/221 [github-221]: https://github.com/fredrikekre/Literate.jl/pull/221
[github-222]: https://github.com/fredrikekre/Literate.jl/issues/222 [github-222]: https://github.com/fredrikekre/Literate.jl/issues/222
[github-223]: https://github.com/fredrikekre/Literate.jl/pull/223 [github-223]: https://github.com/fredrikekre/Literate.jl/pull/223
[github-227]: https://github.com/fredrikekre/Literate.jl/issues/227
[github-228]: https://github.com/fredrikekre/Literate.jl/issues/228 [github-228]: https://github.com/fredrikekre/Literate.jl/issues/228
[github-229]: https://github.com/fredrikekre/Literate.jl/pull/229 [github-229]: https://github.com/fredrikekre/Literate.jl/pull/229
[github-230]: https://github.com/fredrikekre/Literate.jl/pull/230
[Unreleased]: https://github.com/fredrikekre/Literate.jl/compare/v2.15.1...HEAD [Unreleased]: https://github.com/fredrikekre/Literate.jl/compare/v2.16.0...HEAD
[2.16.0]: https://github.com/fredrikekre/Literate.jl/compare/v2.15.1...v2.16.0
[2.15.1]: https://github.com/fredrikekre/Literate.jl/compare/v2.15.0...v2.15.1 [2.15.1]: https://github.com/fredrikekre/Literate.jl/compare/v2.15.0...v2.15.1
[2.15.0]: https://github.com/fredrikekre/Literate.jl/compare/v2.14.2...v2.15.0 [2.15.0]: https://github.com/fredrikekre/Literate.jl/compare/v2.14.2...v2.15.0
[2.14.2]: https://github.com/fredrikekre/Literate.jl/compare/v2.14.1...v2.14.2 [2.14.2]: https://github.com/fredrikekre/Literate.jl/compare/v2.14.1...v2.14.2

8
Project.toml

@ -1,6 +1,6 @@
name = "Literate" name = "Literate"
uuid = "98b081ad-f1c9-55d3-8b20-4c87d4299306" uuid = "98b081ad-f1c9-55d3-8b20-4c87d4299306"
version = "2.15.1" version = "2.16.0"
[deps] [deps]
Base64 = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f" Base64 = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f"
@ -9,11 +9,11 @@ JSON = "682c06a0-de6a-54ab-a142-c8b1cf79cde6"
REPL = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb" REPL = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb"
[compat] [compat]
Base64 = "<0.0.1, 1" Base64 = "1"
IOCapture = "0.2" IOCapture = "0.2"
JSON = "0.18, 0.19, 0.20, 0.21, 1" JSON = "0.18, 0.19, 0.20, 0.21, 1"
REPL = "<0.0.1, 1" REPL = "1"
julia = "1" julia = "1.6"
[extras] [extras]
DisplayAs = "0b91fe84-8a4c-11e9-3e1d-67c38462b6d6" DisplayAs = "0b91fe84-8a4c-11e9-3e1d-67c38462b6d6"

2
docs/Manifest.toml

@ -420,7 +420,7 @@ uuid = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
deps = ["Base64", "IOCapture", "JSON", "REPL"] deps = ["Base64", "IOCapture", "JSON", "REPL"]
path = ".." path = ".."
uuid = "98b081ad-f1c9-55d3-8b20-4c87d4299306" uuid = "98b081ad-f1c9-55d3-8b20-4c87d4299306"
version = "2.15.1" version = "2.16.0"
[[LogExpFunctions]] [[LogExpFunctions]]
deps = ["DocStringExtensions", "IrrationalConstants", "LinearAlgebra"] deps = ["DocStringExtensions", "IrrationalConstants", "LinearAlgebra"]

22
src/Literate.jl

@ -312,6 +312,7 @@ function create_configuration(inputfile; user_config, user_kwargs, type=nothing)
cfg["flavor"] = type === (:md) ? DocumenterFlavor() : DefaultFlavor() cfg["flavor"] = type === (:md) ? DocumenterFlavor() : DefaultFlavor()
cfg["credit"] = true cfg["credit"] = true
cfg["mdstrings"] = false cfg["mdstrings"] = false
cfg["softscope"] = type === (:nb) ? true : false # on for Jupyter notebooks
cfg["keep_comments"] = false cfg["keep_comments"] = false
cfg["execute"] = type === :md ? false : true cfg["execute"] = type === :md ? false : true
cfg["codefence"] = get(user_config, "flavor", cfg["flavor"]) isa DocumenterFlavor && cfg["codefence"] = get(user_config, "flavor", cfg["flavor"]) isa DocumenterFlavor &&
@ -408,6 +409,8 @@ Available options:
- `devurl` (default: `"dev"`): URL for "in-development" docs, see [Documenter docs] - `devurl` (default: `"dev"`): URL for "in-development" docs, see [Documenter docs]
(https://juliadocs.github.io/Documenter.jl/). Unused if `repo_root_url`/ (https://juliadocs.github.io/Documenter.jl/). Unused if `repo_root_url`/
`nbviewer_root_url`/`binder_root_url` are set. `nbviewer_root_url`/`binder_root_url` are set.
- `softscope` (default: `true` for Jupyter notebooks, `false` otherwise): enable/disable
"soft" scoping rules when executing, see e.g. https://github.com/JuliaLang/SoftGlobalScope.jl.
- `repo_root_url`: URL to the root of the repository. Determined automatically on Travis CI, - `repo_root_url`: URL to the root of the repository. Determined automatically on Travis CI,
GitHub Actions and GitLab CI. Used for `@__REPO_ROOT_URL__`. GitHub Actions and GitLab CI. Used for `@__REPO_ROOT_URL__`.
- `nbviewer_root_url`: URL to the root of the repository as seen on nbviewer. Determined - `nbviewer_root_url`: URL to the root of the repository as seen on nbviewer. Determined
@ -580,6 +583,7 @@ function markdown(inputfile, outputdir=pwd(); config::AbstractDict=Dict(), kwarg
flavor=config["flavor"], flavor=config["flavor"],
image_formats=config["image_formats"], image_formats=config["image_formats"],
file_prefix="$(config["name"])-$(chunknum)", file_prefix="$(config["name"])-$(chunknum)",
softscope=config["softscope"],
) )
end end
end end
@ -597,9 +601,10 @@ end
function execute_markdown!(io::IO, sb::Module, block::String, outputdir; function execute_markdown!(io::IO, sb::Module, block::String, outputdir;
inputfile::String, fake_source::String, inputfile::String, fake_source::String,
flavor::AbstractFlavor, image_formats::Vector, file_prefix::String) flavor::AbstractFlavor, image_formats::Vector, file_prefix::String,
softscope::Bool)
# TODO: Deal with explicit display(...) calls # TODO: Deal with explicit display(...) calls
r, str, _ = execute_block(sb, block; inputfile=inputfile, fake_source=fake_source) r, str, _ = execute_block(sb, block; inputfile=inputfile, fake_source=fake_source, softscope=softscope)
# issue #101: consecutive codefenced blocks need newline # issue #101: consecutive codefenced blocks need newline
# issue #144: quadruple backticks allow for triple backticks in the output # issue #144: quadruple backticks allow for triple backticks in the output
plain_fence = "\n````\n" => "\n````" plain_fence = "\n````\n" => "\n````"
@ -734,7 +739,8 @@ function jupyter_notebook(chunks, config)
try try
cd(config["literate_outputdir"]) do cd(config["literate_outputdir"]) do
nb = execute_notebook(nb; inputfile=config["literate_inputfile"], nb = execute_notebook(nb; inputfile=config["literate_inputfile"],
fake_source=config["literate_outputfile"]) fake_source=config["literate_outputfile"],
softscope=config["softscope"])
end end
catch err catch err
@error "error when executing notebook based on input file: " * @error "error when executing notebook based on input file: " *
@ -745,7 +751,7 @@ function jupyter_notebook(chunks, config)
return nb return nb
end end
function execute_notebook(nb; inputfile::String, fake_source::String) function execute_notebook(nb; inputfile::String, fake_source::String, softscope::Bool)
sb = sandbox() sb = sandbox()
execution_count = 0 execution_count = 0
for cell in nb["cells"] for cell in nb["cells"]
@ -753,7 +759,7 @@ function execute_notebook(nb; inputfile::String, fake_source::String)
execution_count += 1 execution_count += 1
cell["execution_count"] = execution_count cell["execution_count"] = execution_count
block = join(cell["source"]) block = join(cell["source"])
r, str, display_dicts = execute_block(sb, block; inputfile=inputfile, fake_source=fake_source) r, str, display_dicts = execute_block(sb, block; inputfile=inputfile, fake_source=fake_source, softscope=softscope)
# str should go into stream # str should go into stream
if !isempty(str) if !isempty(str)
@ -835,7 +841,7 @@ function Base.display(ld::LiterateDisplay, mime::MIME, x)
end end
# Execute a code-block in a module and capture stdout/stderr and the result # Execute a code-block in a module and capture stdout/stderr and the result
function execute_block(sb::Module, block::String; inputfile::String, fake_source::String) function execute_block(sb::Module, block::String; inputfile::String, fake_source::String, softscope::Bool)
@debug """execute_block($sb, block) @debug """execute_block($sb, block)
``` ```
$(block) $(block)
@ -851,8 +857,12 @@ function execute_block(sb::Module, block::String; inputfile::String, fake_source
# `rethrow = Union{}` means that we try-catch all the exceptions thrown in the do-block # `rethrow = Union{}` means that we try-catch all the exceptions thrown in the do-block
# and return them via the return value (they get handled below). # and return them via the return value (they get handled below).
c = IOCapture.capture(rethrow = Union{}) do c = IOCapture.capture(rethrow = Union{}) do
if softscope
include_string(REPL.softscope, sb, block, fake_source)
else
include_string(sb, block, fake_source) include_string(sb, block, fake_source)
end end
end
popdisplay(disp) # IOCapture.capture has a try-catch so should always end up here popdisplay(disp) # IOCapture.capture has a try-catch so should always end up here
if c.error if c.error
error(""" error("""

42
test/runtests.jl

@ -905,6 +905,27 @@ end end
Literate.markdown(inputfile, relpath(outdir); execute=true, Literate.markdown(inputfile, relpath(outdir); execute=true,
flavor=Literate.CommonMarkFlavor()) flavor=Literate.CommonMarkFlavor())
@test read(joinpath(outdir, "inputfile-1.svg"), String) == "issue228" @test read(joinpath(outdir, "inputfile-1.svg"), String) == "issue228"
# Softscope
write(
inputfile,
"""
ret = 0
for k = 1:10
ret += k
end
println("ret = ", ret)
"""
)
Literate.markdown(inputfile, outdir; execute=true, softscope=true)
@test occursin("ret = 55", read(joinpath(outdir, "inputfile.md"), String))
## Disabled softscope
try
Literate.markdown(inputfile, outdir; execute=true, softscope=false)
error("unreachable")
catch err
@test occursin(r"`?ret`? not defined", sprint(Base.showerror, err))
end
end # cd(sandbox) end # cd(sandbox)
end # mktemp end # mktemp
end end end end
@ -1319,8 +1340,29 @@ end end
@test keys(cellout[1]["data"]) == Set(("text/latex",)) @test keys(cellout[1]["data"]) == Set(("text/latex",))
@test cellout[1]["data"]["text/latex"] == "DF(4) as text/latex" @test cellout[1]["data"]["text/latex"] == "DF(4) as text/latex"
@test !haskey(cellout[1], "execution_count") @test !haskey(cellout[1], "execution_count")
# Softscope
write(
inputfile,
"""
ret = 0
for k = 1:10
ret += k
end end
println("ret = ", ret)
"""
)
Literate.notebook(inputfile, outdir)
@test occursin("ret = 55", read(joinpath(outdir, "inputfile.ipynb"), String))
## Disabled softscope
try
Literate.notebook(inputfile, outdir; softscope=false)
error("unreachable")
catch err
@test occursin(r"`?ret`? not defined", sprint(Base.showerror, err))
end end
end # cd(sandbox)
end # mktempdir
end end end end
@testset "Configuration" begin; Base.CoreLogging.with_logger(Base.CoreLogging.NullLogger()) do @testset "Configuration" begin; Base.CoreLogging.with_logger(Base.CoreLogging.NullLogger()) do

Loading…
Cancel
Save