Skip to content

Commit

Permalink
fixes for 0.7
Browse files Browse the repository at this point in the history
  • Loading branch information
SimonDanisch committed May 22, 2018
1 parent 31fb1ed commit 5bde79b
Show file tree
Hide file tree
Showing 7 changed files with 71 additions and 58 deletions.
1 change: 1 addition & 0 deletions src/FileIO.jl
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export DataFormat,
metadata

import Base.showerror
using Base: RefValue

include("query.jl")
include("error_handling.jl")
Expand Down
20 changes: 15 additions & 5 deletions src/loadsave.jl
Original file line number Diff line number Diff line change
@@ -1,11 +1,21 @@
const sym2loader = Dict{Symbol,Vector{Symbol}}()
const sym2saver = Dict{Symbol,Vector{Symbol}}()
const has_pkg3 = try
using Pkg3
true
catch e
false
end

function is_installed(pkg::Symbol)
isdefined(Main, pkg) && isa(getfield(Main, pkg), Module) && return true # is a module defined in Main scope
path = Base.find_in_path(string(pkg)) # hacky way to determine if a Package is installed
path == nothing && return false
return isfile(path)
if isdefined(Base, :find_in_path)
function is_installed(pkg::Symbol)
isdefined(Main, pkg) && isa(getfield(Main, pkg), Module) && return true # is a module defined in Main scope
path = Base.find_in_path(string(pkg)) # hacky way to determine if a Package is installed
path == nothing && return false
return isfile(path)
end
elseif has_pkg3 && isdefined(Pkg3, :installed)
is_installed(pkg::Symbol) = get(Pkg3.installed(), string(pkg), nothing) != nothing
end

function checked_import(pkg::Symbol)
Expand Down
47 changes: 26 additions & 21 deletions src/query.jl
Original file line number Diff line number Diff line change
Expand Up @@ -245,43 +245,42 @@ written in known `Format`. For example, `Stream{PNG}(io)` would
indicate PNG format. If known, the optional `filename` argument can
be used to improve error messages, etc.
"""
struct Stream{F<:DataFormat,IOtype<:IO} <: Formatted{F}
struct Stream{F <: DataFormat, IOtype <: IO} <: Formatted{F}
io::IOtype
filename::Nullable{String}
filename::Union{String, Nothing}
end

Stream{F<:DataFormat}(::Type{F}, io::IO) = Stream{F,typeof(io)}(io, Nullable{String}())
Stream{F<:DataFormat}(::Type{F}, io::IO, filename::AbstractString) = Stream{F,typeof(io)}(io,String(filename))
Stream{F<:DataFormat}(::Type{F}, io::IO, filename) = Stream{F,typeof(io)}(io,filename)
Stream{F}(file::File{F}, io::IO) = Stream{F,typeof(io)}(io,filename(file))
Stream{F<:DataFormat}(::Type{F}, io::IO) = Stream{F,typeof(io)}(io, nothing)
Stream{F<:DataFormat}(::Type{F}, io::IO, filename::AbstractString) = Stream{F, typeof(io)}(io, String(filename))
Stream{F<:DataFormat}(::Type{F}, io::IO, filename) = Stream{F, typeof(io)}(io, filename)
Stream{F}(file::File{F}, io::IO) = Stream{F, typeof(io)}(io, filename(file))

"`stream(s)` returns the stream associated with `Stream` `s`"
stream(s::Stream) = s.io

"""
`filename(stream)` returns a nullable-string of the filename
associated with `Stream` `stream`.
`filename(stream)` returns a string of the filename
associated with `Stream` `stream`, or nothing if there is no file associated.
"""
filename(s::Stream) = s.filename

"""
`file_extension(file)` returns a nullable-string for the file extension associated with `Stream` `stream`.
"""
function file_extension(f::Stream)
isnull(filename(f)) && return filename(f)
splitext(get(filename(f)))[2]
fname = filename(f)
(fname == nothing) && return nothing
splitext(fname)[2]
end

# Note this closes the stream. It's useful when you've opened
# the file to check the magic bytes, but don't want to leave
# a dangling stream.
function file!{F}(strm::Stream{F})
f = filename(strm)
if isnull(f)
error("filename unknown")
end
f == nothing && error("filename unknown")
close(strm.io)
File{F}(get(f))
File{F}(f)
end

# Implement standard I/O operations for File and Stream
Expand Down Expand Up @@ -329,9 +328,9 @@ skipmagic(io, magic::Function) = nothing
skipmagic{N}(io, magic::NTuple{N,UInt8}) = seek(io, length(magic))
function skipmagic(io, magic::Tuple)
lengths = map(length, magic)
all(x->lengths[1] == x, lengths) && return seek(io, lengths[1]) # it doesn't matter what magic bytes get skipped as they all have the same length
all(x-> lengths[1] == x, lengths) && return seek(io, lengths[1]) # it doesn't matter what magic bytes get skipped as they all have the same length
magic = [magic...]
sort!(magic, lt=(a,b)-> length(a)>= length(b)) # start with longest first, to avoid overlapping magic bytes
sort!(magic, lt = (a,b)-> length(a) >= length(b)) # start with longest first, to avoid overlapping magic bytes
seekend(io)
len = position(io)
seekstart(io)
Expand Down Expand Up @@ -397,9 +396,9 @@ hasfunction(s::Tuple) = false #has magic
`query(io, [filename])` returns a `Stream` object with information about the
format inferred from the magic bytes.
"""
query(io::IO, filename) = query(io, Nullable(String(filename)))
query(io::IO, filename) = query(io, String(filename))

