Skip to content

Fix the dead Test-extension guard in the error hint - #67

Open
devmotion wants to merge 3 commits into
masterfrom
dmw/fix-test-extension-guard
Open

devmotion wants to merge 3 commits into
masterfrom
dmw/fix-test-extension-guard

Conversation

@devmotion

@devmotion devmotion commented Sep 21, 2026 •

Copy link
Copy Markdown
Member

Fix the extension name in the error hint. The guard queried :InverseFunctionsTest, but the extension is registered as InverseFunctionsTestExt. Base.get_extension returns nothing for an unknown name rather than erroring, so the guard was permanently true and "Did you forget to load Test?" was appended to every test_inverse MethodError — including ones raised while Test is loaded.

Tests cover both directions: with Test loaded, a wrong-arity MethodError carries no hint; without Test (checked in a subprocess, since Test can't be unloaded), the hint is shown and hasmethod(test_inverse, Tuple{Any,Any}) is false. Tests pass on Julia 1.6, 1.10, 1.11 and 1.13.

An earlier version of this PR also removed __init__ to save load time. That cost turned out to be a @time_imports measurement artifact (see the discussion below), so __init__ and the error hint stay.

Closes #66 (version bumped to 0.1.18 here).

🤖 Generated with Claude Code

`Base.get_extension` returns `nothing` for an unknown extension name, so
querying `:InverseFunctionsTest` instead of `:InverseFunctionsTestExt` left
the guard permanently true: "Did you forget to load Test?" was appended to
every `test_inverse` `MethodError`, including those raised when `Test` is
loaded and the extension method exists.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@codecov

codecov Bot commented Sep 21, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 98.50%. Comparing base (0434eba) to head (aabdd9b).

Additional details and impacted files
@@            Coverage Diff             @@
##           master      #67      +/-   ##
==========================================
+ Coverage   98.48%   98.50%   +0.02%     
==========================================
  Files           6        6              
  Lines         132      134       +2     
==========================================
+ Hits          130      132       +2     
  Misses          2        2              

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@timholy

timholy commented Oct 15, 2026

Copy link
Copy Markdown
Member

Could you fix the timing issue with precompile(__init__, ())? If it does, one small plus is that it would keep an external package's hasmethod(test_inverse, ...) giving an informative error.

@devmotion

Copy link
Copy Markdown
Member Author

Thanks, this made me dig deeper, and the load-time cost I attributed to __init__ turns out to be a @time_imports artifact rather than a real cost.

Under @time_imports, Base.run_module_init prints an extra ┌ … ms Pkg.__init__() line, but only for packages that define __init__. It prints that line inside the timing window used for the package's own line. In a fresh session, printing it is the first use of printstyled/with_output_color/print(::IOStream, ::Float64, …), and compiling those takes ~17 ms on 1.10 and ~35 ms on 1.13 (from jl_dump_compiles). That compile time is reported as the package's "~80% compilation time". (On 1.11/1.12 it isn't counted towards the package line.)

Supporting evidence:

  • __init__ itself is reported as 0.0 ms.
  • An empty __init__ shows the same overhead.
  • Calling the same printstyled/print methods before @time_imports drops InverseFunctions on 1.10 from 19 ms / 88% to 2 ms / 0%.
  • With plain @elapsed using InverseFunctions, master, master + precompile(__init__, ()), an empty __init__, and this PR are all within noise (1.10: ~18–20 ms; 1.13: ~3–5 ms). jl_dump_compiles shows nothing from InverseFunctions being compiled during a normal load.

So precompile(__init__, ()) has nothing to fix, and there's no reason to remove __init__. I'll cut this PR down to the extension-name fix, keep the error hint (and with it an informative hasmethod(test_inverse, …)), and add tests for the hint. Probably worth an upstream issue about @time_imports counting its own printing too.

@timholy

timholy commented Oct 15, 2026

Copy link
Copy Markdown
Member

Gotcha. Also, I dug around a bit, and we compile __init__ by default (I didn't check, but there's even a chance that I'm the one that added that 😆 ).

@timholy

timholy commented Oct 15, 2026

Copy link
Copy Markdown
Member

Nice catch on @time_imports by the way, I do think that merits a report.

devmotion and others added 2 commits October 15, 2026 16:17
With the error hint kept, `test_inverse` only gains a method when
`InverseFunctionsTestExt` is loaded, so `hasmethod` tells downstream code
whether `test_inverse` is usable.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@devmotion
devmotion force-pushed the dmw/fix-test-extension-guard branch from d51de21 to aabdd9b Compare October 15, 2026 14:17
@devmotion devmotion changed the title Fix the dead Test-extension guard and let the extension implement a stub Fix the dead Test-extension guard in the error hint Oct 15, 2026
@devmotion

Copy link
Copy Markdown
Member Author

I reported the finding in JuliaLang/julia#63850

This branch has not been deployed

No deployments
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