Prevent Pkg.test from executing parent's `@main` function

When I test a local package using the test instruction in the Pkg REPL, the function called by the @main macro gets executed after the tests.

For example:

src/Foo.jl:

module Foo

main() = println("hello from main function")

export main

(@main)(args) = main()

end

test/runtests.jl:

using Foo, Test

@testset "Hello from tests" begin
    @test true
end

Results in:

(Foo) pkg> test
     Testing Foo
# [...]
     Testing Running tests...
Test Summary:    | Pass  Total  Time
Hello from tests |    1      1  0.0s
hello from main function
     Testing Foo tests passed

Is there any way to suppress the execution of @main in this scenario? In my real use-case, it is an expensive function. My apologies if this is obvious; I wasn’t able to find how to do it.

First thing, the @main macro isn’t calling a function. (@main) itself is a macro call isolated by parentheses, and it does some background registration before resolving as the name main. So, (@main)(args) = main() literally defines (main)(args) = main(), and you can see this 2nd method:

julia> methods(Foo.main)
# 2 methods for generic function "main" from Main.Foo:
 [1] main()
     @ REPL[2]:3
 [2] main(args)
     @ REPL[2]:7

This isn’t a trivial detail. If you defined a main(args) instead of main() to begin with, this 2nd method would overwrite it.

Second and more pertinent to the issue, I’m pretty sure the implicit import using Foo via export main is triggering the call when the test process ends. You can stop that with explicit named imports, import Foo to only import the name Foo, or removing export main. The last one seems to be the most appropriate: export main is not necessary for terminal Pkg apps, and although it’s mentioned at the end of the section for the julia terminal command, it’s immediately and vaguely discouraged so I don’t really know why it’s there. A plainer problem is if you have 2 packages with their own mains, implicit imports into the same module will ignore those names because of the conflict, so it’s better to reserve export for fairly unique names. If you do want an import to trigger a main call, you can pick one by name with using Foo: main.

Thanks!

I think that the module structure I was trying to implement may be correct in other languages but just isn’t the right way to do things in Julia.

It looks mostly correct to me, I only spotted the 2 problems mentioned earlier and only 1 needed an edit.