Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Using include() with a computed value #7

Closed
staticfloat opened this issue May 18, 2023 · 7 comments
Closed

Using include() with a computed value #7

staticfloat opened this issue May 18, 2023 · 7 comments

Comments

@staticfloat
Copy link
Contributor

staticfloat commented May 18, 2023

Let's imagine that I want to use @safetestset to include a path that is computed at runtime, e.g.:

const msl_loc = Base.locate_package(Base.identify_package("ModelingToolkitStandardLibrary"))
const msl_dir = dirname(dirname(msl_loc))

@safetestset "Blocks: math" begin include(joinpath($msl_loc, "test/Blocks/math.jl")) end

This doesn't seem to work.

@YingboMa
Copy link
Owner

What if you move

const msl_loc = Base.locate_package(Base.identify_package("ModelingToolkitStandardLibrary"))
const msl_dir = dirname(dirname(msl_loc))

into the maco as well?

@staticfloat
Copy link
Contributor Author

What's what I'm doing right now, but it makes for pretty tedious code duplication:

@safetestset "Blocks: math" begin
        using ModelingToolkitStandardLibrary
        include(joinpath(Base.pkgdir(ModelingToolkitStandardLibrary), "test/Blocks/math.jl"))
    end
    @safetestset "Blocks: nonlinear" begin
        using ModelingToolkitStandardLibrary
        include(joinpath(Base.pkgdir(ModelingToolkitStandardLibrary),"test/Blocks/nonlinear.jl"))
    end
    @safetestset "Blocks: continuous" begin
        using ModelingToolkitStandardLibrary
        include(joinpath(Base.pkgdir(ModelingToolkitStandardLibrary),"test/Blocks/continuous.jl"))
    end
    @safetestset "Blocks: sources" begin
        using ModelingToolkitStandardLibrary
        include(joinpath(Base.pkgdir(ModelingToolkitStandardLibrary),"test/Blocks/sources.jl"))
    end
...

I know this is a little niche, it's just a little surprising that it's so difficult to interpolate something into the @safetestset macro.

@topolarity
Copy link

topolarity commented May 19, 2023

esc(quote
    Core.eval($__module__, :(module $$(Meta.quot(mod))
        using Test: @testset
        Expr(:macrocall, Symbol("@testset"), $$__source__, $$testname, $$expr)
    end))
    nothing
end)

Meta-programming is amazing. Macros are a mis-feature 🙃

@staticfloat
Copy link
Contributor Author

Hmmm, but doesn't this evaluate things in the calling module? That kind of defeats the purpose (and breaks the tests), right?

@topolarity
Copy link

topolarity commented May 20, 2023

Yeah you're right, that approach isn't viable

I think you'd probably have to resort to some questionable tricks like this:

# Compute list of globals to import from parent module
imports = filter(
    (Symbol[:eval, Symbol("#eval"), :include, Symbol("#include"), :__init__]),
    names(__module__, all=true))                 
quote
    @eval module $mod
        # Evaluate "import ..foo, ..bar, ..baz" to inherit globals from parent module
        $(Expr(:import, map(x->Expr(:., :., :., x), imports)...))
        
        using Test, SafeTestsets
        @testset $testname $expr
    end
    nothing
end

which still doesn't solve the problem of any imports you want to use, or locals.

@topolarity
Copy link

Ah, here's the trick. Eval locally before you interpolate:

@safetestset "Blocks: math" begin include($(@eval joinpath(msl_loc, "test/Blocks/math.jl"))) end

@staticfloat
Copy link
Contributor Author

You, sir, win the prize! That does indeed work fabulously.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants