Documenter.jl icon indicating copy to clipboard operation
Documenter.jl copied to clipboard

problem with doctests for code that writes to `stdout`

Open ThomasBreuer opened this issue 3 years ago • 4 comments

The following works in a Julia session (version 1.5 or 1.6 or 1.7.0-DEV), but I get the error message ERROR: IOError: stream is closed or unusable when it is run as a doctest.

julia> io = IOContext(stdout);

julia> println(io, "abc")
abc

Note that the following code works as a doctest as well as in a Julia session.

julia> println(stdout, "abc")
abc

julia> println(IOContext(stdout), "abc")
abc

(See oscar-system/Oscar.jl/pull/445 for some context. Perhaps the problem is related to issue #1245, at least the topic and the error message fit.)

ThomasBreuer avatar May 20 '21 16:05 ThomasBreuer

You're running into this: https://github.com/JuliaDocs/IOCapture.jl/#separately-stored-stdout-or-stderr-objects

It's a limitation on how we implement the output capture. Definitely a bug, but I am not sure there's an easy fix.

mortenpi avatar May 21 '21 22:05 mortenpi

Thanks. I will use a workaround as long as the problem is present.

ThomasBreuer avatar May 23 '21 12:05 ThomasBreuer

I'm also getting this error when the example code involves ProgressMeter.jl.

findmyway avatar May 24 '21 07:05 findmyway

I wonder if there's some way to use same redirected IO streams can be used for each capture invocation within a block, rather than separate streams each time[^1]. That would fix examples like

using ProgressMeter
prog = ProgressThresh(1e-5; desc="Minimizing:")
for val in exp10.(range(2, stop=-6, length=20))
    update!(prog, val)
    sleep(0.1)
end

where stderr is being captured in the prog = line, but it gets closed after the line executes, before the for-loop.

I guess a workaround in cases like that is an extra begin or let block;

using ProgressMeter
begin
    prog = ProgressThresh(1e-5; desc="Minimizing:")
    for val in exp10.(range(2, stop=-6, length=20))
        update!(prog, val)
        sleep(0.1)
    end
end

so that documenter executes the whole block within a single capture invocation.

[^1]: I'm not sure this is actually easy, since we want to close the streams to ensure we get all the outputs from that line before moving to the next one.

ericphanson avatar Dec 10 '23 23:12 ericphanson