function query(io::IO, filename::Nullable{String}=Nullable{String}())
function query(io::IO, filename::Union{Nothing, String} = nothing)
magic = Vector{UInt8}(0)
pos = position(io)
for p in magic_list
Expand All @@ -408,7 +407,7 @@ function query(io::IO, filename::Nullable{String}=Nullable{String}())
while length(m) > length(magic)
if eof(io)
seek(io, pos)
return Stream{unknown_df,typeof(io)}(io, filename)
return Stream{unknown_df, typeof(io)}(io, filename)
end
push!(magic, read(io, UInt8))
end
Expand All @@ -421,8 +420,14 @@ function query(io::IO, filename::Nullable{String}=Nullable{String}())
for p in magic_func
seek(io, pos)
f = first(p)
if f(io)
return Stream{DataFormat{last(p)},typeof(io)}(seek(io, pos), filename)
try
if f(io)
return Stream{DataFormat{last(p)},typeof(io)}(seek(io, pos), filename)
end
catch e
println("There was an error in magick function $f")
println("Please open an issue at FileIO.jl. Error:")
println(e)
end
end
seek(io, pos)
Expand Down
39 changes: 18 additions & 21 deletions src/registry.jl
Original file line number Diff line number Diff line change
Expand Up @@ -160,21 +160,19 @@ add_format(format"FLAC","fLaC",".flac",[:FLAC])
### Complex cases

# bedGraph: the complication is that the magic bytes may start at any location within an indeterminate header.
const bedgraph_magic = UInt8[0x74, 0x79, 0x70, 0x65, 0x3D, 0x62, 0x65, 0x64, 0x47, 0x72, 0x61, 0x70, 0x68]
function detect_bedgraph(io)
position(io) == 0 || return false

line = ""

bedgraph_magic = b"type=bedGraph"
# Check lines for magic bytes.
while !eof(io) && !ismatch(r"^\s*([A-Za-z]+\S*)\s+(\d+)\s+(\d+)\s+(\S*\d)\s*$", line) # Note: regex is used to limit the search by exiting the loop when a line matches the bedGraph track format.
line = readline(io, chomp=false)

if contains(line, String(bedgraph_magic)) # Note: String(bedgraph_magic) = "type=bedGraph"
return true
pos = 1
while !eof(io)
r = read(io, UInt8)
if bedgraph_magic[pos] == r
pos >= length(bedgraph_magic) && return true
pos += 1
else
pos = 1
end
end

return false
end
add_format(format"bedGraph", detect_bedgraph, [".bedgraph"], [:BedgraphFiles])
Expand Down Expand Up @@ -235,28 +233,28 @@ end
add_format(format"HDF5", detecthdf5, [".h5", ".hdf5"], [:HDF5])

