Plots breaks incremental compilation

I haven’t managed to produce a MWE yet but I’m hoping someone has encountered a similar problem and can advise.

Basically I am writing a PackageB that uses RecipesBase, and a PackageA that uses both PackageB and Plots.jl (pythonplot backend).

When I do using PackageA the precompilation throws error Evaluation into the closed module Plots breaks incremental compilation as per stack trace below, and I don’t know what to do. If I run the code line by line in the PackageA module which uses PackageB and Plots, then everything is fine…

Any advice is welcome.
Thanks.

Stack trace error
julia> using PackageA
[ Info: Precompiling PackageA [536ffa49-1ac4-47b0-895d-f0a44f6a6d19]
ERROR: LoadError: Evaluation into the closed module `Plots` breaks incremental compilation because the side effects will not be permanent. This is likely due to some other module mutating `Plots` with `eval` during precompilation - don't do this.
Stacktrace:
 [1] eval
   @ .\boot.jl:368 [inlined]
 [2] _pre_imports(pkg::Plots.PythonPlotBackend)
   @ Plots C:\Users\jrafa\.julia\packages\Plots\B5j7d\src\backends.jl:380
 [3] _initialize_backend(pkg::Plots.PythonPlotBackend)
   @ Plots C:\Users\jrafa\.julia\packages\Plots\B5j7d\src\backends.jl:964
 [4] backend(pkg::Plots.PythonPlotBackend)
   @ Plots C:\Users\jrafa\.julia\packages\Plots\B5j7d\src\backends.jl:266
 [5] #pythonplot#316
   @ C:\Users\jrafa\.julia\packages\Plots\B5j7d\src\backends.jl:87 [inlined]
 [6] top-level scope
   @ c:\Users\jrafa\OneDrive\Julia_Code\PackageA\src\PackageA.jl:17
 [7] include
   @ .\Base.jl:419 [inlined]
 [8] include_package_for_output(pkg::Base.PkgId, input::String, depot_path::Vector{String}, dl_load_path::Vector{String}, load_path::Vector{String}, concrete_deps::Vector{Pair{Base.PkgId, UInt64}}, source::Nothing)
   @ Base .\loading.jl:1554
 [9] top-level scope
   @ stdin:1
in expression starting at c:\Users\jrafa\OneDrive\Julia_Code\PackageA\src\PackageA.jl:8
in expression starting at stdin:1
ERROR: Failed to precompile PackageA [536ffa49-1ac4-47b0-895d-f0a44f6a6d19] to C:\Users\jrafa\.julia\compiled\v1.8\PackageA\jl_F2E5.tmp.
Stacktrace:
  [1] error(s::String)
    @ Base .\error.jl:35
  [2] compilecache(pkg::Base.PkgId, path::String, internal_stderr::IO, internal_stdout::IO, keep_loaded_modules::Bool) 
    @ Base .\loading.jl:1707
  [3] compilecache
    @ .\loading.jl:1651 [inlined]
  [4] _require(pkg::Base.PkgId)
    @ Base .\loading.jl:1337
  [5] _require_prelocked(uuidkey::Base.PkgId)
    @ Base .\loading.jl:1200
  [6] macro expansion
    @ .\loading.jl:1180 [inlined]
  [7] macro expansion
    @ .\lock.jl:223 [inlined]
  [8] require(into::Module, mod::Symbol)
    @ Base .\loading.jl:1144
  [9] eval
    @ .\boot.jl:368 [inlined]
 [10] eval
    @ .\Base.jl:65 [inlined]
 [11] repleval(m::Module, code::Expr, #unused#::String)
    @ VSCodeServer c:\Users\jrafa\.vscode\extensions\julialang.language-julia-1.38.2\scripts\packages\VSCodeServer\src\repl.jl:222
 [12] (::VSCodeServer.var"#107#109"{Module, Expr, REPL.LineEditREPL, REPL.LineEdit.Prompt})()
    @ VSCodeServer c:\Users\jrafa\.vscode\extensions\julialang.language-julia-1.38.2\scripts\packages\VSCodeServer\src\repl.jl:186
 [13] with_logstate(f::Function, logstate::Any)
    @ Base.CoreLogging .\logging.jl:511
 [14] with_logger
    @ .\logging.jl:623 [inlined]
 [15] (::VSCodeServer.var"#106#108"{Module, Expr, REPL.LineEditREPL, REPL.LineEdit.Prompt})()
    @ VSCodeServer c:\Users\jrafa\.vscode\extensions\julialang.language-julia-1.38.2\scripts\packages\VSCodeServer\src\repl.jl:187
 [16] #invokelatest#2
    @ .\essentials.jl:729 [inlined]
 [17] invokelatest(::Any)
    @ Base .\essentials.jl:726
 [18] macro expansion
    @ c:\Users\jrafa\.vscode\extensions\julialang.language-julia-1.38.2\scripts\packages\VSCodeServer\src\eval.jl:34 [inlined]
 [19] (::VSCodeServer.var"#61#62")()
    @ VSCodeServer .\task.jl:484

1 Like

Plots.jl does a lot of weird/questionable stuff with evaluating things all over the place. Here is is evalling some other macro inside this function:

I guess it would be interesting to know what is happening at

@ c:\Users\jrafa\OneDrive\Julia_Code\PackageA\src\PackageA.jl:17

in your package that ends up calling this.

But I would also open an issue on the Plots.jl repo as this seems very brittle.

1 Like

@kristoffer.carlsson, thanks for your expert comments.

As requested, line 17 of PackageA is:

pythonplot(dpi=100)

I don’t have enough understanding of what’s going on yet to open an issue on the Plots.jl repo, but I will if I can’t get this resolved.

And are you calling that at top level in your package while it is getting precompiled, or something like that?

I think so.

The simplified structure of PackageA is approximately as follows:

module PackageA

using PackageB
using Plots
pythonplot(dpi=100)

# several include() of files with functions
# export some function

end

From the REPL doing using PackageB is fine.

However, using PackageA produces error indicated above.

Why are you calling pythonplot(dpi=100) there? Something like that will not survive until the time you load the package. If anything, it seems you would want to do

function __init__()
    pythonplot(dpi=100)
end

to have that executed when the package is loaded.

1 Like

Because I didn’t know any better. :sweat:

Thank you for your time and know-how :brain:

NB:
linking here the relevant section of the manual

2 Likes