fredrikekre / Literate.jl

Simple package for literate programming in Julia
https://fredrikekre.github.io/Literate.jl
Other
538 stars 63 forks source link

Include error: no such file or directory #251

Closed gbruer15 closed 1 week ago

gbruer15 commented 1 week ago

sandbox() sets include() to always be relative to the example file. Is there a reason for this? I have a use case where I'd like to include a file from a different directory that includes another file, so I get an error when running with Literate.jl even though the script runs fine on its own.

Here is a minimum failing example:

Here are the files:

$ ls mfe
example.jl utils
$ ls mfe/utils/
utils.jl  utils_A.jl
$ cat mfe/utils/utils_A.jl 
A() = println("Hello")
$ cat mfe/utils/utils.jl 
include("utils_A.jl")
$ cat example_direct.jl
include("utils/utils_A.jl")
A()
$ cat example_indirect.jl
include("utils/utils.jl")
A()

Running normally works fine.

$ julia mfe/example_direct.jl
Hello
$ julia mfe/example_indirect.jl
Hello

Running with Literate.jl fails with the indirect include:

$ julia --project=. -e 'import Literate; Literate.markdown("mfe/example_direct.jl", "mfe"; execute=true)'
[ Info: generating markdown page from `~/a/curr_research/Literate.jl/mfe/example_direct.jl`
[ Info: writing result to `~/a/curr_research/Literate.jl/mfe/example_direct.md`
$ julia --project=. -e 'import Literate; Literate.markdown("mfe/example_indirect.jl", "mfe"; execute=true)'
[ Info: generating markdown page from `~/a/curr_research/Literate.jl/mfe/example_indirect.jl`
ERROR: LoadError: SystemError: opening file "/home/gbruer/a/curr_research/Literate.jl/mfe/utils_A.jl": No such file or directory
in expression starting at /home/gbruer/a/curr_research/Literate.jl/mfe/utils/utils.jl:1
in expression starting at /home/gbruer/a/curr_research/Literate.jl/mfe/example_indirect.md:1
when executing the following code block from inputfile `~/a/curr_research/Literate.jl/mfe/example_indirect.jl`

```julia
include("utils/utils.jl")
A()

Stacktrace: [1] error(s::String) @ Base ./error.jl:35 [2] execute_block(sb::Module, block::String; inputfile::String, fake_source::String, softscope::Bool) @ Literate ~/a/curr_research/Literate.jl/src/Literate.jl:905 [3] execute_block @ ~/a/curr_research/Literate.jl/src/Literate.jl:881 [inlined] [4] execute_markdown!(io::IOBuffer, sb::Module, block::String, outputdir::String; inputfile::String, fake_source::String, flavor::Literate.DocumenterFlavor, image_formats::Vector{Tuple{MIME, String}}, file_prefix::String, softscope::Bool) @ Literate ~/a/curr_research/Literate.jl/src/Literate.jl:644 [5] (::Literate.var"#28#30"{Dict{String, Any}, IOBuffer, Module, Literate.CodeChunk, Int64})() @ Literate ~/a/curr_research/Literate.jl/src/Literate.jl:616 [6] cd(f::Literate.var"#28#30"{Dict{String, Any}, IOBuffer, Module, Literate.CodeChunk, Int64}, dir::String) @ Base.Filesystem ./file.jl:112 [7] markdown(inputfile::String, outputdir::String; config::Dict{Any, Any}, kwargs::@Kwargs{execute::Bool}) @ Literate ~/a/curr_research/Literate.jl/src/Literate.jl:615 [8] top-level scope @ none:1

gbruer15 commented 1 week ago

A quick fix for this is to put this code at the top of your example script:

include(x) = Base.include(@__MODULE__, x)
let
    s = current_task().storage
    if !isnothing(s)
        s[:SOURCE_PATH] = @__FILE__
    end
end

It sets include back to the standard form and sets the source file for include to be the current source file.