From 36bdd4f82b622c462beccea511dbb63257ee9a1f Mon Sep 17 00:00:00 2001 From: Shuhei Kadowaki Date: Sat, 9 May 2020 22:33:58 +0900 Subject: [PATCH 1/3] remove weird default constructor for `WeaveDoc` --- src/Weave.jl | 5 +++- src/config.jl | 13 ---------- src/reader/reader.jl | 44 +++++++++++++++++++++++++++------- src/types.jl | 20 ---------------- test/errors_test.jl | 30 +++++++++++------------ test/formatter_test.jl | 25 +++++++++---------- test/runtests.jl | 3 +++ test/test_module_evaluation.jl | 13 ++++------ 8 files changed, 74 insertions(+), 79 deletions(-) diff --git a/src/Weave.jl b/src/Weave.jl index 42a1124..70ab2a5 100644 --- a/src/Weave.jl +++ b/src/Weave.jl @@ -3,6 +3,9 @@ import Highlights using Mustache using Requires + +const WEAVE_OPTION = "options" # TODO: rename to "weave_options" + function __init__() @require Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80" Base.include( Main, @@ -248,7 +251,7 @@ function notebook( end @info "Running nbconvert" - out = read( + return out = read( `$jupyter_path nbconvert --ExecutePreprocessor.timeout=$timeout --to notebook --execute $outfile $nbconvert_options --output $outfile`, String, ) diff --git a/src/config.jl b/src/config.jl index 67d2edd..d4129d0 100644 --- a/src/config.jl +++ b/src/config.jl @@ -145,16 +145,3 @@ function header_args( latex_cmd, ) end - -""" - header_chunk_defaults!(doc::WeaveDoc) - -Get chunk defaults from header and update. -""" -function header_chunk_defaults!(doc::WeaveDoc) - for key in keys(doc.chunk_defaults) - if (val = get(doc.header["options"], string(key), nothing)) !== nothing - doc.chunk_defaults[key] = val - end - end -end diff --git a/src/reader/reader.jl b/src/reader/reader.jl index 6c1c3e9..1f75c3c 100644 --- a/src/reader/reader.jl +++ b/src/reader/reader.jl @@ -2,20 +2,48 @@ using JSON, YAML """ - read_doc(source::AbstractString, format = :auto) -> WeaveDoc + read_doc(source, format = :auto) Read the input document from `source` and parse it into [`WeaveDoc`](@ref). """ -function read_doc(source::AbstractString, format = :auto) +function read_doc(source, format = :auto) document = replace(read(source, String), "\r\n" => "\n") # fix line ending - format === :auto && (format = detect_informat(source)) chunks = parse_doc(document, format) - header = parse_header(first(chunks)) - doc = WeaveDoc(source, chunks, header) - haskey(header, "options") && header_chunk_defaults!(doc) # TODO: rename `options` => `weave_options` + return WeaveDoc(source, chunks) +end - return doc +function WeaveDoc(source, chunks) + path, fname = splitdir(abspath(source)) + basename = splitext(fname)[1] + + header = parse_header(first(chunks)) + # get chunk defaults from header and update + chunk_defaults = deepcopy(rcParams[:chunk_defaults]) + if haskey(header, WEAVE_OPTION) + for key in keys(chunk_defaults) + if (val = get(header[WEAVE_OPTION], string(key), nothing)) !== nothing + chunk_defaults[key] = val + end + end + end + + return WeaveDoc( + source, + basename, + path, + chunks, + "", + nothing, + "", + "", + header, + "", + "", + Highlights.Themes.DefaultTheme, + "", + chunk_defaults, + ) end """ @@ -32,7 +60,7 @@ function detect_informat(source::AbstractString) return "noweb" end -function parse_doc(document, format) +function parse_doc(document, format)::Vector{WeaveChunk} return if format == "markdown" parse_markdown(document) elseif format == "noweb" diff --git a/src/types.jl b/src/types.jl index 20e0b03..43568c8 100644 --- a/src/types.jl +++ b/src/types.jl @@ -17,26 +17,6 @@ mutable struct WeaveDoc highlight_theme::Type{<:Highlights.AbstractTheme} fig_path::AbstractString chunk_defaults::Dict{Symbol,Any} - function WeaveDoc(source, chunks, header) - path, fname = splitdir(abspath(source)) - basename = splitext(fname)[1] - new( - source, - basename, - path, - chunks, - "", - nothing, - "", - "", - header, - "", - "", - Highlights.Themes.DefaultTheme, - "", - deepcopy(rcParams[:chunk_defaults]), - ) - end end struct ChunkOutput diff --git a/test/errors_test.jl b/test/errors_test.jl index b128ad5..5de002c 100644 --- a/test/errors_test.jl +++ b/test/errors_test.jl @@ -1,4 +1,4 @@ -s1= """ +str = """ ```julia using NonExisting @@ -17,19 +17,19 @@ print(y """ -p1 = Weave.parse_markdown(s1) -doc = Weave.WeaveDoc("dummy1.jmd", p1, Dict()) -doc1 = run_doc(doc, doctype = "pandoc") +let + doc = run_doc(mock_doc(str), doctype = "pandoc") + @test doc.chunks[1].output == "Error: ArgumentError: Package NonExisting not found in current path:\n- Run `import Pkg; Pkg.add(\"NonExisting\")` to install the NonExisting package.\n\n" + @test doc.chunks[2].output == "Error: syntax: incomplete: premature end of input\n" + @test doc.chunks[3].output == "\njulia> plot(x)\nError: UndefVarError: plot not defined\n\njulia> y = 10\n10\n\njulia> print(y\nError: syntax: incomplete: premature end of input\n" +end -@test doc1.chunks[1].output == "Error: ArgumentError: Package NonExisting not found in current path:\n- Run `import Pkg; Pkg.add(\"NonExisting\")` to install the NonExisting package.\n\n" -@test doc1.chunks[2].output == "Error: syntax: incomplete: premature end of input\n" -@test doc1.chunks[3].output == "\njulia> plot(x)\nError: UndefVarError: plot not defined\n\njulia> y = 10\n10\n\njulia> print(y\nError: syntax: incomplete: premature end of input\n" +@test_throws ArgumentError run_doc(mock_doc(str), doctype = "pandoc", throw_errors = true) -@test_throws ArgumentError run_doc(doc, doctype = "pandoc", throw_errors = true) - -doc = Weave.WeaveDoc("dummy1.jmd", p1, Dict()) -doc3 = run_doc(doc, doctype = "md2html") -@test doc3.chunks[1].rich_output == "
\nERROR: ArgumentError: Package NonExisting not found in current path:\n- Run `import Pkg; Pkg.add("NonExisting")` to install the NonExisting package.\n\n
\n" -@test doc3.chunks[2].rich_output == "
\nERROR: syntax: incomplete: premature end of input\n
\n" -@test doc3.chunks[3].output == "\njulia> plot(x)\nError: UndefVarError: plot not defined\n\njulia> y = 10\n10\n\njulia> print(y\nError: syntax: incomplete: premature end of input\n" -@test doc3.chunks[3].rich_output == "" +let + doc = run_doc(mock_doc(str), doctype = "md2html") + @test doc.chunks[1].rich_output == "
\nERROR: ArgumentError: Package NonExisting not found in current path:\n- Run `import Pkg; Pkg.add("NonExisting")` to install the NonExisting package.\n\n
\n" + @test doc.chunks[2].rich_output == "
\nERROR: syntax: incomplete: premature end of input\n
\n" + @test doc.chunks[3].output == "\njulia> plot(x)\nError: UndefVarError: plot not defined\n\njulia> y = 10\n10\n\njulia> print(y\nError: syntax: incomplete: premature end of input\n" + @test doc.chunks[3].rich_output == "" +end diff --git a/test/formatter_test.jl b/test/formatter_test.jl index 633f578..8911261 100644 --- a/test/formatter_test.jl +++ b/test/formatter_test.jl @@ -127,24 +127,21 @@ pformat.formatdict[:keep_unicode] = true f = Weave.format_chunk(dchunk, pformat.formatdict, pformat) @test f == "\\section{Test chunk}\nα\n\n" -function doc_from_string(str) - parsed = Weave.parse_markdown(str) - header = Weave.parse_header(parsed[1]) - Weave.WeaveDoc("",parsed,header) -end -doc_content = """ +str = """ ```julia α = 10 ``` """ -parsed = doc_from_string(doc_content) -ldoc = run_doc(parsed, doctype = "md2tex") -@test occursin(Weave.uc2tex("α"),Weave.format(ldoc)) -@test !occursin("α",Weave.format(ldoc)) +let + doc = run_doc(mock_doc(str), doctype = "md2tex") + @test occursin(Weave.uc2tex("α"), Weave.format(doc)) + @test !occursin("α", Weave.format(doc)) +end -parsed = doc_from_string(doc_content) -ldoc = run_doc(parsed, doctype = "md2tex",latex_keep_unicode=true) -@test occursin("α",Weave.format(ldoc)) -@test !occursin(Weave.uc2tex("α"),Weave.format(ldoc)) +let + doc = run_doc(mock_doc(str), doctype = "md2tex",latex_keep_unicode = true) + @test occursin("α", Weave.format(doc)) + @test !occursin(Weave.uc2tex("α"), Weave.format(doc)) +end diff --git a/test/runtests.jl b/test/runtests.jl index 8c1bf70..69e6c4d 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -6,6 +6,9 @@ using Test # TODO: add test for header processsing # TODO: add test for `include_weave` +# constructs `WeaveDoc` from `String` +mock_doc(str, chunk_parser = Weave.parse_markdown) = Weave.WeaveDoc("dummy", chunk_parser(str)) + @testset "Weave" begin @testset "Chunk options" begin diff --git a/test/test_module_evaluation.jl b/test/test_module_evaluation.jl index 73fefd7..b078d05 100644 --- a/test/test_module_evaluation.jl +++ b/test/test_module_evaluation.jl @@ -1,23 +1,20 @@ @testset "evaluation module" begin - function mock_output(document, mod = nothing) - parsed = Weave.parse_markdown(document) - doc = Weave.WeaveDoc("dummy.jmd", parsed, Dict()) - result_doc = run_doc(doc, mod = mod) - @test isdefined(result_doc.chunks[1], :output) + function mock_output(str, mod = nothing) + result_doc = run_doc(mock_doc(str), mod = mod) return result_doc.chunks[1].output end - document = """ + str = """ ```julia @__MODULE__ ``` """ # in sandbox - @test occursin(r"\#+WeaveSandBox[\#\d]+", mock_output(document)) + @test occursin(r"\#+WeaveSandBox[\#\d]+", mock_output(str)) # in Main - @test strip(mock_output(document, Main)) == "Main" + @test strip(mock_output(str, Main)) == "Main" end @testset "clear_module!" begin From 8303311d59daa36b559ad348fe90293d011134b5 Mon Sep 17 00:00:00 2001 From: Shuhei Kadowaki Date: Sat, 9 May 2020 22:35:45 +0900 Subject: [PATCH 2/3] more robust error rendering test --- test/errors_test.jl | 35 -------------------------- test/runtests.jl | 8 +++--- test/test_error_rendering.jl | 49 ++++++++++++++++++++++++++++++++++++ 3 files changed, 53 insertions(+), 39 deletions(-) delete mode 100644 test/errors_test.jl create mode 100644 test/test_error_rendering.jl diff --git a/test/errors_test.jl b/test/errors_test.jl deleted file mode 100644 index 5de002c..0000000 --- a/test/errors_test.jl +++ /dev/null @@ -1,35 +0,0 @@ -str = """ - -```julia -using NonExisting -``` - -```julia -x = -``` - - -```julia;term=true -plot(x) -y = 10 -print(y -``` - -""" - -let - doc = run_doc(mock_doc(str), doctype = "pandoc") - @test doc.chunks[1].output == "Error: ArgumentError: Package NonExisting not found in current path:\n- Run `import Pkg; Pkg.add(\"NonExisting\")` to install the NonExisting package.\n\n" - @test doc.chunks[2].output == "Error: syntax: incomplete: premature end of input\n" - @test doc.chunks[3].output == "\njulia> plot(x)\nError: UndefVarError: plot not defined\n\njulia> y = 10\n10\n\njulia> print(y\nError: syntax: incomplete: premature end of input\n" -end - -@test_throws ArgumentError run_doc(mock_doc(str), doctype = "pandoc", throw_errors = true) - -let - doc = run_doc(mock_doc(str), doctype = "md2html") - @test doc.chunks[1].rich_output == "
\nERROR: ArgumentError: Package NonExisting not found in current path:\n- Run `import Pkg; Pkg.add("NonExisting")` to install the NonExisting package.\n\n
\n" - @test doc.chunks[2].rich_output == "
\nERROR: syntax: incomplete: premature end of input\n
\n" - @test doc.chunks[3].output == "\njulia> plot(x)\nError: UndefVarError: plot not defined\n\njulia> y = 10\n10\n\njulia> print(y\nError: syntax: incomplete: premature end of input\n" - @test doc.chunks[3].rich_output == "" -end diff --git a/test/runtests.jl b/test/runtests.jl index 69e6c4d..f1997f3 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -15,10 +15,6 @@ mock_doc(str, chunk_parser = Weave.parse_markdown) = Weave.WeaveDoc("dummy", chu include("chunk_options.jl") end - @testset "Error handling " begin - include("errors_test.jl") - end - @testset "module evaluation" begin include("test_module_evaluation.jl") end @@ -27,6 +23,10 @@ mock_doc(str, chunk_parser = Weave.parse_markdown) = Weave.WeaveDoc("dummy", chu include("test_header.jl") end + @testset "error rendering" begin + include("test_error_rendering.jl") + end + @testset "Conversions" begin include("convert_test.jl") end diff --git a/test/test_error_rendering.jl b/test/test_error_rendering.jl new file mode 100644 index 0000000..816aeed --- /dev/null +++ b/test/test_error_rendering.jl @@ -0,0 +1,49 @@ +function get_err_str(ex) + try + eval(ex) + catch err + return sprint(showerror, err) + end +end +get_err_str(str::AbstractString) = get_err_str(Meta.parse(str; raise = false)) + +err_stmt1 = "using NonExisting" +err_stmt2 = "x = " +err_stmt3 = """ +plot(x) +y = 10 +f(y +""" + +str = """ +```julia +$err_stmt1 +``` + +```julia +$err_stmt2 +``` + +```julia; term=true +$err_stmt3 +``` +""" + +err_str1 = get_err_str(err_stmt1) +err_str2 = get_err_str(err_stmt2) +err_str3_1 = get_err_str("plot(x)") +err_str3_2 = get_err_str("f(y") + + +let doc = run_doc(mock_doc(str), doctype = "pandoc") + get_output(i) = doc.chunks[i].output + + @test occursin(err_str1, get_output(1)) + @test occursin(err_str2, get_output(2)) + @test occursin(err_str3_1, get_output(3)) + @test occursin(err_str3_2, get_output(3)) +end + +@test_throws ArgumentError run_doc(mock_doc(str), doctype = "pandoc", throw_errors = true) + +# TODO: test error rendering in `rich_output` From 4dae2a08169f3b6c1319acd20369c86775efe26c Mon Sep 17 00:00:00 2001 From: Shuhei Kadowaki Date: Sat, 9 May 2020 22:42:05 +0900 Subject: [PATCH 3/3] `WEAVE_OPTION_NAME` --- src/Weave.jl | 4 ++-- src/config.jl | 2 +- src/format.jl | 2 +- src/reader/reader.jl | 4 ++-- test/test_header.jl | 4 ++-- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Weave.jl b/src/Weave.jl index 70ab2a5..561fd5f 100644 --- a/src/Weave.jl +++ b/src/Weave.jl @@ -4,7 +4,7 @@ using Mustache using Requires -const WEAVE_OPTION = "options" # TODO: rename to "weave_options" +const WEAVE_OPTION_NAME = "options" # TODO: rename to "weave_options" function __init__() @require Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80" Base.include( @@ -126,7 +126,7 @@ function weave( doc.doctype = doctype # Read args from document header, overrides command line args - if haskey(doc.header, "options") + if haskey(doc.header, WEAVE_OPTION_NAME) ( doctype, informat, diff --git a/src/config.jl b/src/config.jl index d4129d0..2d82ef3 100644 --- a/src/config.jl +++ b/src/config.jl @@ -107,7 +107,7 @@ function header_args( pandoc_options, latex_cmd, ) - args = get(doc.header, "options", Dict()) + args = get(doc.header, WEAVE_OPTION_NAME, Dict()) doctype = get(args, "doctype", doc.doctype) args = combine_args(args, doctype) informat = get(args, "informat", :auto) diff --git a/src/format.jl b/src/format.jl index f9887da..3bb7117 100644 --- a/src/format.jl +++ b/src/format.jl @@ -131,7 +131,7 @@ function strip_header!(docchunk::DocChunk, doctype) else # only strips Weave headers header = YAML.load(m[:header]) - delete!(header, "options") + delete!(header, WEAVE_OPTION_NAME) if isempty(header) lstrip(replace(content, HEADER_REGEX => "")) else diff --git a/src/reader/reader.jl b/src/reader/reader.jl index 1f75c3c..d8b2199 100644 --- a/src/reader/reader.jl +++ b/src/reader/reader.jl @@ -20,9 +20,9 @@ function WeaveDoc(source, chunks) header = parse_header(first(chunks)) # get chunk defaults from header and update chunk_defaults = deepcopy(rcParams[:chunk_defaults]) - if haskey(header, WEAVE_OPTION) + if haskey(header, WEAVE_OPTION_NAME) for key in keys(chunk_defaults) - if (val = get(header[WEAVE_OPTION], string(key), nothing)) !== nothing + if (val = get(header[WEAVE_OPTION_NAME], string(key), nothing)) !== nothing chunk_defaults[key] = val end end diff --git a/test/test_header.jl b/test/test_header.jl index 361061c..4b20206 100644 --- a/test/test_header.jl +++ b/test/test_header.jl @@ -1,4 +1,4 @@ -using YAML +using Weave.YAML # TODO: # - header stripping @@ -19,7 +19,7 @@ options: --- """) -let args = header["options"] +let args = header[Weave.WEAVE_OPTION_NAME] @test Weave.combine_args(args, "md2html") == Dict("fig_ext" => ".png", "out_path" => "html/") @test Weave.combine_args(args, "github") == Dict("fig_ext" => ".png", "out_path" => "md/") @test Weave.combine_args(args, "pandoc") == Dict("fig_ext" => ".png", "out_path" => "reports")