Skip to content

Commit 6ca0044

Browse files
authored
Merge pull request #85 from DrChainsaw/exceptionunwrap
fix exception unwrapping
2 parents bb358bc + c5b0fd7 commit 6ca0044

2 files changed

Lines changed: 39 additions & 2 deletions

File tree

src/parallelism.jl

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,31 @@ exec(e, x, args...) = x
3838
exec(e, d::FileTree, args...) = mapvalues(v -> exec(e, v, fetch), d; lazy=false)
3939
exec(e, f::File, collect_results=fetch) = setvalue(f, exec(e, f[], collect_results))
4040

41+
struct UnwrappedTaskException{E} <: Exception
42+
cnt::Int
43+
msg::String
44+
stack::E
45+
end
46+
47+
function Base.showerror(io::IO, e::UnwrappedTaskException)
48+
println(io, e.cnt, " nested TaskFailedExceptions have been unwrapped by FileTrees to reduce clutter!\n", e.msg)
49+
for (wrapped, bt) in Iterators.reverse(e.stack)
50+
showerror(io, wrapped, bt; backtrace=bt !== nothing)
51+
end
52+
end
53+
4154
fetch_unwrap_exception(t) = try
4255
fetch(t)
4356
catch e
44-
if istaskfailed(t)
45-
rethrow(t.result)
57+
if e isa TaskFailedException
58+
lastthrown = first(current_exceptions(t)).exception
59+
if lastthrown isa UnwrappedTaskException
60+
rethrow(UnwrappedTaskException(lastthrown.cnt + 1, lastthrown.msg, lastthrown.stack))
61+
end
62+
# kept msg in case other executors also want to unwrap
63+
rethrow(UnwrappedTaskException(1, "See Executor.Threads documentation for how to disable unwrapping case anything appears to be missing.", current_exceptions(t)))
4664
end
65+
rethrow(e)
4766
end
4867

4968
"""

test/basics.jl

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,24 @@ import Dagger
257257
end
258258
end
259259

260+
@testset "Unwrap TaskFailedExceptions" begin
261+
innerfun(x) = x + 2 # Error, we will pass a string as x
262+
outerfun(x) = string("Result ", innerfun(x))
263+
# Only Executors.Threads messes with exceptions, so we don't test this above
264+
callsitefun(ft) = exec(Executor.Threads(unwrap_exceptions=true), mapvalues(identity, mapvalues(identity, mapvalues(identity, mapvalues(outerfun, ft)))))
265+
t1 = FileTrees.load(uppercasepath, t, lazy=true)
266+
try
267+
callsitefun(t1)
268+
catch ex
269+
# Bleh! Is there no better way to test that functions show up in the backtrace?
270+
currbt = stacktrace(catch_backtrace())
271+
@test any(s -> s.func == Symbol(callsitefun), currbt)
272+
exstr = sprint(showerror, ex)
273+
@test occursin(string(outerfun), exstr)
274+
@test occursin(string(innerfun), exstr)
275+
end
276+
end
277+
260278

261279
@testset "iterators" begin
262280
@test values(t1) == map(get, filter(hasvalue, nodes(t1)))

0 commit comments

Comments
 (0)