Skip to content

Commit

Permalink
Some enhacements to is_loaded_directly (#1880)
Browse files Browse the repository at this point in the history
  • Loading branch information
lgoettgens authored Oct 29, 2024
1 parent 814f22b commit 193e1b8
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 22 deletions.
42 changes: 36 additions & 6 deletions src/utils.jl
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
function is_loaded_directly()
try
@static if VERSION < v"1.11.0-"
@debug "is_loaded_directly: VERSION < 1.11.0-"
# Check if were loaded from another package
# if VERSION < 1.7.*, only the "other" package will have the
# _tryrequire_from_serialized in the backtrace.
Expand All @@ -12,22 +13,51 @@ function is_loaded_directly()
# or one with four arguments (hence five as the function name is the first argument)
# 'using Package' serialized will have a version with less arguments
bt = Base.process_backtrace(Base.backtrace())
@debug "is_loaded_directly: full backtrace:\n$(sprint(show, "text/plain", bt))"
Base.filter!(sf -> sf[1].func === :_tryrequire_from_serialized, bt)
return length(bt) == 0 ||
(length(bt) == 1 && length(only(bt)[1].linfo.specTypes.parameters) < 4)
length_bt = length(bt)
@debug "is_loaded_directly: `_tryrequire_from_serialized` appears $(length_bt) times in backtrace"
length_bt == 0 && return true
length_bt != 1 && return false
params = only(bt)[1].linfo.specTypes.parameters
@debug "is_loaded_directly: `_tryrequire_from_serialized` gets called with parameters of type $(params)"
return length(params) < 4
else
@debug "is_loaded_directly: VERSION >= 1.11.0-"
# Starting with julia 1.11, the package loading was completely revamped.
# The only difference in the callstack is the line number of the call to _include_from_serialized
# inside of the _require_search_from_serialized function.
# To make it a bit more robust, we check the difference between the line number of the beginning
# of _require_search_from_serialized and the call to _include_from_serialized.
# For `using OtherPackage`, the difference is 61, while for `using Package`, the difference is 75 or 78
# (on all 1.11 pre-releases up to 1.11.0-rc1 and 1.12.0-DEV.896, which are the newest at the time of writing this).
# for 1.12.0-DEV.1322 the differences are 72 and 88
bt = Base.process_backtrace(Base.backtrace())
@debug "is_loaded_directly: full backtrace:\n$(sprint(show, "text/plain", bt))"
Base.filter!(sf -> contains(string(sf[1].func), "_require_search_from_serialized"), bt)
length_bt = length(bt)
@debug "is_loaded_directly: `_require_search_from_serialized` appears $(length_bt) times in backtrace; expected 1"
bt_entry = only(bt)[1]
return bt_entry.line - bt_entry.linfo.def.line >= 73
line_call = bt_entry.line
line_funcbegin = bt_entry.linfo.def.line
line_difference = line_call - line_funcbegin
@debug "is_loaded_directly: `_require_search_from_serialized` called at line $line_call, function begins at line $line_funcbegin, difference $(line_difference)"
# difference for `using Package` / `using OtherPackage`
# 1.11.0-alpha1: 75 / 61
# 1.11.0-alpha2: 75 / 61
# 1.11.0-beta1: 75 / 61
# 1.11.0-beta2: 75 / 61
# 1.11.0-rc1: 75 / 61
# 1.11.0-rc2: 78 / 61
# 1.11.0-rc3: 78 / 61
# 1.11.0-rc4: 77 / 61
# 1.11.0: 77 / 61
# 1.11.1: 77 / 61
# 1.12.0-DEV.896: 78 / 61 # ignored
# 1.12.0-DEV.1322: 88 / 72 # ignored
# 1.12.0-DEV.1506: 106 / 93
@static if v"1.11.0-" < VERSION < v"1.12.0-DEV.1506"
return line_difference >= 73
else # v"1.12.0-DEV.1506" <= VERSION
return line_difference >= 100
end
end
catch e
@debug "Error while checking if loaded directly" exception=(e, Base.catch_backtrace())
Expand Down
1 change: 1 addition & 0 deletions test/utils/Banners/ModA/src/ModA.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ module ModA
import AbstractAlgebra: should_show_banner

function __init__()
@debug "__init__ of ModA"
if should_show_banner()
println("Banner of ModA")
end
Expand Down
1 change: 1 addition & 0 deletions test/utils/Banners/ModB/src/ModB.jl
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import AbstractAlgebra: should_show_banner
using ModA

function __init__()
@debug "__init__ of ModB"
if should_show_banner()
println("Banner of ModB")
end
Expand Down
32 changes: 16 additions & 16 deletions test/utils/Banners/banners.jl
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
using Pkg
using Pkg, Test

@testset "Banners" begin

function run_repl_code(code::String, proj::String)
bin = Base.julia_cmd()
opts = ["--project=$proj", "-i", "-e", "$code; exit();"]
opts = ["--startup-file=no", "--project=$proj", "-i", "-e", "$code; exit();"]
cmd = Cmd(`$bin $opts`, ignorestatus=true)
outs = IOBuffer()
errs = IOBuffer()
proc = run(pipeline(`$cmd`, stderr=errs, stdout=outs))
result = String(take!(outs))
proc = run(pipeline(addenv(`$cmd`, "JULIA_DEBUG" => "AbstractAlgebra,ModA,ModB"), stderr=errs, stdout=outs))
out = String(take!(outs))
err = String(take!(errs))
return result, err, proc.exitcode
return out, err, proc.exitcode
end

# Set up a separate temporary project for some modules that depend on each
Expand All @@ -33,43 +33,43 @@ using Pkg
Pkg.develop(path=raw"$modcdir");
Pkg.precompile();
"""
out,err,exitcode = run_repl_code(code, td)
out, err, exitcode = run_repl_code(code, td)
res = @test exitcode == 0
if res isa Test.Fail
println("out\n$out")
println("err\n$err")
println("OUT:\n$out")
println("ERR:\n$err")
end

# Banner of ModA shows
out, err = run_repl_code("using ModA;", td)
res = @test strip(out) == "Banner of ModA"
if res isa Test.Fail
println("out\n$out")
println("err\n$err")
println("OUT:\n$out")
println("ERR:\n$err")
end

# Banner of ModB shows, but ModA is supressed
out, err = run_repl_code("using ModB;", td)
res = @test strip(out) == "Banner of ModB"
if res isa Test.Fail
println("out\n$out")
println("err\n$err")
println("OUT:\n$out")
println("ERR:\n$err")
end

# Banner of ModB shows, but ModA is supressed, even if ModA is specifically
# used after ModB
out, err = run_repl_code("using ModB; using ModA;", td)
res = @test strip(out) == "Banner of ModB"
if res isa Test.Fail
println("out\n$out")
println("err\n$err")
println("OUT:\n$out")
println("ERR:\n$err")
end

# Banner does not show when our module is a dependency
out, err = run_repl_code("using ModC;", td)
res = @test strip(out) == ""
if res isa Test.Fail
println("out\n$out")
println("err\n$err")
println("OUT:\n$out")
println("ERR:\n$err")
end
end

0 comments on commit 193e1b8

Please sign in to comment.