shg / ob-julia-vterm.el

Org-babel support for Julia code blocks using julia-vterm
GNU General Public License v3.0
36 stars 6 forks source link

World age errors #9

Closed devmotion closed 2 years ago

devmotion commented 2 years ago

Sometimes I run into world age errors. E.g., when executing the code blocks in the following org-mode document

#+begin_src julia-vterm
using Pkg
Pkg.activate(".")
Pkg.add("Plots")
#+end_src

#+begin_src julia-vterm
using Plots

scatter(rand(10))
#+end_src

in the associated REPL the following errors are thrown:

julia> Executing... a5f078fb
ERROR: MethodError: no method matching iterate(::RecipesPipeline.DefaultsDict)
The applicable method may be too new: running in world age 31346, while current world is 31439.
Closest candidates are:
  iterate(::RecipesPipeline.DefaultsDict) at ~/.julia/packages/RecipesPipeline/F2mWY/src/utils.jl:35 (method too new to be called from this world context.)
  iterate(::RecipesPipeline.DefaultsDict, ::Any) at ~/.julia/packages/RecipesPipeline/F2mWY/src/utils.jl:41 (method too new to be called from this world context.)
  iterate(::Union{LinRange, StepRangeLen}) at /nix/store/54b8wil52g0vvy0cyzmvv8576bp7l9f8-julia-bin-1.7.3/share/julia/base/range.jl:826
  ...
Stacktrace:
  [1] isempty(itr::RecipesPipeline.DefaultsDict)
    @ Base ./essentials.jl:775
  [2] typeinfo_prefix(io::IOContext{IOBuffer}, X::RecipesPipeline.DefaultsDict)
    @ Base ./arrayshow.jl:569
  [3] show(io::IOContext{IOBuffer}, t::RecipesPipeline.DefaultsDict)
    @ Base ./dict.jl:30
  [4] show_delim_array(io::IOContext{IOBuffer}, itr::Tuple{RecipesPipeline.DefaultsDict}, op::Char, delim::Char, cl::Char, delim_one::Bool, i1::Int64, n::Int64)
    @ Base ./show.jl:1244
  [5] show_delim_array
    @ ./show.jl:1229 [inlined]
  [6] show(io::IOContext{IOBuffer}, t::Tuple{RecipesPipeline.DefaultsDict})
    @ Base ./show.jl:1262
  [7] _show_default(io::IOBuffer, x::Any)
    @ Base ./show.jl:413
  [8] show_default
    @ ./show.jl:396 [inlined]
  [9] show
    @ ./show.jl:391 [inlined]
 [10] print(io::IOBuffer, x::MethodError)
    @ Base ./strings/io.jl:35
 [11] print_to_string(xs::MethodError)
    @ Base ./strings/io.jl:144
 [12] string(xs::MethodError)
    @ Base ./strings/io.jl:185
 [13] handle_message(logger::Logging.ConsoleLogger, level::Base.CoreLogging.LogLevel, message::Any, _module::Any, group::Any, id::Any, filepath::Any, line::Any; kwargs::Base.Pairs{Symbol, V, Tuple{Vararg{Symbol, N}}, NamedTuple{names, T}} where {V, N, names, T<:Tuple{Vararg{Any, N}}})
    @ Logging /nix/store/54b8wil52g0vvy0cyzmvv8576bp7l9f8-julia-bin-1.7.3/share/julia/stdlib/v1.7/Logging/src/ConsoleLogger.jl:119
 [14] handle_message(logger::Logging.ConsoleLogger, level::Base.CoreLogging.LogLevel, message::Any, _module::Any, group::Any, id::Any, filepath::Any, line::Any)
    @ Logging /nix/store/54b8wil52g0vvy0cyzmvv8576bp7l9f8-julia-bin-1.7.3/share/julia/stdlib/v1.7/Logging/src/ConsoleLogger.jl:109
 [15] macro expansion
    @ ./logging.jl:353 [inlined]
 [16] (::var"#8#10"{MethodError})()
    @ Main ./REPL[2]:14
 [17] with_logstate(f::Function, logstate::Any)
    @ Base.CoreLogging ./logging.jl:511
 [18] with_logger
    @ ./logging.jl:623 [inlined]
 [19] (::var"#7#9")(io::IOStream)
    @ Main ./REPL[2]:13
 [20] open(::var"#7#9", ::String, ::Vararg{String}; kwargs::Base.Pairs{Symbol, Union{}, Tuple{}, NamedTuple{(), Tuple{}}})
    @ Base ./io.jl:330
 [21] open(::Function, ::String, ::String)
    @ Base ./io.jl:328
 [22] top-level scope
    @ REPL[2]:2

