From 8a36dabc3c2a84219b86c74dd412abfb3b3ed7eb Mon Sep 17 00:00:00 2001 From: Alberto Mengali Date: Sun, 3 Mar 2024 19:00:11 +0100 Subject: [PATCH] Call the kaleido binary directly (fixes permission errors on Windows and Julia 1.10) (#17) * point to kaleido.exe directly on windows * try alternative * remove hanging stuff * remove `@test_nowarn` on start() * put bck test_nowarn on non-windows * warn about windows problem on README * testnowarn error * revert test_nowarn error * Throw an error with a suggestion fix if kaleido seems to hang * fix noblock function as bytesavailable does not work here --- Project.toml | 7 ++++--- README.md | 15 +++++++++++++++ src/PlotlyKaleido.jl | 43 ++++++++++++++++++++++++++++++++++++++----- test/runtests.jl | 13 +++++++++++-- 4 files changed, 68 insertions(+), 10 deletions(-) diff --git a/Project.toml b/Project.toml index bf4528d..7dec445 100644 --- a/Project.toml +++ b/Project.toml @@ -14,10 +14,11 @@ julia = "1.6" Kaleido_jll = "0.1, 0.2" [extras] -Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" -PlotlyLight = "ca7969ec-10b3-423e-8d99-40f33abb42bf" EasyConfig = "acab07b0-f158-46d4-8913-50acef6d41fe" PlotlyJS = "f0f68f2c-4968-5e81-91da-67840de0976a" +PlotlyLight = "ca7969ec-10b3-423e-8d99-40f33abb42bf" +Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" +Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" [targets] -test = ["Test", "PlotlyLight", "EasyConfig", "PlotlyJS"] +test = ["Test", "PlotlyLight", "EasyConfig", "PlotlyJS", "Pkg"] diff --git a/README.md b/README.md index 1ca5252..823c65a 100644 --- a/README.md +++ b/README.md @@ -52,4 +52,19 @@ PlotlyKaleido.kill_kaleido() To enable LaTeX (using MathJax v2) in plots, use the keyword argument `mathjax`: ```julia PlotlyKaleido.start(mathjax=true) # start Kaleido server with MathJax enabled +``` + +## Windows Note +Many people one Windows have issues with the latest (0.2.1) version of the Kaleido library (see for example [discourse](https://discourse.julialang.org/t/plotlyjs-causes-errors-cant-figure-out-how-to-use-plotlylight-how-to-use-plotly-from-julia/108853/29), [this PR's comment](https://github.com/JuliaPlots/PlotlyKaleido.jl/pull/17#issuecomment-1969325440) and [this issue](https://github.com/plotly/Kaleido/issues/134) on the Kaleido repository). + +Many people have succesfully fixed this problem on windows by downgrading the kaleido library to version 0.1.0 (see [the previously mentioned issue](https://github.com/plotly/Kaleido/issues/134)). If you experience issues with `PlotlyKaleido.start()` hanging on windows, you may want try adding `Kaledido_jll@v0.1` explicitly to your project environment to fix this. You can do so by either doing: +```julia +add Kaleido_jll@v0.1 +``` +inside the REPL package enviornment, or by calling the following code in the REPL directly: +```julia +begin + import Pkg + Pkg.add(; name = "Kaleido_jll", version = "0.1") +end ``` \ No newline at end of file diff --git a/src/PlotlyKaleido.jl b/src/PlotlyKaleido.jl index 1d2410f..f2631c7 100644 --- a/src/PlotlyKaleido.jl +++ b/src/PlotlyKaleido.jl @@ -26,6 +26,36 @@ is_running() = isdefined(P, :proc) && isopen(P.stdin) && process_running(P.proc) restart(; kwargs...) = (kill_kaleido(); start(; kwargs...)) +# The content of this function is inspired from https://discourse.julialang.org/t/readline-with-default-value-if-no-input-after-timeout/100388/2?u=disberd +function readline_noblock(io) + msg = Channel{String}(1) + + task = Task() do + try + put!(msg, readline(io)) + catch + put!(msg, "Stopped") + end + end + + interrupter = Task() do + sleep(5) + if !istaskdone(task) + Base.throwto(task, InterruptException()) + end + end + + schedule(interrupter) + schedule(task) + wait(task) + out = take!(msg) + out === "Stopped" && error("It looks like the kaleido process is hanging. +If you are on windows this might be caused by known problems with Kaleido v0.2 on windows. +You might want to try forcing a downgrade of the kaleido library to 0.1. +Check the Package Readme at https://github.com/JuliaPlots/PlotlyKaleido.jl/tree/main#windows-note for more details") + return out +end + function start(; plotly_version = missing, mathjax = missing, @@ -33,8 +63,10 @@ function start(; kwargs..., ) is_running() && return - cmd = joinpath(Kaleido_jll.artifact_dir, "kaleido" * (Sys.iswindows() ? ".cmd" : "")) - basic_cmds = [cmd, "plotly"] + # The kaleido executable must be ran from the artifact directory + BIN = Cmd(kaleido(); dir = Kaleido_jll.artifact_dir) + # We push the mandatory plotly flag + push!(BIN.exec, "plotly") chromium_flags = ["--disable-gpu", Sys.isapple() ? "--single-process" : "--no-sandbox"] extra_flags = if plotly_version === missing (; kwargs...) @@ -72,12 +104,13 @@ function start(; push!(user_flags, "--$flag_name=$v") end end - BIN = Cmd(vcat(basic_cmds, chromium_flags, user_flags)) + # We add the flags to the BIN + append!(BIN.exec, chromium_flags, extra_flags) kstdin = Pipe() kstdout = Pipe() kstderr = Pipe() - kproc = + kproc = run(pipeline(BIN, stdin = kstdin, stdout = kstdout, stderr = kstderr), wait = false) process_running(kproc) || error("There was a problem starting up kaleido.") @@ -92,7 +125,7 @@ function start(; P.stderr = kstderr P.proc = kproc - res = readline(P.stdout) # {"code": 0, "message": "Success", "result": null, "version": "0.2.1"} + res = readline_noblock(P.stdout) # {"code": 0, "message": "Success", "result": null, "version": "0.2.1"} length(res) == 0 && error("Kaleido startup failed.") code = JSON.parse(res)["code"] code == 0 || error("Kaleido startup failed with code $code.") diff --git a/test/runtests.jl b/test/runtests.jl index 11f26f1..9cce873 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1,8 +1,17 @@ using Test +import Pkg +if Sys.iswindows() + # Fix kaleido tests on windows due to Kaleido_jll@v0.2.1 hanging + Pkg.add(;name = "Kaleido_jll", version = "0.1") +end @test_nowarn @eval using PlotlyKaleido -@testset "Start" begin - @test_nowarn PlotlyKaleido.start() + @testset "Start" begin + if Sys.iswindows() + PlotlyKaleido.start() + else + @test_nowarn PlotlyKaleido.start() + end @test PlotlyKaleido.is_running() end