Skip to content

Commit

Permalink
Added error handling with html display (#117)
Browse files Browse the repository at this point in the history
* Implemented error handling and initial html display

* Improved html display and tests for error handling
  • Loading branch information
mpastell authored Jan 7, 2018
1 parent 51ea08c commit eead8f2
Show file tree
Hide file tree
Showing 7 changed files with 88 additions and 11 deletions.
6 changes: 5 additions & 1 deletion src/Weave.jl
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ Weave an input document to output file.
* `cache_path`: where of cached output will be saved.
* `cache`: controls caching of code: `:off` = no caching, `:all` = cache everything,
`:user` = cache based on chunk options, `:refresh`, run all code chunks and save new cache.
* `throw_errors` if `false` errors are included in output document and the whole document is
executed. if `true` errors are thrown when they occur.
* `template` : Template (file path) for md2html or md2tex formats.
* `highlight_theme` : Theme (Highlights.AbstractTheme) for used syntax highlighting
* `css` : CSS (file path) used for md2html format
Expand All @@ -79,6 +81,7 @@ function weave(source ; doctype = :auto, plotlib=:auto,
informat=:auto, out_path=:doc, args = Dict(),
fig_path = "figures", fig_ext = nothing,
cache_path = "cache", cache=:off,
throw_errors = false,
template = nothing, highlight_theme = nothing, css = nothing,
latex_cmd = "xelatex")

Expand All @@ -91,7 +94,8 @@ function weave(source ; doctype = :auto, plotlib=:auto,
try
doc = run(doc, doctype = doctype, plotlib=plotlib,
out_path=out_path, args = args,
fig_path = fig_path, fig_ext = fig_ext, cache_path = cache_path, cache=cache)
fig_path = fig_path, fig_ext = fig_ext, cache_path = cache_path, cache=cache,
throw_errors = throw_errors)
formatted = format(doc)

outname = get_outname(out_path, doc)
Expand Down
26 changes: 21 additions & 5 deletions src/display_methods.jl
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,12 @@ mutable struct Report <: Display
mimetypes::Array{AbstractString}
first_plot::Bool
header_script::String
throw_errors::Bool
end

function Report(cwd, basename, formatdict, mimetypes)
Report(cwd, basename, formatdict, "", "", "", 1, AbstractString[], :text, nothing, mimetypes, true, "")
function Report(cwd, basename, formatdict, mimetypes, throw_errors)
Report(cwd, basename, formatdict, "", "", "", 1, AbstractString[], :text, nothing,
mimetypes, true, "", throw_errors)
end


Expand All @@ -34,13 +36,14 @@ function Base.display(report::Report, data)
if mimewritable(m, data)
try
if !istextmime(m)
Compat.invokelatest(display, report, m, data)
Compat.invokelatest(display, report, m, data)
elseif report.cur_chunk.options[:term]
Compat.invokelatest(display, report, "text/plain", data)
else
else
Compat.invokelatest(display, report, m, data)
end
catch e
throw(e)
warn("Failed to display data in \"$m\" format")
continue
end
Expand Down Expand Up @@ -71,6 +74,20 @@ function Base.display(report::Report, m::MIME"text/plain", data)
println(s)
end

function Base.display(report::Report, m::MIME"text/plain", data::Exception)
println("Error: " * sprint(showerror, data))
end

function Base.display(report::Report, m::MIME"text/html", data::Exception)
report.rich_output = sprint(show, m, data)
end

function Base.show(io, m::MIME"text/html", data::Exception)
println(io ,"<pre class=\"julia-error\">")
println(io, Base.Markdown.htmlesc("ERROR: " * sprint(showerror, data)))
println(io ,"</pre>")
end

#Catch "rich_output"
function Base.display(report::Report, m::MIME"text/html", data)
s = reprmime(m, data)
Expand All @@ -88,7 +105,6 @@ function Base.display(report::Report, m::MIME"text/latex", data)
report.rich_output *= "\n" * s
end


"""Add saved figure name to results and return the name"""
function add_figure(report::Report, data, m, ext)
chunk = report.cur_chunk
Expand Down
12 changes: 8 additions & 4 deletions src/run.jl
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ Run code chunks and capture output from parsed document.
"""
function Base.run(doc::WeaveDoc; doctype = :auto, plotlib=:auto,
out_path=:doc, args=Dict(), fig_path = "figures", fig_ext = nothing,
cache_path = "cache", cache = :off)
cache_path = "cache", cache = :off, throw_errors=false)
#cache :all, :user, :off, :refresh

doc.cwd = get_cwd(doc, out_path)
Expand Down Expand Up @@ -60,7 +60,7 @@ function Base.run(doc::WeaveDoc; doctype = :auto, plotlib=:auto,
rcParams[:plotlib_set] = false
plotlib == :auto || init_plotting(plotlib)

report = Report(doc.cwd, doc.basename, doc.format.formatdict, mimetypes)
report = Report(doc.cwd, doc.basename, doc.format.formatdict, mimetypes, throw_errors)
pushdisplay(report)

if cache != :off && cache != :refresh
Expand Down Expand Up @@ -204,7 +204,7 @@ function run_code(chunk::CodeChunk, report::Report, SandBox::Module)
lastline = (result_no == N)
rcParams[:plotlib_set] || detect_plotlib(chunk) #Try to autodetect plotting library
(obj, out) = capture_output(expr, SandBox, chunk.options[:term],
chunk.options[:display], rcParams[:plotlib], lastline)
chunk.options[:display], rcParams[:plotlib], lastline, report.throw_errors)
figures = report.figures #Captured figures
result = ChunkOutput(str_expr, out, report.cur_result, report.rich_output, figures)
report.rich_output = ""
Expand All @@ -223,7 +223,7 @@ end
getstdout() = Base.STDOUT

function capture_output(expr, SandBox::Module, term, disp, plotlib,
lastline)
lastline, throw_errors=false)
#oldSTDOUT = STDOUT
oldSTDOUT = getstdout()
out = nothing
Expand All @@ -243,6 +243,10 @@ function capture_output(expr, SandBox::Module, term, disp, plotlib,
elseif lastline && obj != nothing
(expr.head != :toplevel && expr.head != :(=)) && display(obj)
end
catch E
throw_errors && throw(E)
display(E)
warn("ERROR: $(typeof(E)) occurred, including output in Weaved document")
finally
redirect_stdout(oldSTDOUT)
close(wr)
Expand Down
4 changes: 4 additions & 0 deletions templates/pandoc_skeleton.css
Original file line number Diff line number Diff line change
Expand Up @@ -518,6 +518,10 @@ pre.sourceCode.julia {
border-radius: 4px;
}

pre.julia-error {
color : red
}

code,
kbd,
pre,
Expand Down
4 changes: 4 additions & 0 deletions templates/skeleton_css.css
Original file line number Diff line number Diff line change
Expand Up @@ -515,6 +515,10 @@ pre.sourceCode.julia {
border-radius: 4px;
}

pre.julia-error {
color : red
}

code,
kbd,
pre,
Expand Down
43 changes: 43 additions & 0 deletions test/errors_test.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
using Weave
using Base.Test

s1= """
```julia
using NonExisting
```
```julia
x =
```
```julia;term=true
plot(x)
y = 10
print(y
```
"""

p1 = Weave.parse_doc(s1, "markdown")
doc = Weave.WeaveDoc("dummy1.jmd", p1, Dict())
doc1 = Weave.run(doc, doctype = "pandoc")

@test doc1.chunks[1].output == "Error: ArgumentError: Module NonExisting not found in current path.\nRun `Pkg.add(\"NonExisting\")` to install the NonExisting package.\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"

try
doc2 = Weave.run(doc, doctype = "pandoc", throw_errors = true)
catch E
@test typeof(E) == ArgumentError
@test E.msg == "Module NonExisting not found in current path.\nRun `Pkg.add(\"NonExisting\")` to install the NonExisting package."
end

doc = Weave.WeaveDoc("dummy1.jmd", p1, Dict())
doc3 = Weave.run(doc, doctype = "md2html")
@test doc3.chunks[1].rich_output == "<pre class=\"julia-error\">\nERROR: ArgumentError: Module NonExisting not found in current path.\nRun &#96;Pkg.add&#40;&quot;NonExisting&quot;&#41;&#96; to install the NonExisting package.\n</pre>\n"
@test doc3.chunks[2].rich_output == "<pre class=\"julia-error\">\nERROR: syntax: incomplete: premature end of input\n</pre>\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 == ""
4 changes: 3 additions & 1 deletion test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ using Base.Test
info("Test: Chunk options")
include("chunk_options.jl")

info("Testing error handling")
include("errors_test.jl")

info("Test: Converting")
include("convert_test.jl")

Expand Down Expand Up @@ -32,4 +35,3 @@ include("chunk_opts_gadfly.jl")
info("Test: Weaving with Plots.jl")
include("plotsjl_test.jl")
include("publish_test.jl")

0 comments on commit eead8f2

Please sign in to comment.