How to add a folder path in your .jl script

I recently moved from matlab to julia and I want to add a folder path in my script (similar to addpath(“folder path”) ) in my julia script, so that I can use any function files inside that folder? For example, I am using something like this:

push!(LOAD_PATH,“folder path”)
include(“file_name.jl”)

resulting in error. I also tried require(“file_name.jl”), still resulting in error. Can anyone help plz?

What’s the error? I would expect include("file_name.jl") to work in this case.

1 Like

LOAD_PATH is relevant to loading of packages and modules via import or using. It’s content has no bearing on code inclusion with include.

You either need to specify the full path when using include (relative to the path of the calling file, or the working dir in the REPL), or wrap the functions in a module and load it via import.

The latter method is certainly the more julian.

See also: Newbie question on search path

2 Likes

You shouldn’t be using LOAD_PATH for this. You should have a Project.toml or Manifest.toml in your directory and use import Pkg; Pkg.activate(".")

It could be a problem with “folder path”. Does it exist? Do you have the separators right? Are you using the tilde ~? if so, try something like this:

dir = expanduser("~/path/to/file/")
push!(LOAD_PATH, dir)

Short answer: Julia doesn’t work like Matlab in that way.

For a longer answer, first some background for those who don’t know Matlab. In Matlab functions are organized with one public function per file, and the filename must match the function name. There may be additional private subfunctions in each file, but those are only available within the file (unless you do some trickery). To decide which files, and thus functions, are available for use, Matlab has a path variable where you add directories, and all *.m files within those directories are automatically imported.

The closest Julia analogy is to consider each such directory as a package, and each file corresponds to an exported function. Then adding a Julia package directory to LOAD_PATH becomes similar to Matlab’s addpath, with the difference that the actual activation of a package is triggered by a using statement.

There are more and arguably better options in Julia but the most direct translation of a Matlab code base would be to convert each directory with functions to a package, such that this directory structure

stuff
├── a.m
└── b.m

becomes

Stuff
├── Project.toml
└── src
    ├── a.jl
    ├── b.jl
    └── Stuff.jl

where Stuff.jl contains

module Stuff
export a, b
include("a.jl")
include("b.jl")
end

Notice, however, that if a.m and b.m have subfunctions, those may clash and need to be renamed so they don’t.

Disclaimer: I haven’t used Matlab for several years and never a more recent version than ~2013, so if things have changed drastically in the last few years, this might be outdated advice.

7 Likes

Having also come from Matlab some time ago, I can definitely second the advice of organizing your code by making your own packages.

Not so much related to the above scenario, but one other trick that can be useful for quick one-off scripts is @__DIR__ – e.g.:

cd(@__DIR__)
# then do something with files the script directory

or

read/dlmread/include/whatever(@__DIR__*"somefile.ext")

etc.

1 Like

Almost there

I myself push!() my custom package library onto LOAD_PATH in much the same way as you do in your example @sxd190026.

And, despite some of the comments that almost seem to imply otherwise, I don’t believe this is necessarily a bad technique.

In fact, I find it is one of the easiest ways to add your custom library of utilities to new Julia projects. I think the only real drawback is that it doesn’t lend itself quite as well to sharing these Julia environments with other co-workers.

LOAD_PATH

As @skleinbo said:

  • push!(LOAD_PATH, "/abs/path/to/my/package_lib") essentially adds a package library folder to Julia’s search path.
  • That means include() (file loading mechanism) is unaffected by LOAD_PATH.
  • However: using & import (package loading mechanisms) are affected by LOAD_PATH.

include() vs (using or import)

include("relative/path/to/file.jl"):

  • Loads code from file.jl.

import MyAwesomePackage:

  • Loads entire “package” MyAwesomePackage.

using MyAwesomePackage:

  • Essentially does the same as import MyAwesomePackage
  • But also makes any symbols export-ed from MyAwesomePackage directly available in the caller’s scope.

Also note that both using and import can be used with already-loaded modules (instead of packages) - but we’ll ignore that complexity for now (I don’t find it to be as useful in typical cases - or this discussion).

So what was missing?

There were really only 2 things missing from your solution:

  1. You should import your code as a package instead of loading it as a file.
    • using MyAwesomePackage – instead of – include("file_name.jl)
  2. Packages need to be wrapped in a module - end block.

So, in "/abs/path/to/my/package_lib", I suggest you create a test package:

#MySingleFilePackage.jl
module MySingleFilePackage #Module needs to match file/package name

dosomething() = println("Execute all algorithms!")

export dosomething #If you don't want people to prepend call with "MySingleFilePackage."

end #module MySingleFilePackage

And try it out in your script:

#Just try not to run push!() more than once in your scripts:
push!(LOAD_PATH, "/abs/path/to/my/package_lib")

using MySingleFilePackage
dosomething()

What if I want to create a multi-file package?

Then I suggest you follow the structure for full-blown package described by @GunnarFarneback.

1 Like

I would advise against this myself. In most cases, I find it is bad practice to change the user’s directory without her knowledge. This is typically done in things like bash files - but that’s because it typically only affects the run environment of that particular bash script.

Agreed. I find the @__DIR__ macro particularly useful for locating files you keep in the same directory as your code.

However, I would suggest you use the joinpath() function instead of concatenating strings with *. It can avoid occasional issues with ill-formed paths, and is also platform-aware (Uses "\\" path-separators on Windows machines):

data = dlmread(joinpath(@__DIR__, "somefile.ext"))

Also note that @__DIR__ is typically unnecessary when calling include() because include() already searches relative to the caller’s directory.

1 Like

Yes, hence the note

for quick one-off scripts

1 Like

Thanks. wrapping the functions as modules makes it easy.

1 Like