caused by: MethodError: no method matching iterate(::RecipesPipeline.DefaultsDict)
The applicable method may be too new: running in world age 31346, while current world is 31439.
Closest candidates are:
  iterate(::RecipesPipeline.DefaultsDict) at ~/.julia/packages/RecipesPipeline/F2mWY/src/utils.jl:35 (method too new to be called from this world context.)
  iterate(::RecipesPipeline.DefaultsDict, ::Any) at ~/.julia/packages/RecipesPipeline/F2mWY/src/utils.jl:41 (method too new to be called from this world context.)
  iterate(::Union{LinRange, StepRangeLen}) at /nix/store/54b8wil52g0vvy0cyzmvv8576bp7l9f8-julia-bin-1.7.3/share/julia/base/range.jl:826
  ...
Stacktrace:
  [1] isempty(itr::RecipesPipeline.DefaultsDict)
    @ Base ./essentials.jl:775
  [2] typeinfo_prefix(io::IOContext{IOStream}, X::RecipesPipeline.DefaultsDict)
    @ Base ./arrayshow.jl:569
  [3] show(io::IOContext{IOStream}, t::RecipesPipeline.DefaultsDict)
    @ Base ./dict.jl:30
  [4] _show_default(io::IOStream, x::Any)
    @ Base ./show.jl:413
  [5] show_default
    @ ./show.jl:396 [inlined]
  [6] show
    @ ./show.jl:391 [inlined]
  [7] print(io::IOStream, x::Plots.Plot{Plots.GRBackend})
    @ Base ./strings/io.jl:35
  [8] (::var"#7#9")(io::IOStream)
    @ Main ./REPL[2]:10
  [9] open(::var"#7#9", ::String, ::Vararg{String}; kwargs::Base.Pairs{Symbol, Union{}, Tuple{}, NamedTuple{(), Tuple{}}})
    @ Base ./io.jl:330
 [10] open(::Function, ::String, ::String)
    @ Base ./io.jl:328
 [11] top-level scope
    @ REPL[2]:2

I think this could be solved by not calling print in e.g. https://github.com/shg/ob-julia-vterm.el/blob/a7ff8f05e4a7af4082262c7a7ba3d83ae490a7f3/ob-julia-vterm.el#L98 but Base.invokelatest(print, io, result). (Similar to e.g. the use of invokelatest in Literate: https://github.com/fredrikekre/Literate.jl/blob/master/src/Literate.jl.)

An additional question is if one should call something like Base.invokelatest(show, io, MIME("text/plain"), result) instead, matching the default mime type in the REPL.

shg commented 2 years ago

I can reproduce the error here and confirmed your suggestion fixes the issue. Thank you very much!

I too think the format of the results needs improvement (esp. for vectors, matrices, etc.). Using the same format as REPL would be an option but I would also like to make it as consistent as possible with other ob-* packages. But to be honest, I haven't been able to consider much yet. Suggestions are always very welcome.

devmotion commented 2 years ago

Thanks for the quick fix!

One possible idea could also be to support a :display option, similar to emacs-jupyter. If specified, then print/show could use the provided mime type. And otherwise one could either always fall back to text/plain, or have a list of standard mime types (such as text/html, image/png, text/plain etc.) in some pre-defined order and check if the result supports them (with Base.invokelatest(showable, mime, result)) and use the supported mime type (similar to what Literate.jl does and I guess IJulia, and hence emacs-jupyter).

shg commented 2 years ago

Thanks for the idea. Allowing the user control with the header argument sounds a reasonable choice. I will check how those other programs handle this.

shg commented 2 years ago

I updated the code to show results in text/plain MIME type as you suggested. Thank you! #12