Launching examples from a Julia package

I am trying to provide a convenience function for the users of my package that launchs Jupyter notebook examples from the command line without depending on IJulia:

module Foo

# ...

function examples()
  using IJulia
  notebook(dir=joinpath(@__DIR__,"examples"))
end

end

The user would then launch the examples with “Foo.examples()” from the Julia prompt. The code above doesn’t work because we are not allowed to have using statements inside of functions. Is there any solution around this?

I believe that we would benefit from having reproducible examples in Julia packages via a standardized process. Is there anything happening with this regards already?

1 Like

You could use eval: @eval using IJulia.

1 Like

Thank you @mauro3. I am getting a strange error message now saying that notebook() is not a valid method:

ERROR: MethodError: no method matching notebook()
The applicable method may be too new: running in world age 21816, while current world is 21820.
Closest candidates are:
  notebook(; dir, detached) at /home/juliohm/.julia/v0.6/IJulia/src/IJulia.jl:104 (method too new to be called from this world context.)

Yep. Maybe use invokelatest or also @eval.

2 Likes

Perfect @mauro3, the final solution for future reference:

module Foo
function examples()
  @eval using IJulia
  @eval notebook(dir=Pkg.dir("Foo","examples"))
end
end
3 Likes

Pkg.dir has a built in joinpath, so this can be elegantly written as
Pkg.dir("Foo", "examples")

1 Like

Thanks @baggepinnen, that is definitely more elegant :slight_smile:

Will update the answer and mark as solved.

The @__DIR__ you originally had is better than using Pkg.dir, as the former will work if the package is loaded from somewhere else on LOAD_PATH.

1 Like

Thank you @tkelman, I will unroll the changes and use @__DIR__ again, I always forget that Pkg.dir() is not portable.

@tkelman, actually @__DIR__ isn’t defined in the REPL? I tried calling the function after loading the package, and @__DIR__ is nothing.

Yeah depends whether you intend to write the code down in a .jl file that users will include, or as an example that they will copy-paste in the REPL. I think @__DIR__ was changed recently to behave as pwd() when used in the REPL, but that’s not exactly what you want for copy-pasted code.

1 Like

In that case, I will keep using Pkg.dir(), it should work in nearly 100% of the cases.

Why not

module Foo
using IJulia
function examples()
  notebook(dir=Pkg.dir("Foo","examples"))
end
end

@PetrKryslUCSD, I don’t want to depend on IJulia, that is why we delay the evaluation inside of the function. So everyone that needs to run the examples, will install IJulia.

Untried, but maybe that is avoidable by extracting the macro out of the @eval portion

module Foo
function examples()
  path = joinpath(@__DIR__, "examples")
  @eval using IJulia
  @eval notebook(dir=path)) 
end
end

Thank you @Evizero, unfortunately it doesn’t work, it says path is undefined?

Maybe try

@eval notebook(dir=$path)
1 Like

There are currently two possible solutions thanks to @mauro3, @Evizero, @adamslc and @tkelman:

Solution a)

function examples()
  @eval using IJulia
  opennotebook(dir) = notebook(dir=dir)
  Base.invokelatest(opennotebook, joinpath(@__DIR__,"..","examples"))
end

Solution b)

function examples()
  path = joinpath(@__DIR__,"..","examples")
  @eval using IJulia
  @eval notebook(dir=$path)
end

I am biased towards solution b), will update the answer in the thread.