Hello, I have the following questions.
Below is a MWE script that I want to run with julia --project=myLocalEnv .\mySimpleScript.jl. What I’ve discovered is that even if the package DataFrames is not installed in myLocalEnv, the script will run correctly since "@#.#" usually belongs to the LOAD_PATH and in my case DataFrames were installed in that global environment.
# LOAD_PATH = ["@", "@stdlib"]
# direct assignment to that variable has no effect
# these lines help to prevent "leaking"
# packages from
empty!(LOAD_PATH)
push!(LOAD_PATH, "@")
push!(LOAD_PATH, "@stdlib")
using DataFrames
function main()
println("HELLO WORLD FROM MAIN FUNCTION!")
println("$ARGS")
@show Base.active_project()
@show Base.current_project()
@show pathof(DataFrames)
@show LOAD_PATH
dat = DataFrame("a"=>[1, 2, 3], "b"=>[4, 5, 6] )
@show dat
end
if abspath(PROGRAM_FILE) == @__FILE__
main()
end
So, my questions are:
Is this a correct (idiomatic?) way to prevent using packages from a global environment?
What you have encountered is the environment stack. The idiomatic approach to this is to keep your version specific global environment mostly empty. Specifically, we do not recommend having a package such as DataFrames.jl in your global default environment.
As an alternative, you can add it to another shared environment such as “@datascience”. The “@” will install the package in a shared space in your ~/.julia/environments that you can access from anywhere.
Also note that Julia is stricter here if you build a Julia package rather than a script.
Because only the second version modifies the existing variable Base.LOAD_PATH, which determines where packages can be loaded from. The first creates a new variable Main.LOAD_PATH that julia’s package loading won’t know or care about. (Main is the implicit module in which your script code runs.)
Interesting… So, in layman terms, by writing LOAD_PATH = ... (with a scope in Main) I’ve accidentally created a new variable that shadowed Base.LOAD_PATH. Is my understanding correct? By the way, is there any special function that can show the scope (module? function?) to which a variable belongs?
help?> @which
@which
Applied to a function or macro call, it evaluates the arguments to the specified call, and returns the Method object for the method that would be called for those arguments.
Applied to a variable, it returns the module in which the variable was bound. It calls out to the which function.
Note that simply using @which is sufficient to establish the binding:
julia> @which LOAD_PATH # In a fresh session
Base
julia> LOAD_PATH = []
ERROR: cannot assign a value to imported variable Base.LOAD_PATH from module Main
Stacktrace:
[1] top-level scope
@ REPL[1]:1
Thanks for the explanation! @which LOAD_PATH, unfortunately, didn’t work in my script, but what it showed through REPL is perfectly enough for my understanding of inner workings for now.
That’s because @which is defined in the InteractiveUtils standard library, which is automatically loaded in an interactive repl session but not when running a script. You could do using InteractiveUtils at the top of your script, but it’s probably not the best idea, it’s meant specifically for interactive exploration.