From e8de9d6f0c708d09b63d6229e61cbc505168758f Mon Sep 17 00:00:00 2001 From: ChrisRackauckas-Claude Date: Wed, 24 Jun 2026 09:24:14 -0400 Subject: [PATCH 1/3] Add ExplicitImports QA checks; declare init/get_expression public Wire the full set of ExplicitImports checks into the QA test group and fix the import hygiene they surface: - Implicit -> explicit: replace `using ExprTools, Serialization, SHA` with per-name `using Dep: name` imports (combinedef/splitdef, SHA1_CTX/update!, AbstractSerializer/deserialize/serialize). - Remove stale `import Base.Experimental: @opaque` (the macro is never invoked; closures_to_opaque builds the macrocall expr manually). This also clears the lone non-public explicit import. - Declare `init` and `get_expression` public (Julia >= 1.11, guarded) since they are documented, downstream-relied-on entry points. High-leverage for the fleet: downstream packages qualifying these now pass check_all_qualified_accesses_are_public against this library. The only remaining non-public qualified accesses are `Base.deepcopy_internal` and `Serialization.serialize_type` -- the documented-by-convention extension points for customizing deepcopy/serialization. Neither owner marks them public and there is no public alternative, so they are minimally ignore-listed with a comment rather than rewritten. All 6 checks pass locally on Julia lts (1.10) and 1 (1.12). Co-Authored-By: Chris Rackauckas Co-Authored-By: Claude Opus 4.8 (1M context) --- Project.toml | 6 ++++-- src/RuntimeGeneratedFunctions.jl | 14 ++++++++++++-- test/qa/Project.toml | 2 ++ test/qa/qa.jl | 23 ++++++++++++++++++++++- 4 files changed, 40 insertions(+), 5 deletions(-) diff --git a/Project.toml b/Project.toml index 6158ccb..33db557 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "RuntimeGeneratedFunctions" uuid = "7e49a35a-f44a-4d26-94aa-eba1b4ca6b47" authors = ["Chris Rackauckas and contributors"] -version = "0.5.20" +version = "0.5.21" [deps] ExprTools = "e2ba6199-217a-4e67-a87a-7c52f15ade04" @@ -11,6 +11,7 @@ Serialization = "9e88b42a-f829-5b0c-bbe9-9e923198166b" [compat] Aqua = "0.8" BenchmarkTools = "1" +ExplicitImports = "1" ExprTools = "0.1" SHA = "0.7, 1" SafeTestsets = "0.1, 1" @@ -22,9 +23,10 @@ julia = "1.10" [extras] Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595" BenchmarkTools = "6e4b80f9-dd63-53aa-95a3-0cdb28fa8baf" +ExplicitImports = "7d51a73a-1435-4ff3-83d9-f097790105c7" SafeTestsets = "1bc83da4-3b8d-516f-aca4-4fe02f6d838f" SciMLTesting = "09d9d899-5365-40a9-917a-5f67fddea283" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" [targets] -test = ["Aqua", "BenchmarkTools", "SafeTestsets", "SciMLTesting", "Test"] +test = ["Aqua", "BenchmarkTools", "ExplicitImports", "SafeTestsets", "SciMLTesting", "Test"] diff --git a/src/RuntimeGeneratedFunctions.jl b/src/RuntimeGeneratedFunctions.jl index 1146c3c..8539288 100644 --- a/src/RuntimeGeneratedFunctions.jl +++ b/src/RuntimeGeneratedFunctions.jl @@ -1,10 +1,20 @@ module RuntimeGeneratedFunctions -using ExprTools, Serialization, SHA -import Base.Experimental: @opaque +using ExprTools: ExprTools, combinedef, splitdef +using SHA: SHA, SHA1_CTX, update! +using Serialization: Serialization, AbstractSerializer, deserialize, serialize export RuntimeGeneratedFunction, @RuntimeGeneratedFunction, drop_expr +# `init` and `get_expression` are documented, downstream-relied-on entry points +# (see README and the `@autodocs` API page) that are intentionally not exported +# to keep them namespaced under `RuntimeGeneratedFunctions.`. Declare them public +# so downstream packages can qualify-access them and pass ExplicitImports' +# `check_all_qualified_accesses_are_public`. +@static if VERSION >= v"1.11" + eval(Expr(:public, :init, :get_expression)) +end + const _rgf_docs = """ @RuntimeGeneratedFunction(function_expression) @RuntimeGeneratedFunction(context_module, function_expression, opaque_closures=true) diff --git a/test/qa/Project.toml b/test/qa/Project.toml index edf82cc..981e813 100644 --- a/test/qa/Project.toml +++ b/test/qa/Project.toml @@ -1,5 +1,6 @@ [deps] Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595" +ExplicitImports = "7d51a73a-1435-4ff3-83d9-f097790105c7" RuntimeGeneratedFunctions = "7e49a35a-f44a-4d26-94aa-eba1b4ca6b47" SafeTestsets = "1bc83da4-3b8d-516f-aca4-4fe02f6d838f" SciMLTesting = "09d9d899-5365-40a9-917a-5f67fddea283" @@ -10,6 +11,7 @@ RuntimeGeneratedFunctions = {path = "../.."} [compat] Aqua = "0.8" +ExplicitImports = "1" SafeTestsets = "0.1, 1" SciMLTesting = "1" Test = "1" diff --git a/test/qa/qa.jl b/test/qa/qa.jl index c5a252a..82b0d64 100644 --- a/test/qa/qa.jl +++ b/test/qa/qa.jl @@ -1,4 +1,4 @@ -using RuntimeGeneratedFunctions, Aqua +using RuntimeGeneratedFunctions, Aqua, ExplicitImports @testset "Aqua" begin Aqua.find_persistent_tasks_deps(RuntimeGeneratedFunctions) Aqua.test_ambiguities(RuntimeGeneratedFunctions, recursive = false) @@ -9,3 +9,24 @@ using RuntimeGeneratedFunctions, Aqua Aqua.test_unbound_args(RuntimeGeneratedFunctions) Aqua.test_undefined_exports(RuntimeGeneratedFunctions) end + +@testset "ExplicitImports" begin + @test ExplicitImports.check_no_implicit_imports(RuntimeGeneratedFunctions) === nothing + @test ExplicitImports.check_no_stale_explicit_imports(RuntimeGeneratedFunctions) === + nothing + @test ExplicitImports.check_all_explicit_imports_via_owners(RuntimeGeneratedFunctions) === + nothing + @test ExplicitImports.check_all_qualified_accesses_via_owners(RuntimeGeneratedFunctions) === + nothing + # `Base.deepcopy_internal` and `Serialization.serialize_type` are the + # documented-by-convention extension points used to customize `deepcopy` and + # `Serialization.serialize`, respectively. Neither owner declares them + # public, but overriding/calling them is the only supported way to get the + # required behavior, so they are ignored rather than rewritten. + @test ExplicitImports.check_all_qualified_accesses_are_public( + RuntimeGeneratedFunctions; + ignore = (:deepcopy_internal, :serialize_type) + ) === nothing + @test ExplicitImports.check_all_explicit_imports_are_public(RuntimeGeneratedFunctions) === + nothing +end From 653ea076af206a87a3fcaa75b5bdcb0d680731a6 Mon Sep 17 00:00:00 2001 From: ChrisRackauckas-Claude Date: Wed, 24 Jun 2026 11:23:14 -0400 Subject: [PATCH 2/3] QA: use canonical SciMLTesting run_qa for Aqua + ExplicitImports Replace the direct Aqua/ExplicitImports calls in test/qa/qa.jl with a single run_qa(RuntimeGeneratedFunctions; Aqua, ExplicitImports, explicit_imports=true, ei_kwargs=...) call, the canonical SciMLTesting QA body. The per-check ignore list for check_all_qualified_accesses_are_public (:deepcopy_internal, :serialize_type) is carried over verbatim via ei_kwargs. The init/get_expression public declarations and all other PR fixes are retained. Bump SciMLTesting [compat] to "1.4" in Project.toml and test/qa/Project.toml, since run_qa's ExplicitImports support was introduced in SciMLTesting 1.4.0. Verified locally on Julia 1.10 (lts) and 1.12 (the "1" channel): the QA group passes 17/17 (all 6 ExplicitImports checks plus Aqua) via run_qa. Co-Authored-By: Chris Rackauckas Co-Authored-By: Claude Opus 4.8 (1M context) --- Project.toml | 2 +- test/qa/Project.toml | 2 +- test/qa/qa.jl | 46 +++++++++++++++----------------------------- 3 files changed, 17 insertions(+), 33 deletions(-) diff --git a/Project.toml b/Project.toml index 33db557..05f38ca 100644 --- a/Project.toml +++ b/Project.toml @@ -15,7 +15,7 @@ ExplicitImports = "1" ExprTools = "0.1" SHA = "0.7, 1" SafeTestsets = "0.1, 1" -SciMLTesting = "1" +SciMLTesting = "1.4" Serialization = "1.10" Test = "1" julia = "1.10" diff --git a/test/qa/Project.toml b/test/qa/Project.toml index 981e813..1b7da55 100644 --- a/test/qa/Project.toml +++ b/test/qa/Project.toml @@ -13,6 +13,6 @@ RuntimeGeneratedFunctions = {path = "../.."} Aqua = "0.8" ExplicitImports = "1" SafeTestsets = "0.1, 1" -SciMLTesting = "1" +SciMLTesting = "1.4" Test = "1" julia = "1.10" diff --git a/test/qa/qa.jl b/test/qa/qa.jl index 82b0d64..7e22baf 100644 --- a/test/qa/qa.jl +++ b/test/qa/qa.jl @@ -1,32 +1,16 @@ -using RuntimeGeneratedFunctions, Aqua, ExplicitImports -@testset "Aqua" begin - Aqua.find_persistent_tasks_deps(RuntimeGeneratedFunctions) - Aqua.test_ambiguities(RuntimeGeneratedFunctions, recursive = false) - Aqua.test_deps_compat(RuntimeGeneratedFunctions) - Aqua.test_piracies(RuntimeGeneratedFunctions) - Aqua.test_project_extras(RuntimeGeneratedFunctions) - Aqua.test_stale_deps(RuntimeGeneratedFunctions) - Aqua.test_unbound_args(RuntimeGeneratedFunctions) - Aqua.test_undefined_exports(RuntimeGeneratedFunctions) -end +using RuntimeGeneratedFunctions, Aqua, ExplicitImports, SciMLTesting -@testset "ExplicitImports" begin - @test ExplicitImports.check_no_implicit_imports(RuntimeGeneratedFunctions) === nothing - @test ExplicitImports.check_no_stale_explicit_imports(RuntimeGeneratedFunctions) === - nothing - @test ExplicitImports.check_all_explicit_imports_via_owners(RuntimeGeneratedFunctions) === - nothing - @test ExplicitImports.check_all_qualified_accesses_via_owners(RuntimeGeneratedFunctions) === - nothing - # `Base.deepcopy_internal` and `Serialization.serialize_type` are the - # documented-by-convention extension points used to customize `deepcopy` and - # `Serialization.serialize`, respectively. Neither owner declares them - # public, but overriding/calling them is the only supported way to get the - # required behavior, so they are ignored rather than rewritten. - @test ExplicitImports.check_all_qualified_accesses_are_public( - RuntimeGeneratedFunctions; - ignore = (:deepcopy_internal, :serialize_type) - ) === nothing - @test ExplicitImports.check_all_explicit_imports_are_public(RuntimeGeneratedFunctions) === - nothing -end +# `Base.deepcopy_internal` and `Serialization.serialize_type` are the +# documented-by-convention extension points used to customize `deepcopy` and +# `Serialization.serialize`, respectively. Neither owner declares them public, but +# overriding/calling them is the only supported way to get the required behavior, +# so they are ignored rather than rewritten. +run_qa( + RuntimeGeneratedFunctions; + Aqua = Aqua, + ExplicitImports = ExplicitImports, + explicit_imports = true, + ei_kwargs = (; + all_qualified_accesses_are_public = (; ignore = (:deepcopy_internal, :serialize_type)), + ), +) From f576cef3654213164d246c6b8a8277241650bada Mon Sep 17 00:00:00 2001 From: ChrisRackauckas-Claude Date: Wed, 24 Jun 2026 21:23:05 -0400 Subject: [PATCH 3/3] QA: adopt SciMLTesting 1.5 minimal run_qa form SciMLTesting 1.5.0 makes Aqua and ExplicitImports its own direct dependencies and auto-detects them in run_qa, so the per-repo QA body no longer threads them through: - test/qa/qa.jl: drop the now-auto-detected `Aqua = Aqua` and `ExplicitImports = ExplicitImports` module arguments. Keep `explicit_imports = true` (the ExplicitImports checks are opt-in as of 1.5, defaulting off) and the per-check `ei_kwargs` ignore-list verbatim. Imports collapse to `using RuntimeGeneratedFunctions, SciMLTesting, Test`. - test/qa/Project.toml: drop ExplicitImports (now transitive via SciMLTesting). KEEP Aqua as a direct dep: Aqua's `test_ambiguities` runs `detect_ambiguities` in a child process that does `using Aqua`, which requires Aqua to be a direct dependency of the active QA environment -- a transitive-only Aqua makes that subprocess fail with "Package Aqua not found in current path" (verified reproducible on Julia 1.10 and 1.11). ExplicitImports has no such subprocess and works transitively. - Project.toml: drop Aqua and ExplicitImports from the root [extras]/[targets] test set (the root test target runs neither; QA is the separate test/qa sub-env). - Bump SciMLTesting [compat] to "1.5" in both Project.toml and test/qa/Project.toml. Verified locally against the released SciMLTesting 1.5.0 (no dev-from-branch): GROUP=QA `Pkg.test` passes 17/17 on Julia 1.10 (lts) and 1.12 (the "1" channel) -- all six ExplicitImports checks plus Aqua's full test_all. Co-Authored-By: Chris Rackauckas Co-Authored-By: Claude Opus 4.8 (1M context) --- Project.toml | 8 ++------ test/qa/Project.toml | 4 +--- test/qa/qa.jl | 4 +--- 3 files changed, 4 insertions(+), 12 deletions(-) diff --git a/Project.toml b/Project.toml index 05f38ca..3f5e352 100644 --- a/Project.toml +++ b/Project.toml @@ -9,24 +9,20 @@ SHA = "ea8e919c-243c-51af-8825-aaa63cd721ce" Serialization = "9e88b42a-f829-5b0c-bbe9-9e923198166b" [compat] -Aqua = "0.8" BenchmarkTools = "1" -ExplicitImports = "1" ExprTools = "0.1" SHA = "0.7, 1" SafeTestsets = "0.1, 1" -SciMLTesting = "1.4" +SciMLTesting = "1.5" Serialization = "1.10" Test = "1" julia = "1.10" [extras] -Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595" BenchmarkTools = "6e4b80f9-dd63-53aa-95a3-0cdb28fa8baf" -ExplicitImports = "7d51a73a-1435-4ff3-83d9-f097790105c7" SafeTestsets = "1bc83da4-3b8d-516f-aca4-4fe02f6d838f" SciMLTesting = "09d9d899-5365-40a9-917a-5f67fddea283" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" [targets] -test = ["Aqua", "BenchmarkTools", "ExplicitImports", "SafeTestsets", "SciMLTesting", "Test"] +test = ["BenchmarkTools", "SafeTestsets", "SciMLTesting", "Test"] diff --git a/test/qa/Project.toml b/test/qa/Project.toml index 1b7da55..ab6ab9e 100644 --- a/test/qa/Project.toml +++ b/test/qa/Project.toml @@ -1,6 +1,5 @@ [deps] Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595" -ExplicitImports = "7d51a73a-1435-4ff3-83d9-f097790105c7" RuntimeGeneratedFunctions = "7e49a35a-f44a-4d26-94aa-eba1b4ca6b47" SafeTestsets = "1bc83da4-3b8d-516f-aca4-4fe02f6d838f" SciMLTesting = "09d9d899-5365-40a9-917a-5f67fddea283" @@ -11,8 +10,7 @@ RuntimeGeneratedFunctions = {path = "../.."} [compat] Aqua = "0.8" -ExplicitImports = "1" SafeTestsets = "0.1, 1" -SciMLTesting = "1.4" +SciMLTesting = "1.5" Test = "1" julia = "1.10" diff --git a/test/qa/qa.jl b/test/qa/qa.jl index 7e22baf..8536643 100644 --- a/test/qa/qa.jl +++ b/test/qa/qa.jl @@ -1,4 +1,4 @@ -using RuntimeGeneratedFunctions, Aqua, ExplicitImports, SciMLTesting +using RuntimeGeneratedFunctions, SciMLTesting, Test # `Base.deepcopy_internal` and `Serialization.serialize_type` are the # documented-by-convention extension points used to customize `deepcopy` and @@ -7,8 +7,6 @@ using RuntimeGeneratedFunctions, Aqua, ExplicitImports, SciMLTesting # so they are ignored rather than rewritten. run_qa( RuntimeGeneratedFunctions; - Aqua = Aqua, - ExplicitImports = ExplicitImports, explicit_imports = true, ei_kwargs = (; all_qualified_accesses_are_public = (; ignore = (:deepcopy_internal, :serialize_type)),