Skip to content

Commit 053dba0

Browse files
committed
synthesize fallback for docstring() using other traits when no Base
Julia doc string
1 parent 7e6b568 commit 053dba0

File tree

3 files changed

+106
-15
lines changed

3 files changed

+106
-15
lines changed

src/metadata_utils.jl

Lines changed: 55 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -209,26 +209,71 @@ function doc_header(SomeModelType)
209209
params = MLJModelInterface.hyperparameters(SomeModelType)
210210

211211
ret =
212-
"""
213-
$name
212+
"""
213+
```
214+
$name
215+
```
214216
215-
Model type for $human_name, based on [$(package_name).jl]($package_url).
217+
Model type for $human_name, based on [$(package_name).jl]($package_url).
216218
217-
From MLJ, the type can be imported using
219+
From MLJ, the type can be imported using
218220
219-
$name = @load $name pkg=$package_name
221+
```
222+
$name = @load $name pkg=$package_name
223+
```
220224
221-
Do `model = $name()` to construct an instance with default hyper-parameters.
222-
""" |> chomp
225+
Do `model = $name()` to construct an instance with default hyper-parameters.
226+
""" |> chomp
223227

224228
isempty(params) && return ret
225229

226230
p = first(params)
231+
ret *= " "
227232
ret *=
233+
"""
234+
Provide keyword arguments to override hyper-parameter defaults, as in
235+
`$name($p=...)`.
236+
""" |> chomp
237+
238+
return ret
239+
end
240+
228241
"""
229-
Provide keyword arguments to override hyper-parameter defaults, as in
230-
`$name($p=...)`.
231-
""" |> chomp
242+
synthesize_docstring
243+
244+
Private method.
245+
246+
Generates a value for the `docstring` trait for use with a model which
247+
does not have a standard document string, to use as the fallback. See
248+
[`metadata_model`](@ref).
232249
250+
"""
251+
function synthesize_docstring(M)
252+
package_name = MLJModelInterface.package_name(M)
253+
package_url = MLJModelInterface.package_url(M)
254+
model_name = MLJModelInterface.name(M)
255+
human_name = MLJModelInterface.human_name(M)
256+
hyperparameters = MLJModelInterface.hyperparameters(M)
257+
258+
# generate text for the section on hyperparameters
259+
text_for_params = ""
260+
if !is_wrapper(M)
261+
model = M()
262+
isempty(hyperparameters) || (text_for_params *= "### Hyper-parameters")
263+
for p in hyperparameters
264+
value = getproperty(model, p)
265+
text_for_params *= "\n\n- `$p = $value`"
266+
end
267+
end
268+
269+
ret = doc_header(M)
270+
if !isempty(text_for_params)
271+
ret *=
272+
"""
273+
274+
$text_for_params
275+
276+
"""
277+
end
233278
return ret
234279
end

src/model_traits.jl

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,13 @@ const DeterministicDetector = Union{
1313

1414
const StatTraits = StatisticalTraits
1515

16-
StatTraits.docstring(M::Type{<:Model}) = Base.Docs.doc(M) |> string
16+
function StatTraits.docstring(M::Type{<:Model})
17+
docstring = Base.Docs.doc(M) |> string
18+
if occursin("No documentation found", docstring)
19+
docstring = synthesize_docstring(M)
20+
end
21+
return docstring
22+
end
1723

1824
StatTraits.is_supervised(::Type{<:Supervised}) = true
1925
StatTraits.is_supervised(::Type{<:SupervisedAnnotator}) = true

test/model_traits.jl

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
end
33

44
@mlj_model mutable struct U1 <: Unsupervised
5+
a::Int
6+
b = sin
57
end
68

79
@mlj_model mutable struct D1 <: Deterministic
@@ -24,9 +26,17 @@ end
2426
foo(::P1) = 0
2527
bar(::P1) = nothing
2628

29+
M.package_name(::Type{<:S1}) = "Sibelius"
30+
M.package_url(::Type{<:S1}) = "www.find_the_eighth.org"
31+
M.human_name(::Type{<:S1}) = "silly model"
32+
33+
M.package_name(::Type{<:U1}) = "Bach"
34+
M.package_url(::Type{<:U1}) = "www.did_he_write_565.com"
35+
M.human_name(::Type{<:U1}) = "my model"
36+
2737
@testset "traits" begin
2838
ms = S1()
29-
mu = U1()
39+
mu = U1(a=42, b=sin)
3040
md = D1()
3141
mp = P1()
3242
mi = I1()
@@ -38,11 +48,11 @@ bar(::P1) = nothing
3848
@test target_scitype(ms) == Unknown
3949
@test is_pure_julia(ms) == false
4050

41-
@test package_name(ms) == "unknown"
51+
@test package_name(ms) == "Sibelius"
4252
@test package_license(ms) == "unknown"
4353
@test load_path(ms) == "unknown"
4454
@test package_uuid(ms) == "unknown"
45-
@test package_url(ms) == "unknown"
55+
@test package_url(ms) == "www.find_the_eighth.org"
4656

4757
@test is_wrapper(ms) == false
4858
@test supports_online(ms) == false
@@ -51,8 +61,38 @@ bar(::P1) = nothing
5161

5262
@test hyperparameter_ranges(md) == (nothing,)
5363

54-
@test docstring(ms)[1:16] == "No documentation"[1:16]
64+
@test docstring(ms) == M.doc_header(S1)
65+
doc = docstring(mu) |> Markdown.parse
66+
comparison =
67+
"""
68+
```
69+
U1
70+
```
71+
72+
Model type for my model, based on [Bach.jl](www.did_he_write_565.com).
73+
74+
From MLJ, the type can be imported using
75+
76+
```
77+
U1 = @load U1 pkg=Bach
78+
```
79+
80+
Do `model = U1()` to construct an instance with default hyper-parameters.
81+
Provide keyword arguments to override hyper-parameter defaults, as in
82+
`U1(a=...)`.
83+
84+
### Hyper-parameters
85+
86+
- `a = 0`
87+
88+
- `b = sin`
89+
90+
""" |> Markdown.parse
91+
@test doc == comparison
92+
5593
@test name(ms) == "S1"
94+
@test human_name(ms) == "silly model"
95+
5696

5797
@test is_supervised(ms)
5898
@test is_supervised(sa)

0 commit comments

Comments
 (0)