Create and use local module

Hi,

I want to make an application. So I do cd ; julia and then switch to Pkg mode and use generate to generate my application.

I then have a src/app.jl. Now I want to add a few files that do some fancy stuff. Apparently, I could use include to load those files but that’s bad because Revise doesn’t recognize it. The proper way is to make a module.

So I scope my files with the module keyword. Now I want to use them, but how?

Let’s say I have the following in my src/

main.jl

module test
# How to lod myPlot module here?
end # module

myPlot.jl

module myPlot

using Plots

function plotSine()
    x = LinRange(0,1,11)
    y = sin.(x)
    gr()
    p = plot(x,y, title="hi test 2")
    plot!(p,x,y.*2)
    display(p)
end

end

include(“myPlot.jl”)
using .myPlot

Perhaps your example is too simple, but if you are actually testing some plots, than you can put the

into a file and include that file each time. Not everything needs to be a module.

There is also the includet (include-track) option:

using Revise
includet("myPlot.jl")

which will then track the changes of the file included, the module included.

The only valid workflow I found consists of using Revise and Revise works with includet and not with include. Now I don’t want to clutter my codebase with includets, so I have to use a module. I can’t help it, that’s how Julia works.

So thanks, but my question remains. :slight_smile:

Of course I know about includet. Now I could includet myPlot.jl separately and test it separately but that just seems wrong because the file might not be isolated like that. So currently I can’t see how anyone would ever use include in their code, forcing me to make everything a module.

Put your module in your LOAD_PATH. Then

using MyModule

will start it up without using include. You’ll also get all the benefits of Revise.

I don’t like this idea sorry. I don’t want to use environment variables for loading modules. That just seems weird. Ther’es a Project.toml and a Manifest.toml which should take care of such things, no?

But I agree that registering the module correctly is probably my issue here.

Except what other said: It’s weird to use a module for everything.

I think the solution is as follows.

  1. Do ]dev . in your package environment. That way using MyPackage is visible everywhere and you can do using MyPackage inside your testing module
  2. I think there is some confusion about what
# test/runtests.jl
module test
    include("MyPackage.jl")
    using .MyPackage
end

does. When do include("test/runtests.jl") this will overwrite the last test module and load a new one. This means that any changes to MyPackage get brought in when you run the tests. So it will always be up to date.

I hope this is helpful.

LOAD_PATH is not a variable you set in your .login file. It’s easier than that and works well with the toml files.

If you projects/modules … live in Module_Directory, all you need to do is type

push!(LOAD_PATH," Module_Directory")

in the REPL or, better yet, put it in your .startup.jl file. You’ll never have to think about it again. Doing this enables Julia to find things in Project/src directories with ease.

Maybe I am missing the point but this works for me:

main.jl:

module myMain
# How to lod myPlot module here?

include("myPlot.jl")
using .myPlot

end # module

myPlot.jl:

module myPlot

using Plots

function plotSine()
    x = LinRange(0,1,11)
    y = sin.(x)
    gr()
    p = plot(x,y, title="hi test 2")
    plot!(p,x,y.*2)
    display(p)
end

end

Both files in d:\Temp, in the REPL:

julia> cd("d:\\temp")

julia> include("main.jl")

julia> myMain.myPlot.plotSine()

I once had a similar issue and got my help in this thread, maybe you find some insights too:

Perhaps the example you are providing is not representative of what you want. But:

  1. the code of the plotSine() function could well be in the global scope. That is, you could have a file name “plotsine.jl” with that code inside (without the function ... end. You can include that file using include(), see the plot, and if you want to modify its content, just modify it and include the file again. You don’t need any module for that, and you do not need revise for that either.

  2. You may have several functions in the same file, let say, file myfuncs.jl, with:

f(x) = x + 1
g(x) = abs(x)
h(x) = 2*x

You then can include that file directly and use those functions. If you modify that file, just include it again and the methods will be overwritten. Again, no module or Revise need for now.

  1. A slightly more sophisticated approach is to use Revise and includet. Instead of including again the file after each modification, use includet(myfuncs.jl). The modifications of the file will tracked. You only need one includet, which is being used in the REPL where you are working, no includets will permeate your code anywhere.

  2. You can includet(myPlots.jl) and that will track the modifications of that file (no additional module layer, like your main, needed there).

Finally, I do agree that there is a problem in that Revise does not track the modifications of a include()d file within a a file which was itself included with includet. It does track the modifications if the file is included (with include()) within a package. For greater projects in which it is natural that one has a properly organized project, one would use Revise and using MyProject, and the files included with include() anywhere within that projects are tracked by revise. This is the most common workflow (I think) for larger projects.

Explaining myself:

MyModule.jl:

module MyModule
  include("./mycode.jl")
end

mycode.jl:

f(x) = x + 1

Testing:

julia> using Revise

julia> includet("./MyModule.jl")

julia> MyModule.f(1)
2

shell> vim mycode.jl # changed the behaviour of f(x) inside mycode.jl

julia> MyModule.f(1) # the change in f was not tracked
2

julia> 

I think this is an issue. Perhaps someone can explain if there is a reason for the file not being tracked, or if we should file an issue.

EDIT: According to this post:

includet is thought to track only the file itself. The workflow that is recommended is that of @ctkelley, meaning, if the module is in the current directory:

using Revise
push!(LOAD_PATH,"./")
using MyModule

Not bad. One can add this push!(LOAD_PATH,"./") to the startup.jl file and then just use the modules in the current working directory directly.

1 Like

On windows the command is:

push!(LOAD_PATH,".\\")

The other method is via Pkg, attached my installation description, as I do not know how to attach documents here, the description is added in form of figures:



(I am happy to share the original word file, if someone can put it somewhere on a public place for further improvement)