Skip to content

Conversation

@mind6
Copy link
Contributor

@mind6 mind6 commented Jul 24, 2025

No description provided.

@itsdfish
Copy link
Owner

Thank you for making this pull request. Once a few issues are fixed, I think this will be very helpful.

When I run your fork locally, I get the following problem starting on this line:

[ Info: Exporting symbols from DistributionsExt to PackageExtensionsExample
┌ Error: Error during loading of extension DistributionsExt of PackageExtensionsExample, use `Base.retry_load_extensions()` to retry.
│   exception =
│    1-element ExceptionStack:
│    InitError: invalid using path: "ext" does not name a module
│    Stacktrace:
│      [1] top-level scope
│        @ none:1
│      [2] top-level scope
│        @ ~/.julia/dev/PackageExtensionsExample.jl/ext/DistributionsExt.jl:33
│      [3] eval
│        @ ./boot.jl:430 [inlined]
│      [4] __init__()
│        @ DistributionsExt ~/.julia/dev/PackageExtensionsExample.jl/ext/DistributionsExt.jl:29
│      [5] run_module_init(mod::Module, i::Int64)
│        @ Base ./loading.jl:1378
│      [6] register_restored_modules(sv::Core.SimpleVector, pkg::Base.PkgId, path::String)
│        @ Base ./loading.jl:1366
│      [7] _include_from_serialized(pkg::Base.PkgId, path::String, ocachepath::String, depmods::Vector{Any}, ignore_native::Nothing; register::Bool)
│        @ Base ./loading.jl:1254
│      [8] _include_from_serialized (repeats 2 times)
│        @ ./loading.jl:1210 [inlined]
│      [9] _require_search_from_serialized(pkg::Base.PkgId, sourcepath::String, build_id::UInt128, stalecheck::Bool; reasons::Dict{String, Int64}, DEPOT_PATH::Vector{String})
│        @ Base ./loading.jl:2057
│     [10] _require(pkg::Base.PkgId, env::Nothing)
│        @ Base ./loading.jl:2527
│     [11] __require_prelocked(uuidkey::Base.PkgId, env::Nothing)
│        @ Base ./loading.jl:2388
│     [12] #invoke_in_world#3
│        @ ./essentials.jl:1089 [inlined]
│     [13] invoke_in_world
│        @ ./essentials.jl:1086 [inlined]
│     [14] _require_prelocked
│        @ ./loading.jl:2375 [inlined]
│     [15] _require_prelocked
│        @ ./loading.jl:2374 [inlined]
│     [16] run_extension_callbacks(extid::Base.ExtensionId)
│        @ Base ./loading.jl:1544
│     [17] run_extension_callbacks(pkgid::Base.PkgId)
│        @ Base ./loading.jl:1576
│     [18] run_package_callbacks(modkey::Base.PkgId)
│        @ Base ./loading.jl:1396
│     [19] __require_prelocked(uuidkey::Base.PkgId, env::String)
│        @ Base ./loading.jl:2399
│     [20] #invoke_in_world#3
│        @ ./essentials.jl:1089 [inlined]
│     [21] invoke_in_world
│        @ ./essentials.jl:1086 [inlined]
│     [22] _require_prelocked(uuidkey::Base.PkgId, env::String)
│        @ Base ./loading.jl:2375
│     [23] macro expansion
│        @ ./loading.jl:2314 [inlined]
│     [24] macro expansion
│        @ ./lock.jl:273 [inlined]
│     [25] __require(into::Module, mod::Symbol)
│        @ Base ./loading.jl:2271
│     [26] #invoke_in_world#3
│        @ ./essentials.jl:1089 [inlined]
│     [27] invoke_in_world
│        @ ./essentials.jl:1086 [inlined]
│     [28] require(into::Module, mod::Symbol)
│        @ Base ./loading.jl:2260
│     [29] eval
│        @ ./boot.jl:430 [inlined]
│     [30] include_string(mapexpr::typeof(REPL.softscope), mod::Module, code::String, filename::String)
│        @ Base ./loading.jl:2734
│     [31] invokelatest(::Any, ::Any, ::Vararg{Any}; kwargs::@Kwargs{})
│        @ Base ./essentials.jl:1055
│     [32] invokelatest(::Any, ::Any, ::Vararg{Any})
│        @ Base ./essentials.jl:1052
│     [33] inlineeval(m::Module, code::String, code_line::Int64, code_column::Int64, file::String; softscope::Bool)
│        @ VSCodeServer ~/.vscode/extensions/julialang.language-julia-1.149.2/scripts/packages/VSCodeServer/src/eval.jl:271
│     [34] (::VSCodeServer.var"#69#74"{Bool, Bool, Bool, Module, String, Int64, Int64, String, VSCodeServer.ReplRunCodeRequestParams})()
│        @ VSCodeServer ~/.vscode/extensions/julialang.language-julia-1.149.2/scripts/packages/VSCodeServer/src/eval.jl:181
│     [35] withpath(f::VSCodeServer.var"#69#74"{Bool, Bool, Bool, Module, String, Int64, Int64, String, VSCodeServer.ReplRunCodeRequestParams}, path::String)
│        @ VSCodeServer ~/.vscode/extensions/julialang.language-julia-1.149.2/scripts/packages/VSCodeServer/src/repl.jl:276
│     [36] (::VSCodeServer.var"#68#73"{Bool, Bool, Bool, Module, String, Int64, Int64, String, VSCodeServer.ReplRunCodeRequestParams})()
│        @ VSCodeServer ~/.vscode/extensions/julialang.language-julia-1.149.2/scripts/packages/VSCodeServer/src/eval.jl:179
│     [37] hideprompt(f::VSCodeServer.var"#68#73"{Bool, Bool, Bool, Module, String, Int64, Int64, String, VSCodeServer.ReplRunCodeRequestParams})
│        @ VSCodeServer ~/.vscode/extensions/julialang.language-julia-1.149.2/scripts/packages/VSCodeServer/src/repl.jl:38
│     [38] #67
│        @ ~/.vscode/extensions/julialang.language-julia-1.149.2/scripts/packages/VSCodeServer/src/eval.jl:150 [inlined]
│     [39] with_logstate(f::VSCodeServer.var"#67#72"{Bool, Bool, Bool, Module, String, Int64, Int64, String, VSCodeServer.ReplRunCodeRequestParams}, logstate::Base.CoreLogging.LogState)
│        @ Base.CoreLogging ./logging/logging.jl:524
│     [40] with_logger
│        @ ./logging/logging.jl:635 [inlined]
│     [41] (::VSCodeServer.var"#66#71"{VSCodeServer.ReplRunCodeRequestParams})()
│        @ VSCodeServer ~/.vscode/extensions/julialang.language-julia-1.149.2/scripts/packages/VSCodeServer/src/eval.jl:263
│     [42] #invokelatest#2
│        @ ./essentials.jl:1055 [inlined]
│     [43] invokelatest(::Any)
│        @ Base ./essentials.jl:1052
│     [44] (::VSCodeServer.var"#64#65")()
│        @ VSCodeServer ~/.vscode/extensions/julialang.language-julia-1.149.2/scripts/packages/VSCodeServer/src/eval.jl:34
│    during initialization of module DistributionsExt
└ @ Base loading.jl:1550

After this point, cool_function and @cool_macro work. However, MyExtType is not defined in the subsequent commands. Do you know how to fix this?

Thanks again!

@mind6
Copy link
Contributor Author

mind6 commented Jul 26, 2025

It worked on Julia 1.10. In 1.11 they changed the extension mechanism. If you comment out the init() code, and run it AFTER you get to the REPL, it works. I'm just not sure how to make it automatic in 1.11 yet.

@mind6
Copy link
Contributor Author

mind6 commented Jul 26, 2025

I used a hack that delays the eval until after __init__() returns. I don't think you can really rely on this, but it shows what's happening in 1.11

@itsdfish
Copy link
Owner

Thanks for the fix!

@itsdfish itsdfish merged commit 41581ab into itsdfish:main Jul 26, 2025
2 checks passed
@itsdfish
Copy link
Owner

@mind6, would you be willing to advise on the proper way to unit test the new components you added? I have little experience with macros.I tried the following, but received a warning and error.

@testset "before import" begin
    @test length(methods(cool_function)) == 0
    # warning here
    @test_throws LoadError @macroexpand @cool_macro
    @test !isdefined(PackageExtensionsExample,:MyExtType)
end

@testset "after import" begin
    using Distributions
    @test length(methods(cool_function)) == 1
    @test @macroexpand @cool_macro
    # error here
    @test isdefined(PackageExtensionsExample,:MyExtType)
end

@mind6
Copy link
Contributor Author

mind6 commented Jul 26, 2025

Sure, you can try this:

using Test
@testset "cool_macro" begin
   tmpmod = Module()
   @test try
      @eval tmpmod begin
         using PackageExtensionsExample
         @cool_macro
      end
      false
   catch e
      e isa LoadError
   end
end

@itsdfish
Copy link
Owner

Thank you. Unfortunately, I'm not sure if that works. It passes both when distributions is imported and when it is not imported. I was hoping to have two tests: one showing it has an error before Distributions is imported, and a second test showing that it works after Distributions is imported. Any ideas.

I fixed the other error by increasing the delay after importing Distributions:

    sleep(.1)
    @test isdefined(PackageExtensionsExample, :MyExtType)

Increasing the delay in the source code did not work.

@mind6
Copy link
Contributor Author

mind6 commented Jul 26, 2025

right, I guess temporary modules aren't set up as packages and it does nothing when you import another package. You might try ask on discourse if there's any way to catch a LoadError.

@mind6
Copy link
Contributor Author

mind6 commented Jul 29, 2025

try this:

#=
You should be able run this script from any directory with any project settings.
=#

using Pkg, Test

cd(@__DIR__)

# activates the project in the script's directory
Pkg.activate(".")

# adds the local PackageExtensionsExample package to the script project (don't use Pkg.add here)
Pkg.develop(path="../")

using PackageExtensionsExample

@testset "before loading Distributions" begin
	@test try
		Core.eval(Main, :(
			module m1
			using PackageExtensionsExample
			@cool_macro
			end
		))
		false
	catch e

		for (exc, bt) in Base.current_exceptions()
			showerror(stdout, exc, bt)
			println()
		end

		e isa LoadError
	end
end

using Distributions

@testset "after loading Distributions" begin
	@test try
		Core.eval(Main, :(
			module m2
			using PackageExtensionsExample
			@cool_macro
			end
		))
		true
	catch e
		false
	end
end

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

Successfully merging this pull request may close these issues.

2 participants