Automatically load tooling with BasicAutoloads.jl

Hey folks!

If I write @btime, @be, @testset, @test, etc. in the REPL, I don’t want to see

ERROR: LoadError: UndefVarError: `@testset` not defined in `Main`
Suggestion: check for spelling errors or missing imports.
in expression starting at REPL[2]:1

If BenchmarkTools.jl / Chairmarks.jl / Test.jl / etc. are dev tools you use, then when you invoke them, you may, like me, want them to run rather than prompt for missing imports. To streamline my workflow slightly, I include the following in my ~/.julia/config/startup.jl file:

if isinteractive()
    import BasicAutoloads
    BasicAutoloads.register_autoloads([
        ["@b", "@be"]            => :(using Chairmarks),
        ["@benchmark"]           => :(using BenchmarkTools),
        ["@test", "@testset", "@test_broken", "@test_deprecated", "@test_logs",
        "@test_nowarn", "@test_skip", "@test_throws", "@test_warn", "@inferred"] =>
                                    :(using Test),
        ["@about"]               => :(using About; macro about(x) Expr(:call, About.about, x) end),
    ])
end

And add BasicAutoloads.jl, Chairmarks.jl, BenchmarkTools.jl, and About.jl to my default environment. This means that whenever I run one of the commands listed above for the first time in a REPL session, the appropriate package is automatically loaded.

More generally, BasicAutoloads.jl lets you run an arbitrary Julia expression when you type a symbol into the REPL for the first time. If you attempt to auto-load a package that you don’t have in any environment on your load path, you will get the interactive prompt to install it.


Inspired by this Zulip thread, @fredrikekre’s startup.jl, discussion with @tecosaur, and feedback+advice about the interactive prompt from @aplavin

31 Likes

Really cool! Just wanted to share this snippet which will automatically load Revise before importing any package that is under development:

if isinteractive()
    using BasicAutoloads
    using Pkg
    BasicAutoloads.register_autoloads([
        [pkg.name for (_, pkg) in Pkg.dependencies() if pkg.is_direct_dep && pkg.is_tracking_path] => :(using Revise),
    ])
end

Edit: Could add this as an example to the readme?

2 Likes

Oh that’s so clever! And it can visibly improve startup times:

x@fedora:~/.julia/dev/julia$ julia --banner=short --startup-file=no
  o  | Version 1.11.0-beta1 (2024-04-10)
 o o | Official https://julialang.org/ release
julia> @time using BasicAutoloads
  0.017424 seconds (19.68 k allocations: 916.914 KiB)

julia> @time using Revise
  0.513514 seconds (763.44 k allocations: 47.495 MiB, 4.32% gc time, 0.78% compilation time)

It’s not perfect in that it won’t track a package that is not in the dev dependencies of the environment Julia is started in, nor packages loaded indirectly (i.e. not at the REPL) but could still be useful for some people. I’d accept a PR adding it to the readme!

1 Like