Skip to content

Commit 3cf464e

Browse files
SimonDanischtimholy
authored andcommitted
better error messages (#76)
* better error messages
1 parent 080efaa commit 3cf464e

File tree

6 files changed

+78
-38
lines changed

6 files changed

+78
-38
lines changed

src/error_handling.jl

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,24 @@ function handle_current_error(e, library, islast::Bool)
5353
end
5454
handle_current_error(e::NotInstalledError) = warn(string("lib ", e.library, " not installed, trying next library"))
5555

56+
5657
"""
5758
Handles a list of thrown errors after no IO library was found working
5859
"""
59-
function handle_error(exceptions::Vector)
60+
function handle_exceptions(exceptions::Vector, action)
61+
# first show all errors when there are more then one
62+
multiple = length(exceptions) > 1
63+
println("Error$(multiple?"s" : "") encountered while $action.")
64+
if multiple
65+
println("All errors:")
66+
for (err, file) in exceptions
67+
println(" ", err)
68+
end
69+
end
70+
# then handle all errors.
71+
# this way first fatal exception throws and user can still see all errors
72+
# TODO, don't throw, if it contains a NotInstalledError?!
73+
println("Fatal error:")
6074
for exception in exceptions
6175
continue_ = handle_error(exception...)
6276
continue_ || break
@@ -66,10 +80,10 @@ end
6680
handle_error(e, q) = rethrow(e)
6781

6882
function handle_error(e::NotInstalledError, q)
69-
println("Library ", e.library, " is not installed but can load format: ", q)
83+
println("Library \"", e.library, "\" is not installed but is recommended as a library to load format: \"", file_extension(q), "\"")
7084
!isinteractive() && rethrow(e) # if we're not in interactive mode just throw
7185
while true
72-
println("should we install ", e.library, " for you? (y/n):")
86+
println("Should we install \"", e.library, "\" for you? (y/n):")
7387
input = lowercase(chomp(strip(readline(STDIN))))
7488
if input == "y"
7589
info(string("Start installing ", e.library, "..."))

src/loadsave.jl

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,8 @@ function load{F}(q::Formatted{F}, args...; options...)
7474
isfile(filename(q)) || open(filename(q)) # force systemerror
7575
throw(UnknownFormat(q))
7676
end
77-
libraries = applicable_loaders(q)
78-
failures = Any[]
77+
libraries = applicable_loaders(q)
78+
failures = Any[]
7979
for library in libraries
8080
try
8181
Library = checked_import(library)
@@ -84,16 +84,15 @@ function load{F}(q::Formatted{F}, args...; options...)
8484
end
8585
return Library.load(q, args...; options...)
8686
catch e
87-
handle_current_error(e, library, library == last(libraries))
8887
push!(failures, (e, q))
8988
end
9089
end
91-
handle_error(failures)
90+
handle_exceptions(failures, "loading \"$(filename(q))\"")
9291
end
9392
function save{F}(q::Formatted{F}, data...; options...)
9493
unknown(q) && throw(UnknownFormat(q))
95-
libraries = applicable_savers(q)
96-
failures = Any[]
94+
libraries = applicable_savers(q)
95+
failures = Any[]
9796
for library in libraries
9897
try
9998
Library = checked_import(library)
@@ -102,9 +101,8 @@ function save{F}(q::Formatted{F}, data...; options...)
102101
end
103102
return Library.save(q, data...; options...)
104103
catch e
105-
handle_current_error(e, library, library == last(libraries))
106104
push!(failures, (e, q))
107105
end
108106
end
109-
handle_error(failures)
107+
handle_exceptions(failures, "saving \"$(filename(q))\"")
110108
end

src/query.jl

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,8 @@ end
4646
const unknown_df = DataFormat{:UNKNOWN}
4747

4848
"""
49-
`unknown(f)` returns true if the format of `f` is unknown."""
49+
`unknown(f)` returns true if the format of `f` is unknown.
50+
"""
5051
unknown(::Type{format"UNKNOWN"}) = true
5152
unknown{sym}(::Type{DataFormat{sym}}) = false
5253

@@ -155,7 +156,8 @@ end
155156

156157
"""
157158
`info(fmt)` returns the magic bytes/extension information for
158-
`DataFormat` `fmt`."""
159+
`DataFormat` `fmt`.
160+
"""
159161
Base.info{sym}(::Type{DataFormat{sym}}) = sym2info[sym]
160162

161163

@@ -217,7 +219,8 @@ abstract Formatted{F<:DataFormat} # A specific file or stream
217219
"""
218220
`File(fmt, filename)` indicates that `filename` is a file of known
219221
DataFormat `fmt`. For example, `File{fmtpng}(filename)` would indicate a PNG
220-
file."""
222+
file.
223+
"""
221224
immutable File{F<:DataFormat} <: Formatted{F}
222225
filename::Compat.UTF8String
223226
end
@@ -239,7 +242,8 @@ file_extension(f::File) = splitext(filename(f))[2]
239242
`Stream(fmt, io, [filename])` indicates that the stream `io` is
240243
written in known `Format`. For example, `Stream{PNG}(io)` would
241244
indicate PNG format. If known, the optional `filename` argument can
242-
be used to improve error messages, etc."""
245+
be used to improve error messages, etc.
246+
"""
243247
immutable Stream{F<:DataFormat,IOtype<:IO} <: Formatted{F}
244248
io::IOtype
245249
filename::Nullable{Compat.UTF8String}
@@ -255,7 +259,8 @@ stream(s::Stream) = s.io
255259

256260
"""
257261
`filename(stream)` returns a nullable-string of the filename
258-
associated with `Stream` `stream`."""
262+
associated with `Stream` `stream`.
263+
"""
259264
filename(s::Stream) = s.filename
260265

261266
"""

test/error_handling.jl

Lines changed: 40 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,30 @@
1+
println("these tests will print warnings: ")
12
context("Not installed") do
2-
eval(Base, :(is_interactive = true)) # for interactive error handling
3+
eval(Base, :(is_interactive = true)) # for interactive error handling
34

4-
add_format(format"NotInstalled", (), ".not_installed", [:NotInstalled])
5-
stdin_copy = STDIN
5+
add_format(format"NotInstalled", (), ".not_installed", [:NotInstalled])
6+
stdin_copy = STDIN
67
stderr_copy = STDERR
78
rs, wr = redirect_stdin()
8-
rserr, wrerr = redirect_stderr()
9-
ref = @async save("test.not_installed")
10-
println(wr, "y")
11-
if VERSION < v"0.4.0-dev"
12-
@fact_throws ErrorException wait(ref) #("unknown package NotInstalled")
13-
else
14-
@fact_throws CompositeException wait(ref) #("unknown package NotInstalled")
15-
end
16-
ref = @async save("test.not_installed")
17-
println(wr, "invalid") #test invalid input
18-
println(wr, "n") # don't install
19-
wait(ref)
20-
@fact istaskdone(ref) --> true
9+
rserr, wrerr = redirect_stderr()
10+
ref = @async save("test.not_installed")
11+
println(wr, "y")
12+
if VERSION < v"0.4.0-dev"
13+
@fact_throws ErrorException wait(ref) #("unknown package NotInstalled")
14+
else
15+
@fact_throws CompositeException wait(ref) #("unknown package NotInstalled")
16+
end
17+
ref = @async save("test.not_installed")
18+
println(wr, "invalid") #test invalid input
19+
println(wr, "n") # don't install
20+
wait(ref)
21+
@fact istaskdone(ref) --> true
2122

2223
close(rs);close(wr);close(rserr);close(wrerr)
23-
redirect_stdin(stdin_copy)
24+
redirect_stdin(stdin_copy)
2425
redirect_stderr(stderr_copy)
2526

26-
eval(Base, :(is_interactive = false)) # for interactive error handling
27+
eval(Base, :(is_interactive = false)) # for interactive error handling
2728

2829
end
2930

@@ -41,3 +42,24 @@ context("Absent implementation") do
4142
@fact_throws FileIO.WriterError save(Stream(format"BROKEN", STDOUT))
4243
redirect_stderr(stderr_copy)
4344
end
45+
46+
module MultiError1
47+
import FileIO: @format_str, File
48+
load(file::File{format"MultiError"}) = error("1")
49+
end
50+
module MultiError2
51+
import FileIO: @format_str, File, magic
52+
load(file::File{format"MultiError"}) = error("2")
53+
end
54+
context("multiple errors") do
55+
println("this test will print warnings: ")
56+
add_format(
57+
format"MultiError",
58+
(),
59+
".multierr",
60+
[:MultiError1],
61+
[:MultiError2]
62+
)
63+
ret = @test_throws ErrorException load("test.multierr")
64+
#@test ret.value.msg == "1" # this is 0.5 only
65+
end

test/query.jl

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,9 @@ end
5454

5555
end
5656

57+
58+
59+
5760
try
5861
empty!(FileIO.ext2sym)
5962
empty!(FileIO.magic_list)
@@ -235,8 +238,6 @@ try
235238
[:LoadTest1, FileIO.LOAD, OSKey],
236239
[:LoadTest2]
237240
)
238-
stderr_copy = STDERR
239-
rd,wr = redirect_stderr()
240241
@fact lensave0 + 1 --> length(FileIO.sym2saver)
241242
@fact lenload0 + 1 --> length(FileIO.sym2loader)
242243
@fact length(FileIO.sym2loader[:MultiLib]) --> 2
@@ -252,9 +253,8 @@ try
252253
@fact isdefined(:LoadTest1) --> true # first module should load first but fail
253254
@fact x --> 42
254255
rm(fn)
255-
close(rd);close(wr)
256-
redirect_stderr(stderr_copy)
257256
end
257+
258258
finally
259259
# Restore the registry
260260
empty!(FileIO.ext2sym)

test/runtests.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using FileIO
22
using FactCheck
3+
using Base.Test
34
facts("FileIO") do
45
include("query.jl")
56
include("loadsave.jl")

0 commit comments

Comments
 (0)