Is there any way to tell through code whether a function supports a particular kwarg or not? I have a list of args in a Dict, and I need to filter this Dict to those that are supported by the function being called but short of calling the function, and catching the Exception for unrecognized kwarg, I cannot figure out how to tell in advance if an arg is supported or not.
I don’t need to check arg types (though that would be useful), just their names.
Edit: Thanks everyone, this problem has now been solved. I use the following code that appears to work in versions of Julia >= 0.4:
function getKWArgs(f::Function, m::Union{Method,Void}=nothing)
mts = methods(f)
# In Julia 0.4, methods() returns a MethodTable
# In Julia 0.6 it returns a MethodList that has an `mt` property with the MethodTable
if isa(mts, MethodTable)
table = mts
elseif isdefined(mts, :mt)
table = mts.mt
else
return Symbol[]
end
mts = collect(mts)
# If there's no kwsorter in the MethodTable, this function does not accept kwargs
if !isdefined(table, :kwsorter)
return Symbol[]
end
method_index = 1
if m == nothing
m = mts[method_index]
else
method_index = findfirst(x -> m == x, mts)
end
kwsorter = collect(methods(table.kwsorter))[method_index]
if isdefined(Base, :kwarg_decl)
# Julia 0.6 has Base.kwarg_decl to get kwargs
# Code from https://github.com/JuliaDocs/DocStringExtensions.jl/blob/8e9da56adf4b6b5b6380d05c28f43e8b2d922f0c/src/utilities.jl#L243
kwargs = Base.kwarg_decl(m, typeof(kwsorter))
if isa(kwargs, Vector) && length(kwargs) > 0
filter!(arg -> !occursin("#", string(arg)), kwargs)
# Keywords *may* not be sorted correctly. We move the vararg one to the end.
local index = findfirst(arg -> endswith(string(arg), "..."), kwargs)
if index != nothing
kwargs[index], kwargs[end] = kwargs[end], kwargs[index]
end
return kwargs
end
else
# Julia 0.4 needs us to parse the kwsorter code as a string and pull out the kwargs
# The only caveat is that we cannot tell if there is a vararg at the end. It's only
# possible to tell if there are non kw varargs (ie, before the ;)
kwargs = map(
x -> Symbol(split(x, ",")[1][2:end]), # String processing is faster than eval/parse
filter(
x -> startswith(x, ":") && !endswith(x, ",0"), # Non-kwargs have the third arg set to 0. kwargs have it set to 2 or 34 and could be other values
split(
replace(
string(kwsorter.func.code), # Convert the kwsorter code to a string to parse it because we can't get anything out of :AST
r"^.*Any\[Any\[(Any\[.*?)(Any\[symbol\(\"##index|, *:\(begin).*"s,
s"\1"
),
r"((\],)?Any\[|\]$)",
keep=false
)
)
)
return kwargs
end
return Symbol[]
end