Using local Julia modules in Pluto

1.3k views Asked by At

What is the correct way to import local modules in Pluto v0.18.0 notebooks with Julia 1.7.2? The using keyword adds exported members to the main namespace in Julia. Given a sample module, in foo.jl,

module Foo
    export bar
    function bar()
        return "baz"
    end
end

The following code cell works in a Pluto Notebook:

# "baz"
begin
    include("./foo.jl")
    using .Foo
    bar()
end

However, if I attempt to call bar from another cell, I get the following error:

# UndefVarError: bar not defined
bar()

Though I notice that Foo.bar() does work.

How do I add my own modules in a way that I get access to their exported members directly in the notebook's namespace?

1

There are 1 answers

0
AsgerHB On BEST ANSWER

This discussion gives a possible solution. It describes a better way of getting the module reference than what I have in my question.

If the module is not the last definition in the file, the import function has to be redefined. A suggested name is to have a variant called "ingredients"

#ingredients (generic function with 1 method)
function ingredients(path::String)
    # this is from the Julia source code (evalfile in base/loading.jl)
    # but with the modification that it returns the module instead of the last object
    name = Symbol(basename(path))
    m = Module(name)
    Core.eval(m,
        Expr(:toplevel,
             :(eval(x) = $(Expr(:core, :eval))($name, x)),
             :(include(x) = $(Expr(:top, :include))($name, x)),
             :(include(mapexpr::Function, x) = $(Expr(:top, :include))(mapexpr, $name, x)),
             :(include($path))))
    m
end

Then the module can be loaded in like so (I don't know the reason why I have to say ingredients().Foo)

#Main.Foo.jl.Foo
Foo = ingredients("My Library/Foo.jl").Foo

and then with the module reference, you have to manually bring all exported variables into the global scope:

#bar = bar (generic function with 1 method)
bar = Foo.bar