test_unbound_args: add a functionality to ignore specific methods#316
test_unbound_args: add a functionality to ignore specific methods#316arnaud-ma wants to merge 6 commits intoJuliaTesting:masterfrom
Conversation
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## master #316 +/- ##
==========================================
- Coverage 74.90% 74.86% -0.04%
==========================================
Files 11 11
Lines 761 764 +3
==========================================
+ Hits 570 572 +2
- Misses 191 192 +1 ☔ View full report in Codecov by Sentry. |
|
The ability to ignore specific methods when testing for unbound arguments would be helpful. |
New `tups_to_mat` function results in unbound type parameters because of `Vararg`, trying to fix. See [Aqua.jl #316](JuliaTesting/Aqua.jl#316) and [#86](JuliaTesting/Aqua.jl#86).
New `tups_to_mat` function results in unbound type parameters because of `Vararg`, trying to fix. See [Aqua.jl #316](JuliaTesting/Aqua.jl#316) and [#86](JuliaTesting/Aqua.jl#86).
lgoettgens
left a comment
There was a problem hiding this comment.
Thanks for working on this. Adding exceptions is indeed something that each of the test functions should have. Some detailed comments below
src/unbound_args.jl
Outdated
| unbounds = detect_unbound_args_recursively(m) | ||
| for i in ignore | ||
| # i[2:end] is empty if length(i) == 1 | ||
| ignore_signature = Tuple{typeof(i[1]),i[2:end]...} |
There was a problem hiding this comment.
This approach unfortunately does not work for callable objects.
Please make sure that this also works for cases like
struct S{U}
s::U
end
(::S{U})(::NTuple{N,T}) where {N,T,U} = (N,T,U)
(::S{U})(::Tuple{}) where {U} = (0,Any,U)and include such an example in the tests
|
All done! |
src/unbound_args.jl
Outdated
| callable, args = i[1], i[2:end] # i[2:end] is empty if length(i) == 1 | ||
|
|
||
| # the type of the function is the function itself if it is a callable object | ||
| callable_t = callable isa Function ? typeof(callable) : callable |
There was a problem hiding this comment.
Hmm, I thinks this still isn't quite what we want here.
For custom structs, say struct S end, there are both function signatures containing S and Type{S} (which isn't even quite typeof(S)), since the former is for callable objects and the latter for constructors.
Furthermore, there are subtypes of Function, that are not a singleton type of function xxx, e.g. Base.ComposedFunction.
Maybe you have an idea that makes all of these cases work. If not, I think we just need the user to specify the exact signature, i.e. foo(x::Int, y::Float64) as (typeof(foo), Int, Float64).
There was a problem hiding this comment.
Ah, I understand now. Thank you very much for your patience. After some research, I can't find any way to be 100% sure that we are dealing with a "simple" method.
But specifying the exact signature requires some knowledge from the user. To help the user, I think adding what method.sig returns in the error message can be a good idea. For example from this:
Unbound type parameters detected:
[1] f(x) where T @ Main.Foo ~/projets/forks/Aqua/Aqua.jl/a.jl:15
[2] (::Main.Foo.S{U})(::NTuple{N, T}) where {N, T, U} @ Main.Foo ~/projets/forks/Aqua/Aqua.jl/a.jl:8
[3] Main.Foo.S(::NTuple{N, T}) where {N, T} @ Main.Foo ~/projets/forks/Aqua/Aqua.jl/a.jl:11to this:
Unbound type parameters detected:
[1] f(x) where T @ Main.Foo ~/projets/forks/Aqua/Aqua.jl/a.jl:15
signature: Tuple{typeof(Main.Foo.f), Any} where T
[2] (::Main.Foo.S{U})(::NTuple{N, T}) where {N, T, U} @ Main.Foo ~/projets/forks/Aqua/Aqua.jl/a.jl:8
signature: Tuple{Main.Foo.S{U}, NTuple{N, T}} where {N, T, U}
[3] Main.Foo.S(::NTuple{N, T}) where {N, T} @ Main.Foo ~/projets/forks/Aqua/Aqua.jl/a.jl:11
signature: Tuple{Type{Main.Foo.S}, NTuple{N, T}} where {N, T}
What do you think about that?
There was a problem hiding this comment.
I am not a fan of requiring 3x of vertical space. Instead, I think we could make a function public that returns the list of methods, so that a user can query this for the signature themselves. But I would put that to a follow-up PR.
For this PR, it would be great if you could do the small adaptions needed for this, and adapt the docstring as well.
…est_unbounds_args
|
If you are willing to rewrite your code, this may be a better workaround: The Aqua documentation on julia> f(::Tuple{T, Vararg{T, NmOne}}) where {T, NmOne} = (NmOne + 1 ,T);
julia> f((1,2,3))
(3, Int64)
julia> import Test;
julia> Test.detect_unbound_args(Main)
0-element Vector{Method} |
With this PR, it is now possible to ignore some methods, given their signature. For example, taking the false positive in #86:
It is possible to disable the false positive with:
This specific example has been added in the unit tests.
To improve flexibility, the possibility to call directlyAqua.test_unbound_args(unbounds_args)whereunbounds_argsis a collection of methods (probably got withTest.detect_unbound_args) is also added.