rikhuijzer / PlutoStaticHTML.jl

Convert Pluto notebooks to HTML in automated workflows
https://PlutoStaticHTML.huijzer.xyz
MIT License
83 stars 7 forks source link

Allow showing errors to readers #148

Closed kellertuer closed 2 years ago

kellertuer commented 2 years ago

I am currently starting with tutorials for Manifolds.jl using Pluto and PlutoStaticHTML.

In the notebook (preview) at

https://juliamanifolds.github.io/Manifolds.jl/previews/PR534/tutorials/getstarted.html

I have a few cells where I would like to actually have an error to illustrate what error to expect. Maybe this is also something for Pluto to have a way to nicely expect/display errors, but

For example the cell before 3. The Sphere is quite tricky just to display an error. Could this maybe be made nicer?

Also rendered markdown code and input cells look exactly the same, is there a way to change their appearance?

rikhuijzer commented 2 years ago

For example the cell before 3. The Sphere is quite tricky just to display an error. Could this maybe be made nicer?

Ah yes good question. See https://github.com/rikhuijzer/PlutoStaticHTML.jl/issues/73. If you have the time, then a PR to update the docs here at PlutoStaticHTML could be nice.

Let's leave this issue open until one of us updates the docs

kellertuer commented 2 years ago

Maybe this would even be something for PlutoUI – something to nicely display an expected error (and maybe even really throw an error if there is no error to display). Then PlutoStaticHTML could just render that PlutoUI-element “reasonably”?

I find my current solution a little hand-crafted and the error display also does not really look nice.

kellertuer commented 2 years ago

I still have to check how this renders in PlutoStaticHMML but the solution I ended up with (adapted from the linked Pluto issue) is

macro expect_error(code, error=:DomainError)
    quote
        try
            $(esc(code))
            error(string("Error of type ", $(esc(error)), " was not thrown."))
        catch e
            if e isa $(esc(error))
                pretty_error(e)
            else
                rethrow()
            end
        end
    end
end;

together with

function pretty_error(err) 
    Markdown.parse("""
!!! info "This is how the Error we expect here looks like"
$(replace(sprint(showerror, err), "\n" => "\n        "))
```

""") end;

kellertuer commented 2 years ago

The only problem is, that the code above does not work with PlutoStaticHTML. Defining both and havoc a cell like

# ╔═╡ d3caea7a-89ff-4f04-94e9-922048ad0bb1
@expect_error throw(DomainError(0.0,"Moep")) DomainError

yields