function detect_stlascii(io)
pos = position(io)
try
position(io) != 0 && (seekstart(io); return false)
seekend(io)
len = position(io)
seekstart(io)
seek(io, pos)
len < 80 && return false
header = read(io, 80) # skip header
seekstart(io)
seek(io, pos)
@show String(header[1:6])
header[1:6] == b"solid " && !detect_stlbinary(io)
finally
seekstart(io)
seek(io, pos)
end
end

function detect_stlbinary(io)
size_header = 80+sizeof(UInt32)
size_triangleblock = (4*3*sizeof(Float32)) + sizeof(UInt16)

position(io) != 0 && (seekstart(io); return false)
size_header = 80 + sizeof(UInt32)
size_triangleblock = (4 * 3 * sizeof(Float32)) + sizeof(UInt16)
pos = position(io)
seekend(io)
len = position(io)
seekstart(io)
seek(io, pos)
len < size_header && return false

skip(io, 80) # skip header
Expand All @@ -267,7 +265,6 @@ function detect_stlbinary(io)
attrib_byte_count = read(io, UInt16) # read last attrib_byte
attrib_byte_count != zero(UInt16) && (seekstart(io); return false) # should be zero as not used
result = eof(io) # if end of file, we have a stl!
seekstart(io)
return result
end
add_format(format"STL_ASCII", detect_stlascii, [".stl", ".STL"], [:MeshIO])
Expand Down
4 changes: 2 additions & 2 deletions test/error_handling.jl
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@ println("these tests will print warnings: ")
rserr, wrerr = redirect_stderr()
ref = @async save("test.not_installed", nothing)
println(wr, "y")
@test_throws CompositeException wait(ref) #("unknown package NotInstalled")
@test_throws CompositeException fetch(ref) #("unknown package NotInstalled")
ref = @async save("test.not_installed", nothing)
println(wr, "invalid") #test invalid input
println(wr, "n") # don't install
wait(ref)
fetch(ref)
@test istaskdone(ref)

close(rs);close(wr);close(rserr);close(wrerr)
Expand Down
8 changes: 4 additions & 4 deletions test/loadsave.jl
Original file line number Diff line number Diff line change
Expand Up @@ -175,8 +175,8 @@ add_saver(format"DUMMY", :Dummy)
f = File(format"DUMMY", fnrel)
@test !(isabspath(filename(f)))
open(f) do s
@test isabspath(get(filename(s)))
@test endswith(get(filename(s)),fn)
@test isabspath(filename(s))
@test endswith(filename(s), fn)
end
end

Expand All @@ -192,8 +192,8 @@ add_saver(format"DUMMY", :Dummy)
f = File(format"DUMMY", fnrel)
@test !(isabspath(filename(f)))
open(f) do s
@test isabspath(get(filename(s)))
@test endswith(get(filename(s)),fn2)
@test isabspath(filename(s))
@test endswith(filename(s),fn2)
end
end
rm(fn2)
Expand Down
10 changes: 5 additions & 5 deletions test/query.jl
Original file line number Diff line number Diff line change
Expand Up @@ -93,12 +93,12 @@ try
io = IOBuffer()
s = Stream(format"JUNK", io)
@test typeof(s) == Stream{DataFormat{:JUNK},IOBuffer}
@test isnull(filename(s))
@test filename(s) == nothing
@test_throws Exception FileIO.file!(s)
s = Stream(format"JUNK", io, "junk.jnk")
@test get(filename(s)) == "junk.jnk"
s = Stream(format"JUNK", io, Nullable("junk2.jnk"))
@test get(filename(s)) == "junk2.jnk"
@test filename(s) == "junk.jnk"
s = Stream(format"JUNK", io, "junk2.jnk")
@test filename(s) == "junk2.jnk"
end

@testset "query" begin
Expand All @@ -122,7 +122,7 @@ try
q = query(io)
@test typeof(q) == Stream{format"JUNK",typeof(io)}
@test !(unknown(q))
@test isnull(file_extension(q))
@test file_extension(q) == nothing

# File with correct extension
str = String(take!(io))
Expand Down

0 comments on commit 5bde79b

Please sign in to comment.