Recommended development workflow in VSCode

I’m trying to move from Juno to VSCode, but I’m having trouble getting introspection to work well with my code setup. In Juno, I made local modules available by push!ing to LOAD_PATH. This post indicates that this is not a viable option in VSCode; I don’t understand what I should be doing instead.

I would like to:

  1. Write modules that I can…
  2. Import from other modules/scripts I’m working on, all while…
  3. getting the benefits of VSCode language server introspection, etc.

All my code is local (no public github projects). My current setup is…

Project.toml
Manifest.toml
src/
 - Main.jl 
 - Module1.jl 
 - Module2.jl 
test/
 - TestModule1.jl 
 - TestModule2.jl 

In Juno, I would push the src/ folder onto LOAD_PATH. What is VSCode-conformant mechanism for making the modules available for import to each other and Main?

I’d prefer to retain my current code setup, but I’m willing to refactor my code in any way necessary to get autocompletion in VSCode.

I’ve been trying to figure this out for days, to no avail. Please help!!!

2 Likes

You shouldn’t need to modify LOAD_PATH. Instead, you should add whatever projects you are working on and need, even locally, to an environment, which could be the global one.

This means doing Pkg.add(“/path/to/some/code”), or Pkg.dev depending on what you need (see the Pkg docs).

When you open a folder that contains a Project file in VSCode, that environment will be activated automatically, and all the packages added to that project will be available. If you open a folder that isn’t a project, the global environment will be selected.

1 Like

The closest equivalent to what you were doing before is to Pkg.dev all the folders you need to your global environment.

1 Like

Thank you; that’s helpful. A couple follow-on questions.

Pkg.add(path="path_to_code") seems to require that path_to_code be the root of a git repository. Is that correct?

Currently my project’s Modules are free to import each other directly. For instance, referring to my project layout above, Main.jl has a clause using Module2 at the top of the file. This style of code organization worked fine when I was allowed to push! the src directory to LOAD_PATH, but appears to be broken if LOAD_PATH is not modified.

Reviewing the code loading section of the Julia docs suggests that in order for my modules to be able to import one another, it’s required to decompose each into a separate package (and make each into it’s own git repo). Is that right? It seems like a lot of trouble, just to get import and using to work…

Part of my confusion stems from my coming to Julia from Python, where several modules in a package can import one-another easily using relative imports: if this were a python package, the Main file would have from . import Module1. Is this not possible in Julia?

What is the recommended way to enable easy importing between modules in the same source directory without making each of them its own package?

I think I understand yor situation a bit better. The advice above, that is to Pkg.add/dev all the folders applies to standalone packages/projects.

For your filestructure, which I think is a single package, you would instead use submodules.

You can simply include("Module1.jl") from Main.jl. Then to access Module1 from Main’s scope, you would do using .Module1. From Module1 you would do using ..Main to access names defined in Main. The dots are there to define the scope of the imports.

See Modules · The Julia Language and How to arrange a package with submodules and multiple files? - #6 by Gu_Junhua

I think that should answer your questions. I believe the only difference from Python is that you need to include the file (prior to doing using/import), since using and import don’t look things up by filename. This does mean you need to make sure you don’t include the same file multiple times.

1 Like

Thanks again; super helpful. I did as you suggested, refactoring into submodules using include()s, but I’m still having trouble getting autcompletion in test scripts. I now have a package called Cluster, with a sub-module Quadforms and I want to write a test script for the submodule.

# ./Cluster
Project.toml
Manifest.toml
src/
 - Cluster.jl 
 - Quadforms.jl 
test/ 
 - TestQuadforms.jl 

# Cluster.jl 
module Cluster 
include("Quadforms.jl")
end 

# TestQuadforms.jl 
using Cluster.Quadforms # <-- perhaps my error is here?

@test Quadforms.function_to_test(1.0)==3.0

In TestQuadforms, when I type @test Quadforms., VSCode does not provide a dropdown of all names in Quadforms as I would expect. Also, I cannot use ‘go to definition’. What am I doing wrong here?

I was looking at some other projects. It appears that Distributions and FinEtools both explicitly export tons of names from local modules in their root module by the same name. Is that the only/best way to address my test script problem?

You’ve been an enormous help; I’ve been foundering over this for several days. Thanks to you I’m seeing a light at the end of the tunnel. Thanks again.

I also have another repository, whether exports are done from a module specifically constructed for that purpose: MeshCore.jl/Exports.jl at master · PetrKryslUCSD/MeshCore.jl · GitHub

In other words, instead of exporting from all the modules, this one particular module imports the things that I think constitute the API, and then exports those symbols. The advantage is that if one doesn’t want to have all those exported symbols in the environment, is easy to pick and choose; on the other hand, for someone who wishes to have all those symbols available, including this one module (submodule of the MeshCore package) provides the public interface in one shot.

1 Like

Very interesting. Thank you. Your comment brings another question to mind. Is there a way in Julia to segregate the private (package-local) API from the public (package-external) API, that is, to share code between submodules that I don’t want accessible from outside of the package? And I’d like to do this without resorting to include().

For example, my package, Cluster, contained a Utils sub-module which is:

  1. used by OTHER submodules in my package…
  2. but which I don’t want to be visible outside the package (by calling/client code)…
  3. and I want to avoid using include("Utils.jl") in the submodules to avoid redundant code/typing problems…
  4. and all without breaking out Utils into its own package.

Can it be done in Julia?

It is straightforward in python because modules of a package can load each other’s code without going through the package root module (init.py). The public API can be placed in the package __init__.py file, thus achieving segregation of public and private APIs.

Thanks again!

I do use submodules extensively. Their files are included. They are are included just once, and everywhere else they are needed they are "using"ed.

The trick

include("MyModule.jl")
using .MyModule

should appear very clearly in the documentation (Home · Julia in VS Code).

Many thanks to the developers of this Julia extension for VS Code !

1 Like

It really isn’t a “trick”. It is standard application of the principle of nesting of modules, the relative versus absolute path: Modules · The Julia Language

But you are right in that the documentation for the editor might benefit from an example that shows this.

1 Like

Some time ago I really appreciated atom-julia-client/workflow.md at master · JunoLab/atom-julia-client · GitHub , a document that

  1. clearly explains the workflow problems
  2. offers solutions
  3. explains how and why these solutions work.