[ Info: Starting evaluation of Pluto notebook getstarted.jl
[ Info: Finished evaluation of Pluto notebook getstarted.jl in 1 second
ERROR: LoadError: TypeError: in typeassert, expected UnitRange{Int64}, got a value of type Nothing
Stacktrace:
  [1] _wrap_admonition_body(html::String)
    @ PlutoStaticHTML ~/.julia/packages/PlutoStaticHTML/AEni0/src/style.jl:36
  [2] _convert_admonition(html::SubString{String})
    @ PlutoStaticHTML ~/.julia/packages/PlutoStaticHTML/AEni0/src/style.jl:57
  [3] _replace(io::IOBuffer, repl::typeof(PlutoStaticHTML._convert_admonition), str::String, r::UnitRange{Int64}, pattern::Base.RegexAndMatchData)
    @ Base ./strings/util.jl:665
  [4] replace(str::String, pat_repl::Pair{Regex, typeof(PlutoStaticHTML._convert_admonition)}; count::Int64)
    @ Base ./strings/util.jl:706
  [5] replace
    @ ./strings/util.jl:676 [inlined]
  [6] _convert_admonitions(html::String)
    @ PlutoStaticHTML ~/.julia/packages/PlutoStaticHTML/AEni0/src/style.jl:67
  [7] _cell2html(cell::Pluto.Cell, oopts::OutputOptions)
    @ PlutoStaticHTML ~/.julia/packages/PlutoStaticHTML/AEni0/src/html.jl:163
  [8] #23
    @ ~/.julia/packages/PlutoStaticHTML/AEni0/src/html.jl:189 [inlined]
  [9] iterate
    @ ./generator.jl:47 [inlined]
 [10] collect_to!(dest::Vector{String}, itr::Base.Generator{Vector{Base.UUID}, PlutoStaticHTML.var"#23#24"{Pluto.Notebook, OutputOptions}}, offs::Int64, st::Int64)
    @ Base ./array.jl:845
 [11] collect_to_with_first!(dest::Vector{String}, v1::String, itr::Base.Generator{Vector{Base.UUID}, PlutoStaticHTML.var"#23#24"{Pluto.Notebook, OutputOptions}}, st::Int64)
    @ Base ./array.jl:823
 [12] _collect(c::Vector{Base.UUID}, itr::Base.Generator{Vector{Base.UUID}, PlutoStaticHTML.var"#23#24"{Pluto.Notebook, OutputOptions}}, #unused#::Base.EltypeUnknown, isz::Base.HasShape{1})
    @ Base ./array.jl:817
 [13] collect_similar
    @ ./array.jl:716 [inlined]
 [14] map
    @ ./abstractarray.jl:2933 [inlined]
 [15] notebook2html(nb::Pluto.Notebook, path::String, oopts::OutputOptions)
    @ PlutoStaticHTML ~/.julia/packages/PlutoStaticHTML/AEni0/src/html.jl:187
 [16] _outcome2html(nb::Pluto.Notebook, in_path::String, bopts::BuildOptions, output_format::PlutoStaticHTML.OutputFormat, oopts::OutputOptions)
    @ PlutoStaticHTML ~/.julia/packages/PlutoStaticHTML/AEni0/src/build.jl:277
 [17] #35
    @ ~/.julia/packages/PlutoStaticHTML/AEni0/src/build.jl:297 [inlined]
 [18] iterate
    @ ./generator.jl:47 [inlined]
 [19] _collect(c::Vector{PlutoStaticHTML.OutputFormat}, itr::Base.Generator{Vector{PlutoStaticHTML.OutputFormat}, PlutoStaticHTML.var"#35#37"{Pluto.Notebook, String, BuildOptions, OutputOptions}}, #unused#::Base.EltypeUnknown, isz::Base.HasShape{1})
    @ Base ./array.jl:807
 [20] collect_similar(cont::Vector{PlutoStaticHTML.OutputFormat}, itr::Base.Generator{Vector{PlutoStaticHTML.OutputFormat}, PlutoStaticHTML.var"#35#37"{Pluto.Notebook, String, BuildOptions, OutputOptions}})
    @ Base ./array.jl:716
 [21] map
    @ ./abstractarray.jl:2933 [inlined]
 [22] _outcome2text(session::Pluto.ServerSession, nb::Pluto.Notebook, in_path::String, bopts::BuildOptions, oopts::OutputOptions)
    @ PlutoStaticHTML ~/.julia/packages/PlutoStaticHTML/AEni0/src/build.jl:293
 [23] build_notebooks(bopts::BuildOptions, files::Vector{String}, oopts::OutputOptions; session::Pluto.ServerSession)
    @ PlutoStaticHTML ~/.julia/packages/PlutoStaticHTML/AEni0/src/build.jl:474
 [24] build_notebooks (repeats 2 times)
    @ ~/.julia/packages/PlutoStaticHTML/AEni0/src/build.jl:458 [inlined]
 [25] top-level scope
    @ ~/Repositories/Julia/Manifolds.jl/docs/make.jl:44
 [26] include(fname::String)
    @ Base.MainInclude ./client.jl:476
 [27] top-level scope
    @ REPL[6]:1
in expression starting at /Users/ronnber/Repositories/Julia/Manifolds.jl/docs/make.jl:42

Any ideas where to start debugging? Note the cell does work fine in Pluto.

rikhuijzer commented 2 years ago

That's a bug. I'll see whether I can write a test and patch it. Probably done before tomorrow 12:00

kellertuer commented 2 years ago

Cool (because I would have had no idea where to start).

Don't worry its not urgent, its already nice that we found a way to display errors that fast. I have to write quite some part of the tutorial anyways, still. So if it takes longer – no problem :)

kellertuer commented 2 years ago

Sorry to bother again – in general the result looks great!

Screenshot 2022-10-13 at 08 48 59

I just noticed the e> (which also only appears for one of the two displays, the other one is fine). I looked at the code and its

  <div class="admonition-body">
    <pre><code>DomainError with 0.1:
    The vector &#91;0.1, 1.0, 1.0&#93; is not a tangent vector to &#91;1, 0, 0&#93; on Sphere&#40;2, ℝ&#41;, since it is not orthogonal in the embedding.</code></pr
  </div>e>

( did not change any of the line breaks.

Any idea how this might have happened that the pre is so strangely split?

rikhuijzer commented 2 years ago

Any idea how this might have happened that the pre is so strangely split?

Yeah because I'm trying to parse HTML with basic string operations and regexes which are not a good idea, see https://stackoverflow.com/a/1732454/5056635.

I should have switched to a XML parser 😅

kellertuer commented 2 years ago

Then – just maybe – don't regexp 😃

Ok, but then I know where that's from and that its not me ;)

rikhuijzer commented 2 years ago

Very helpful. Thanks :+1:

rikhuijzer commented 2 years ago

Sorry to bother again – in general the result looks great!

Screenshot 2022-10-13 at 08 48 59

I just noticed the e> (which also only appears for one of the two displays, the other one is fine). I looked at the code and its

  <div class="admonition-body">
    <pre><code>DomainError with 0.1:
    The vector &#91;0.1, 1.0, 1.0&#93; is not a tangent vector to &#91;1, 0, 0&#93; on Sphere&#40;2, ℝ&#41;, since it is not orthogonal in the embedding.</code></pr
  </div>e>

( did not change any of the line breaks.

Any idea how this might have happened that the pre is so strangely split?

@kellertuer Is the issue fixed now in v6.0.4?

kellertuer commented 2 years ago

yes, it looks perfect locally :) Thanks!