Writing jldoctests
This page describes how to write and maintain jldoctest
blocks in the documentation. Following these guidelines helps keep doctests reliable and easy to read.
Filters
Use filter =
whenever output contains text that might vary across runs. The following are common situations where this may happen:
- The output contains arrays with undefined memory (e.g. from
undef
orsimilar
) - The output contains random numbers
- The output contains timing information
- The output contains file system paths
Common filter sequences
The documentation relies on several recurring patterns:
r"int.jl:\\d+"
— remove line numbers from introspection macros.r"Stacktrace:(\\n \\[0-9]+\\].*)*"
— hide stack traces when illustrating errors.r"Closest candidates.*\\n .*"
— skip the method suggestions printed byMethodError
.r"@ .*"
— strip file locations from the output ofmethods
or@which
.r"\\@world\\(MyStruct, \\d+:\\d+\\)"
— filter world age numbers.r"with \\d+ methods"
— ignore method counts when redefining functions.r"[0-9\\.]+ seconds \\(.*?\\)"
— remove timing output with memory information.r"[0-9\\.]+ seconds"
— remove simple timing results.r"[0-9\\.]+"
— filter digits from names such as anonymous functions.r"([A-B] [0-5])"
andr"[A-B] [X-Z] [0-5]"
— account for non-deterministic process output.r"(world\\nhello|hello\\nworld)"
— allow either ordering of interleaved output.
If none of these match your situation, craft a regular expression that removes the varying text. Using filters keeps doctests stable across platforms and Julia versions.
When writing regex filters inside docstrings, remember to double escape backslashes. For example, use r"[\\d\\.]+"
instead of r"[\d\.]+"
. This is necessary because the docstring itself processes escape sequences before the regex is created.
Setup code
Small setup expressions may be placed inline using the setup =
option:
```jldoctest; setup = :(using InteractiveUtils)
...
```
For longer setup code or if multiple blocks require the same environment, use the DocTestSetup
meta block:
```@meta
DocTestSetup = :(import Random; Random.seed!(1234))
```
and disable it afterwards with
```@meta
DocTestSetup = nothing
```
Teardown code
If you need teardown code (e.g. to delete created temporary files or to reset the current directory), you can use the teardown =
option:
```jldoctest; setup = :(oldpath = pwd(); cd(mktempdir())), teardown = :(cd(oldpath))
...
```
Maintaining state between snippets
Related doctest blocks can share state by giving them the same label after the jldoctest
keyword. The manual uses this pattern to demonstrate mutation:
```jldoctest mutation_vs_rebind
julia> a = [1,2,3]
...
```
and later
```jldoctest mutation_vs_rebind
julia> a[1] = 42
...
```
Blocks with the same name execute sequentially during doctesting, so variables created in the first block remain available in the following ones.
When a snippet needs to preserve its result for later examples, give it a label and reuse that label. This avoids repeating setup code and mirrors a REPL session more closely.
Further reading
For a complete reference of doctest syntax, see the corresponding Documenter.jl docs.