Browse Source

Formatted

pull/200/head
J S 3 years ago
parent
commit
fa050c7863
  1. 23
      docs/make.jl
  2. 4
      docs/src/outputformats.jl
  3. 2
      examples/README.jl
  4. 6
      examples/example.jl
  5. 7
      src/IJulia.jl
  6. 225
      src/Literate.jl
  7. 623
      test/runtests.jl

23
docs/make.jl

@ -5,7 +5,11 @@ if haskey(ENV, "GITHUB_ACTIONS") @@ -5,7 +5,11 @@ if haskey(ENV, "GITHUB_ACTIONS")
end
deployconfig = Documenter.auto_detect_deploy_system()
Documenter.post_status(deployconfig; type="pending", repo="github.com/fredrikekre/Literate.jl.git")
Documenter.post_status(
deployconfig;
type = "pending",
repo = "github.com/fredrikekre/Literate.jl.git",
)
using Literate
using Plots # to not capture precompilation output
@ -14,7 +18,7 @@ EXAMPLE = joinpath(@__DIR__, "..", "examples", "example.jl") @@ -14,7 +18,7 @@ EXAMPLE = joinpath(@__DIR__, "..", "examples", "example.jl")
OUTPUT = joinpath(@__DIR__, "src/generated")
function preprocess(str)
str = replace(str, "x = 123" => "y = 321"; count=1)
str = replace(str, "x = 123" => "y = 321"; count = 1)
return str
end
@ -23,7 +27,12 @@ Literate.notebook(EXAMPLE, OUTPUT, preprocess = preprocess) @@ -23,7 +27,12 @@ Literate.notebook(EXAMPLE, OUTPUT, preprocess = preprocess)
Literate.script(EXAMPLE, OUTPUT, preprocess = preprocess)
# generate the example notebook for the documentation, keep in sync with outputformats.md
Literate.markdown(joinpath(@__DIR__, "src/outputformats.jl"), OUTPUT; credit = false, name = "name")
Literate.markdown(
joinpath(@__DIR__, "src/outputformats.jl"),
OUTPUT;
credit = false,
name = "name",
)
Literate.notebook(joinpath(@__DIR__, "src/outputformats.jl"), OUTPUT; name = "notebook")
Literate.script(joinpath(@__DIR__, "src/outputformats.jl"), OUTPUT; credit = false)
@ -41,7 +50,10 @@ if haskey(ENV, "GITHUB_ACTIONS") @@ -41,7 +50,10 @@ if haskey(ENV, "GITHUB_ACTIONS")
end
url = "https://nbviewer.jupyter.org/github/fredrikekre/Literate.jl/blob/gh-pages/$(folder)/"
str = read(joinpath(@__DIR__, "src/outputformats.md"), String)
str = replace(str, "[notebook.ipynb](generated/notebook.ipynb)." => "[notebook.ipynb]($(url)generated/notebook.ipynb).")
str = replace(
str,
"[notebook.ipynb](generated/notebook.ipynb)." => "[notebook.ipynb]($(url)generated/notebook.ipynb).",
)
write(joinpath(@__DIR__, "src/outputformats.md"), str)
end
@ -61,7 +73,8 @@ makedocs( @@ -61,7 +73,8 @@ makedocs(
"customprocessing.md",
"documenter.md",
"tips.md",
"generated/example.md"]
"generated/example.md",
],
)
deploydocs(

4
docs/src/outputformats.jl

@ -3,9 +3,9 @@ @@ -3,9 +3,9 @@
# In julia rational numbers can be constructed with the `//` operator.
# Lets define two rational numbers, `x` and `y`:
x = 1//3
x = 1 // 3
#-
y = 2//5
y = 2 // 5
# When adding `x` and `y` together we obtain a new rational number:

2
examples/README.jl

@ -20,7 +20,7 @@ @@ -20,7 +20,7 @@
# running these commands from the package root of Literate.jl:
using Literate
Literate.markdown("examples/README.jl", "."; flavor=Literate.CommonMarkFlavor())
Literate.markdown("examples/README.jl", "."; flavor = Literate.CommonMarkFlavor())
# [docs-img]: https://img.shields.io/badge/docs-latest%20release-blue.svg
# [docs-url]: https://fredrikekre.github.io/Literate.jl/

6
examples/example.jl

@ -33,8 +33,8 @@ @@ -33,8 +33,8 @@
# as markdown, and all the other lines are interpreted as code. Here is some code:
#nb %% A slide [code] {"slideshow": {"slide_type": "fragment"}}
x = 1//3
y = 2//5
x = 1 // 3
y = 2 // 5
#nb # %% A slide [markdown] {"slideshow": {"slide_type": "subslide"}}
# In markdown sections we can use markdown syntax. For example, we can
@ -96,7 +96,7 @@ foo() @@ -96,7 +96,7 @@ foo()
#nb %% A slide [code] {"slideshow": {"slide_type": "subslide"}}
using Plots
x = range(0, stop=6π, length=1000)
x = range(0, stop = 6π, length = 1000)
y1 = sin.(x)
y2 = cos.(x)
plot(x, [y1, y2])

7
src/IJulia.jl

@ -19,7 +19,8 @@ const application_vnd_vegalite_v2 = MIME("application/vnd.vegalite.v2+json") @@ -19,7 +19,8 @@ const application_vnd_vegalite_v2 = MIME("application/vnd.vegalite.v2+json")
function display_dict(x)
data = Dict{String,Any}("text/plain" => limitstringmime(text_plain, x))
if showable(application_vnd_vegalite_v2, x)
data[string(application_vnd_vegalite_v2)] = JSON.parse(limitstringmime(application_vnd_vegalite_v2, x))
data[string(application_vnd_vegalite_v2)] =
JSON.parse(limitstringmime(application_vnd_vegalite_v2, x))
end
if showable(image_svg, x)
data[string(image_svg)] = limitstringmime(image_svg, x)
@ -57,14 +58,14 @@ function limitstringmime(mime::MIME, x) @@ -57,14 +58,14 @@ function limitstringmime(mime::MIME, x)
if israwtext(mime, x)
return String(x)
else
show(IOContext(buf, :limit=>true, :color=>true), mime, x)
show(IOContext(buf, :limit => true, :color => true), mime, x)
end
else
b64 = Base64EncodePipe(buf)
if isa(x, Vector{UInt8})
write(b64, x) # x assumed to be raw binary data
else
show(IOContext(b64, :limit=>true, :color=>true), mime, x)
show(IOContext(b64, :limit => true, :color => true), mime, x)
end
close(b64)
end

225
src/Literate.jl

@ -44,7 +44,9 @@ mutable struct CodeChunk <: Chunk @@ -44,7 +44,9 @@ mutable struct CodeChunk <: Chunk
end
CodeChunk() = CodeChunk(String[], false)
ismdline(line) = (occursin(r"^\h*#$", line) || occursin(r"^\h*# .*$", line)) && !occursin(r"^\h*##", line)
ismdline(line) =
(occursin(r"^\h*#$", line) || occursin(r"^\h*# .*$", line)) &&
!occursin(r"^\h*##", line)
function parse(content; allow_continued = true)
lines = collect(eachline(IOBuffer(content)))
@ -78,7 +80,10 @@ function parse(content; allow_continued = true) @@ -78,7 +80,10 @@ function parse(content; allow_continued = true)
end
# remove "## " and "##\n", strip the leading "#" from "## xyz" and "##| xyz"
# Note: accepts only standard space character (not no-break space U+00A0)
line = replace(replace(line, r"^(\h*)#(#(:? |\|).*)$" => s"\1\2"), r"^(\h*#)#$" => s"\1")
line = replace(
replace(line, r"^(\h*)#(#(:? |\|).*)$" => s"\1\2"),
r"^(\h*#)#$" => s"\1",
)
push!(chunks[end].lines, line)
end
end
@ -108,7 +113,10 @@ function parse(content; allow_continued = true) @@ -108,7 +113,10 @@ function parse(content; allow_continued = true)
append!(merged_chunks[end].lines, chunk.lines)
else # need to put back "#"
for line in chunk.lines
push!(merged_chunks[end].lines, rstrip(line.first * "# " * line.second))
push!(
merged_chunks[end].lines,
rstrip(line.first * "# " * line.second),
)
end
end
else
@ -124,11 +132,7 @@ function parse(content; allow_continued = true) @@ -124,11 +132,7 @@ function parse(content; allow_continued = true)
return chunks
end
function replace_default(content, sym;
config::Dict,
branch = "gh-pages",
commit = "master"
)
function replace_default(content, sym; config::Dict, branch = "gh-pages", commit = "master")
repls = Pair{Any,Any}[]
# add some shameless advertisement
@ -159,7 +163,7 @@ function replace_default(content, sym; @@ -159,7 +163,7 @@ function replace_default(content, sym;
newlines = sprint() do io
foreach(l -> println(io, "# ", l), eachline(IOBuffer(m[1])))
end
str = replace(str, multiline_r => chop(newlines); count=1)
str = replace(str, multiline_r => chop(newlines); count = 1)
end
return str
end
@ -199,12 +203,16 @@ function replace_default(content, sym; @@ -199,12 +203,16 @@ function replace_default(content, sym;
# fix links
if get(ENV, "DOCUMENTATIONGENERATOR", "") == "true"
## DocumentationGenerator.jl
base_url = get(ENV, "DOCUMENTATIONGENERATOR_BASE_URL", "DOCUMENTATIONGENERATOR_BASE_URL")
base_url =
get(ENV, "DOCUMENTATIONGENERATOR_BASE_URL", "DOCUMENTATIONGENERATOR_BASE_URL")
nbviewer_root_url = "https://nbviewer.jupyter.org/urls/$(base_url)"
push!(repls, "@__NBVIEWER_ROOT_URL__" => nbviewer_root_url)
else
push!(repls, "@__REPO_ROOT_URL__" => get(config, "repo_root_url", "<unknown>"))
push!(repls, "@__NBVIEWER_ROOT_URL__" => get(config, "nbviewer_root_url", "<unknown>"))
push!(
repls,
"@__NBVIEWER_ROOT_URL__" => get(config, "nbviewer_root_url", "<unknown>"),
)
push!(repls, "@__BINDER_ROOT_URL__" => get(config, "binder_root_url", "<unknown>"))
end
@ -227,8 +235,11 @@ end @@ -227,8 +235,11 @@ end
filename(str) = first(splitext(last(splitdir(str))))
isdocumenter(cfg) = cfg["flavor"]::AbstractFlavor isa DocumenterFlavor
_DEFAULT_IMAGE_FORMATS = [(MIME("image/svg+xml"), ".svg"), (MIME("image/png"), ".png"),
(MIME("image/jpeg"), ".jpeg")]
_DEFAULT_IMAGE_FORMATS = [
(MIME("image/svg+xml"), ".svg"),
(MIME("image/png"), ".png"),
(MIME("image/jpeg"), ".jpeg"),
]
# Cache of inputfile => head branch
const HEAD_BRANCH_CACHE = Dict{String,String}()
@ -245,9 +256,9 @@ function edit_commit(inputfile, user_config) @@ -245,9 +256,9 @@ function edit_commit(inputfile, user_config)
git_root = try
readchomp(
pipeline(
setenv(`$(git) rev-parse --show-toplevel`; dir=dirname(inputfile));
stderr=devnull,
)
setenv(`$(git) rev-parse --show-toplevel`; dir = dirname(inputfile));
stderr = devnull,
),
)
catch
end
@ -266,8 +277,8 @@ function edit_commit(inputfile, user_config) @@ -266,8 +277,8 @@ function edit_commit(inputfile, user_config)
str = try
read(
pipeline(
setenv(`$(git) remote show origin`, env; dir=dirname(inputfile)),
stderr=devnull,
setenv(`$(git) remote show origin`, env; dir = dirname(inputfile)),
stderr = devnull,
),
String,
)
@ -283,16 +294,20 @@ function edit_commit(inputfile, user_config) @@ -283,16 +294,20 @@ function edit_commit(inputfile, user_config)
end
# Default to DefaultFlavor() setting
pick_codefence(flavor::AbstractFlavor,execute::Bool,name::AbstractString)=pick_codefence(DefaultFlavor(),execute,name)
pick_codefence(flavor::DefaultFlavor,execute::Bool,name::AbstractString)=("````julia" => "````")
pick_codefence(flavor::DocumenterFlavor,execute::Bool,name::AbstractString)=(execute ?
pick_codefence(DefaultFlavor(),execute,name) : ("````@example $(name)" => "````")
pick_codefence(flavor::AbstractFlavor, execute::Bool, name::AbstractString) =
pick_codefence(DefaultFlavor(), execute, name)
pick_codefence(flavor::DefaultFlavor, execute::Bool, name::AbstractString) =
("````julia" => "````")
pick_codefence(flavor::DocumenterFlavor, execute::Bool, name::AbstractString) = (
execute ? pick_codefence(DefaultFlavor(), execute, name) :
("````@example $(name)" => "````")
)
pick_codefence(flavor::QuartoFlavor,execute::Bool,name::AbstractString)=(execute ?
error("QuartoFlavor does not support argument execute=true!") : ("```{julia}" => "```")
pick_codefence(flavor::QuartoFlavor, execute::Bool, name::AbstractString) = (
execute ? error("QuartoFlavor does not support argument execute=true!") :
("```{julia}" => "```")
)
function create_configuration(inputfile; user_config, user_kwargs, type=nothing)
function create_configuration(inputfile; user_config, user_kwargs, type = nothing)
# Combine user config with user kwargs
user_config = Dict{String,Any}(string(k) => v for (k, v) in user_config)
user_kwargs = Dict{String,Any}(string(k) => v for (k, v) in user_kwargs)
@ -301,16 +316,25 @@ function create_configuration(inputfile; user_config, user_kwargs, type=nothing) @@ -301,16 +316,25 @@ function create_configuration(inputfile; user_config, user_kwargs, type=nothing)
# deprecation of documenter kwarg
if (d = get(user_config, "documenter", nothing); d !== nothing)
if type === :md
Base.depwarn("The documenter=$(d) keyword to Literate.markdown is deprecated." *
Base.depwarn(
"The documenter=$(d) keyword to Literate.markdown is deprecated." *
" Pass `flavor = Literate.$(d ? "DocumenterFlavor" : "CommonMarkFlavor")()`" *
" instead.", Symbol("Literate.markdown"))
" instead.",
Symbol("Literate.markdown"),
)
user_config["flavor"] = d ? DocumenterFlavor() : CommonMarkFlavor()
elseif type === :nb
Base.depwarn("The documenter=$(d) keyword to Literate.notebook is deprecated." *
" It is not used anymore for notebook output.", Symbol("Literate.notebook"))
Base.depwarn(
"The documenter=$(d) keyword to Literate.notebook is deprecated." *
" It is not used anymore for notebook output.",
Symbol("Literate.notebook"),
)
elseif type === :jl
Base.depwarn("The documenter=$(d) keyword to Literate.script is deprecated." *
" It is not used anymore for script output.", Symbol("Literate.script"))
Base.depwarn(
"The documenter=$(d) keyword to Literate.script is deprecated." *
" It is not used anymore for script output.",
Symbol("Literate.script"),
)
end
end
@ -327,7 +351,7 @@ function create_configuration(inputfile; user_config, user_kwargs, type=nothing) @@ -327,7 +351,7 @@ function create_configuration(inputfile; user_config, user_kwargs, type=nothing)
cfg["codefence"] = pick_codefence(
get(user_config, "flavor", cfg["flavor"]),
get(user_config, "execute", cfg["execute"]),
get(user_config, "name", replace(cfg["name"], r"\s" => "_"))
get(user_config, "name", replace(cfg["name"], r"\s" => "_")),
)
cfg["image_formats"] = _DEFAULT_IMAGE_FORMATS
cfg["edit_commit"] = edit_commit(inputfile, user_config)
@ -367,7 +391,8 @@ function create_configuration(inputfile; user_config, user_kwargs, type=nothing) @@ -367,7 +391,8 @@ function create_configuration(inputfile; user_config, user_kwargs, type=nothing)
else
get(user_config, "devurl", "dev")
end
elseif (m = match(r"refs\/pull\/(\d+)\/merge", get(ENV, "GITHUB_REF", ""))) !== nothing
elseif (m = match(r"refs\/pull\/(\d+)\/merge", get(ENV, "GITHUB_REF", ""))) !==
nothing
"previews/PR$(m.captures[1])"
else
"dev"
@ -443,12 +468,16 @@ Available options: @@ -443,12 +468,16 @@ Available options:
`$(_DEFAULT_IMAGE_FORMATS)`. Results which are `showable` with a MIME type are saved with
the first match, with the corresponding extension.
"""
const DEFAULT_CONFIGURATION=nothing # Dummy const for documentation
const DEFAULT_CONFIGURATION = nothing # Dummy const for documentation
function preprocessor(inputfile, outputdir; user_config, user_kwargs, type)
# Create configuration by merging default and userdefined
config = create_configuration(inputfile; user_config=user_config,
user_kwargs=user_kwargs, type=type)
config = create_configuration(
inputfile;
user_config = user_config,
user_kwargs = user_kwargs,
type = type,
)
# normalize paths
inputfile = normpath(inputfile)
@ -457,15 +486,21 @@ function preprocessor(inputfile, outputdir; user_config, user_kwargs, type) @@ -457,15 +486,21 @@ function preprocessor(inputfile, outputdir; user_config, user_kwargs, type)
mkpath(outputdir)
outputdir = realpath(abspath(outputdir))
isdir(outputdir) || error("not a directory: $(outputdir)")
ext = type === (:nb) ? ".ipynb" : (type === (:md) && config["flavor"] isa QuartoFlavor) ? ".qmd" : ".$(type)"
ext =
type === (:nb) ? ".ipynb" :
(type === (:md) && config["flavor"] isa QuartoFlavor) ? ".qmd" : ".$(type)"
outputfile = joinpath(outputdir, config["name"]::String * ext)
if inputfile == outputfile
throw(ArgumentError("outputfile (`$outputfile`) is identical to inputfile (`$inputfile`)"))
throw(
ArgumentError(
"outputfile (`$outputfile`) is identical to inputfile (`$inputfile`)",
),
)
end
output_thing = type === (:md) ? "markdown page" :
type === (:nb) ? "notebook" :
type === (:jl) ? "plain script file" : error("nope")
output_thing =
type === (:md) ? "markdown page" :
type === (:nb) ? "notebook" : type === (:jl) ? "plain script file" : error("nope")
@info "generating $(output_thing) from `$(Base.contractuser(inputfile))`"
# Add some information for passing around Literate methods
@ -494,7 +529,7 @@ function preprocessor(inputfile, outputdir; user_config, user_kwargs, type) @@ -494,7 +529,7 @@ function preprocessor(inputfile, outputdir; user_config, user_kwargs, type)
end
# default replacements
content = replace_default(content, type; config=config)
content = replace_default(content, type; config = config)
# parse the content into chunks
chunks = parse(content; allow_continued = type !== :nb)
@ -502,7 +537,7 @@ function preprocessor(inputfile, outputdir; user_config, user_kwargs, type) @@ -502,7 +537,7 @@ function preprocessor(inputfile, outputdir; user_config, user_kwargs, type)
return chunks, config
end
function write_result(content, config; print=print)
function write_result(content, config; print = print)
outputfile = config["literate_outputfile"]
@info "writing result to `$(Base.contractuser(outputfile))`"
open(outputfile, "w") do io
@ -519,10 +554,15 @@ Generate a plain script file from `inputfile` and write the result to `outputdir @@ -519,10 +554,15 @@ Generate a plain script file from `inputfile` and write the result to `outputdir
See the manual section on [Configuration](@ref) for documentation
of possible configuration with `config` and other keyword arguments.
"""
function script(inputfile, outputdir=pwd(); config::AbstractDict=Dict(), kwargs...)
function script(inputfile, outputdir = pwd(); config::AbstractDict = Dict(), kwargs...)
# preprocessing and parsing
chunks, config =
preprocessor(inputfile, outputdir; user_config=config, user_kwargs=kwargs, type=:jl)
chunks, config = preprocessor(
inputfile,
outputdir;
user_config = config,
user_kwargs = kwargs,
type = :jl,
)
# create the script file
ioscript = IOBuffer()
@ -558,10 +598,15 @@ to the directory `outputdir`. @@ -558,10 +598,15 @@ to the directory `outputdir`.
See the manual section on [Configuration](@ref) for documentation
of possible configuration with `config` and other keyword arguments.
"""
function markdown(inputfile, outputdir=pwd(); config::AbstractDict=Dict(), kwargs...)
function markdown(inputfile, outputdir = pwd(); config::AbstractDict = Dict(), kwargs...)
# preprocessing and parsing
chunks, config =
preprocessor(inputfile, outputdir; user_config=config, user_kwargs=kwargs, type=:md)
chunks, config = preprocessor(
inputfile,
outputdir;
user_config = config,
user_kwargs = kwargs,
type = :md,
)
# create the markdown file
sb = sandbox()
@ -578,7 +623,9 @@ function markdown(inputfile, outputdir=pwd(); config::AbstractDict=Dict(), kwarg @@ -578,7 +623,9 @@ function markdown(inputfile, outputdir=pwd(); config::AbstractDict=Dict(), kwarg
write(iocode, codefence.first)
# make sure the code block is finalized if we are printing to ```@example
# (or ````@example, any number of backticks >= 3 works)
if chunk.continued && occursin(r"^`{3,}@example", codefence.first) && isdocumenter(config)
if chunk.continued &&
occursin(r"^`{3,}@example", codefence.first) &&
isdocumenter(config)
write(iocode, "; continued = true")
end
write(iocode, '\n')
@ -596,11 +643,16 @@ function markdown(inputfile, outputdir=pwd(); config::AbstractDict=Dict(), kwarg @@ -596,11 +643,16 @@ function markdown(inputfile, outputdir=pwd(); config::AbstractDict=Dict(), kwarg
any(write_line, chunk.lines) && write(iomd, seekstart(iocode))
if execute
cd(config["literate_outputdir"]) do
execute_markdown!(iomd, sb, join(chunk.lines, '\n'), outputdir;
inputfile=config["literate_inputfile"],
fake_source=config["literate_outputfile"],
flavor=config["flavor"],
image_formats=config["image_formats"])
execute_markdown!(
iomd,
sb,
join(chunk.lines, '\n'),
outputdir;
inputfile = config["literate_inputfile"],
fake_source = config["literate_outputfile"],
flavor = config["flavor"],
image_formats = config["image_formats"],
)
end
end
end
@ -615,18 +667,26 @@ function markdown(inputfile, outputdir=pwd(); config::AbstractDict=Dict(), kwarg @@ -615,18 +667,26 @@ function markdown(inputfile, outputdir=pwd(); config::AbstractDict=Dict(), kwarg
return outputfile
end
function execute_markdown!(io::IO, sb::Module, block::String, outputdir;
inputfile::String, fake_source::String,
flavor::AbstractFlavor, image_formats::Vector)
function execute_markdown!(
io::IO,
sb::Module,
block::String,
outputdir;
inputfile::String,
fake_source::String,
flavor::AbstractFlavor,
image_formats::Vector,
)
# 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)
# issue #101: consecutive codefenced blocks need newline
# issue #144: quadruple backticks allow for triple backticks in the output
plain_fence = "\n````\n" => "\n````"
if r !== nothing && !REPL.ends_with_semicolon(block)
if (flavor isa FranklinFlavor || flavor isa DocumenterFlavor) &&
Base.invokelatest(showable, MIME("text/html"), r)
htmlfence = flavor isa FranklinFlavor ? ("~~~" => "~~~") : ("```@raw html" => "```")
htmlfence =
flavor isa FranklinFlavor ? ("~~~" => "~~~") : ("```@raw html" => "```")
write(io, "\n", htmlfence.first, "\n")
Base.invokelatest(show, io, MIME("text/html"), r)
write(io, "\n", htmlfence.second, "\n")
@ -668,8 +728,8 @@ function parse_nbmeta(line) @@ -668,8 +728,8 @@ function parse_nbmeta(line)
# Cf. https://jupytext.readthedocs.io/en/latest/formats.html#the-percent-format
m = match(r"^%% ([^[{]+)?\s*(?:\[(\w+)\])?\s*(\{.*)?$", line)
typ = m.captures[2]
name = m.captures[1] === nothing ? Dict{String, String}() : Dict("name" => m.captures[1])
meta = m.captures[3] === nothing ? Dict{String, Any}() : JSON.parse(m.captures[3])
name = m.captures[1] === nothing ? Dict{String,String}() : Dict("name" => m.captures[1])
meta = m.captures[3] === nothing ? Dict{String,Any}() : JSON.parse(m.captures[3])
return typ, merge(name, meta)
end
line_is_nbmeta(line::Pair) = line_is_nbmeta(line.second)
@ -683,16 +743,21 @@ Generate a notebook from `inputfile` and write the result to `outputdir`. @@ -683,16 +743,21 @@ Generate a notebook from `inputfile` and write the result to `outputdir`.
See the manual section on [Configuration](@ref) for documentation
of possible configuration with `config` and other keyword arguments.
"""
function notebook(inputfile, outputdir=pwd(); config::AbstractDict=Dict(), kwargs...)
function notebook(inputfile, outputdir = pwd(); config::AbstractDict = Dict(), kwargs...)
# preprocessing and parsing
chunks, config =
preprocessor(inputfile, outputdir; user_config=config, user_kwargs=kwargs, type=:nb)
chunks, config = preprocessor(
inputfile,
outputdir;
user_config = config,
user_kwargs = kwargs,
type = :nb,
)
# create the notebook
nb = jupyter_notebook(chunks, config)
# write to file
outputfile = write_result(nb, config; print = (io, c)->JSON.print(io, c, 1))
outputfile = write_result(nb, config; print = (io, c) -> JSON.print(io, c, 1))
return outputfile
end
@ -708,13 +773,15 @@ function jupyter_notebook(chunks, config) @@ -708,13 +773,15 @@ function jupyter_notebook(chunks, config)
chunktype = isa(chunk, MDChunk) ? "markdown" : "code"
if !isempty(chunk.lines) && line_is_nbmeta(chunk.lines[1])
metatype, metadata = parse_nbmeta(chunk.lines[1])
metatype !== nothing && metatype != chunktype && error("specifying a different cell type is not supported")
metatype !== nothing &&
metatype != chunktype &&
error("specifying a different cell type is not supported")
popfirst!(chunk.lines)
else
metadata = Dict{String, Any}()
metadata = Dict{String,Any}()
end
lines = isa(chunk, MDChunk) ?
String[x.second for x in chunk.lines] : # skip indent
lines =
isa(chunk, MDChunk) ? String[x.second for x in chunk.lines] : # skip indent
chunk.lines
@views map!(x -> x * '\n', lines[1:end-1], lines[1:end-1])
cell["cell_type"] = chunktype
@ -740,7 +807,7 @@ function jupyter_notebook(chunks, config) @@ -740,7 +807,7 @@ function jupyter_notebook(chunks, config)
language_info = Dict()
language_info["file_extension"] = ".jl"
language_info["mimetype"] = "application/julia"
language_info["name"]= "julia"
language_info["name"] = "julia"
language_info["version"] = string(VERSION)
metadata["language_info"] = language_info
@ -753,8 +820,11 @@ function jupyter_notebook(chunks, config) @@ -753,8 +820,11 @@ function jupyter_notebook(chunks, config)
@info "executing notebook `$(config["name"] * ".ipynb")`"
try
cd(config["literate_outputdir"]) do
nb = execute_notebook(nb; inputfile=config["literate_inputfile"],
fake_source=config["literate_outputfile"])
nb = execute_notebook(
nb;
inputfile = config["literate_inputfile"],
fake_source = config["literate_outputfile"],
)
end
catch err
@error "error when executing notebook based on input file: " *
@ -773,7 +843,8 @@ function execute_notebook(nb; inputfile::String, fake_source::String) @@ -773,7 +843,8 @@ function execute_notebook(nb; inputfile::String, fake_source::String)
execution_count += 1
cell["execution_count"] = execution_count
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)
# str should go into stream
if !isempty(str)
@ -875,14 +946,16 @@ function execute_block(sb::Module, block::String; inputfile::String, fake_source @@ -875,14 +946,16 @@ function execute_block(sb::Module, block::String; inputfile::String, fake_source
end
popdisplay(disp) # IOCapture.capture has a try-catch so should always end up here
if c.error
error("""
error(
"""
$(sprint(showerror, c.value))
when executing the following code block from inputfile `$(Base.contractuser(inputfile))`
```julia
$block
```
""")
""",
)
end
return c.value, c.output, disp.data
end

623
test/runtests.jl

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save