From 58c24969fe6d8da15bff263bc0a854f927536282 Mon Sep 17 00:00:00 2001 From: David Anthoff Date: Fri, 28 Aug 2026 14:38:49 -0700 Subject: [PATCH] Create a v2 --- Project.toml | 5 +- src/ExcelFiles.jl | 108 ++++++++++++++++++++++++++--- test/TestData.xls | Bin 0 -> 29184 bytes test/TestData.xlsx | Bin 0 -> 17767 bytes test/runtests.jl | 150 +--------------------------------------- test/test_excelfiles.jl | 147 +++++++++++++++++++++++++++++++++++++++ 6 files changed, 249 insertions(+), 161 deletions(-) create mode 100644 test/TestData.xls create mode 100644 test/TestData.xlsx create mode 100644 test/test_excelfiles.jl diff --git a/Project.toml b/Project.toml index 68ecaaa..9394511 100644 --- a/Project.toml +++ b/Project.toml @@ -18,7 +18,7 @@ XLSX = "fdbf4ff8-1666-58a4-91e7-1b58723a45e0" [compat] DataValues = "0.4.11" -ExcelReaders = "0.11" +ExcelReaders = "0.11, 0.12" FileIO = "1" IterableTables = "0.8.3, 0.9, 0.10, 0.11, 1" IteratorInterfaceExtensions = "0.1.1, 1" @@ -32,6 +32,7 @@ julia = "1" [extras] DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" +TestItemRunner = "f8b46487-2199-4994-9208-9a1283c18c0a" [targets] -test = ["Test", "DataFrames"] +test = ["Test", "TestItemRunner", "DataFrames"] diff --git a/src/ExcelFiles.jl b/src/ExcelFiles.jl index 9b7eb6a..f1b1903 100644 --- a/src/ExcelFiles.jl +++ b/src/ExcelFiles.jl @@ -49,7 +49,7 @@ function gennames(n::Integer) return res end -function _readxl(file::ExcelReaders.ExcelFile, sheetname::AbstractString, startrow::Integer, startcol::Integer, endrow::Integer, endcol::Integer; header::Bool=true, colnames::Vector{Symbol}=Symbol[]) +function _readxls(file::ExcelReaders.ExcelFile, sheetname::AbstractString, startrow::Integer, startcol::Integer, endrow::Integer, endcol::Integer; header::Bool=true, colnames::Vector{Symbol}=Symbol[]) data = ExcelReaders.readxl_internal(file, sheetname, startrow, startcol, endrow, endcol) nrow, ncol = size(data) @@ -103,24 +103,110 @@ function _readxl(file::ExcelReaders.ExcelFile, sheetname::AbstractString, startr return columns, colnames end +function process_xlsx_data(data; header::Bool=true, colnames::Vector{Symbol}=Symbol[]) + nrow, ncol = size(data) + + if length(colnames) == 0 + if header + headervec = data[1, :] + NAcol = map(i -> isa(i, DataValues.DataValue) && DataValues.isna(i), headervec) + headervec[NAcol] = gennames(count(!iszero, NAcol)) + + # This somewhat complicated conditional makes sure that column names + # that are integer numbers end up without an extra ".0" as their name + colnames = [isa(i, AbstractFloat) ? ( modf(i)[1] == 0.0 ? Symbol(Int(i)) : Symbol(string(i)) ) : Symbol(i) for i in vec(headervec)] + else + colnames = gennames(ncol) + end + elseif length(colnames) != ncol + error("Length of colnames must equal number of columns in selected range") + end + + columns = Array{Any}(undef, ncol) + + for i = 1:ncol + if header + vals = data[2:end,i] + else + vals = data[:,i] + end + + # Check whether all non-NA values in this column + # are of the same type + type_of_el = length(vals) > 0 ? typeof(vals[1]) : Any + for val = vals + type_of_el = promote_type(type_of_el, typeof(val)) + end + + if type_of_el <: DataValue + columns[i] = convert(DataValueArray{eltype(type_of_el)}, vals) + + # TODO Check wether this hack is correct + for (j, v) in enumerate(columns[i]) + if v isa DataValue && !DataValues.isna(v) && v[] isa DataValue + columns[i][j] = v[] + end + end + else + columns[i] = convert(Array{type_of_el}, vals) + end + end + + return columns, colnames +end + +function _readxlsx(file, sheetname::AbstractString, startrow::Integer, startcol::Integer, endrow::Integer, endcol::Integer; header::Bool=true, colnames::Vector{Symbol}=Symbol[]) + data = ExcelReaders.readxl_internal(file, sheetname, startrow, startcol, endrow, endcol) + + +end + +function _readxlsx(file, range; header::Bool=true, colnames::Vector{Symbol}=Symbol[]) + data = ExcelReaders.readxl_internal(file, sheetname, startrow, startcol, endrow, endcol) + + process_xlsx_data(data, header=header, colnames=colnames) +end + function IteratorInterfaceExtensions.getiterator(file::ExcelFile) + old_style_excel_file = endswith(file.filename, ".xls") + column_data, col_names = if occursin("!", file.range) - excelfile = openxl(file.filename) + if old_style_excel_file + excelfile = openxl(file.filename) - sheetname, startrow, startcol, endrow, endcol = ExcelReaders.convert_ref_to_sheet_row_col(file.range) + sheetname, startrow, startcol, endrow, endcol = ExcelReaders.convert_ref_to_sheet_row_col(file.range) - _readxl(excelfile, sheetname, startrow, startcol, endrow, endcol; file.keywords...) + _readxls(excelfile, sheetname, startrow, startcol, endrow, endcol; file.keywords...) + else + excelfile = XLSX.readxlsx(file.filename) + + _readxlsx(excelfile, file.range; file.keywords...) + end else - excelfile = openxl(file.filename) - sheet = excelfile.workbook.sheet_by_name(file.range) + if old_style_excel_file + excelfile = openxl(file.filename) + sheet = excelfile.workbook.sheet_by_name(file.range) + + keywords = filter(i -> !(i[1] in (:header, :colnames)), file.keywords) + startrow, startcol, endrow, endcol = ExcelReaders.convert_args_to_row_col(sheet; keywords...) + + keywords2 = copy(file.keywords) + keywords2 = filter(i -> !(i[1] in (:skipstartrows, :skipstartcols, :nrows, :ncols)), file.keywords) - keywords = filter(i -> !(i[1] in (:header, :colnames)), file.keywords) - startrow, startcol, endrow, endcol = ExcelReaders.convert_args_to_row_col(sheet; keywords...) + _readxls(excelfile, file.range, startrow, startcol, endrow, endcol; keywords2...) + else + excelfile = openxl(file.filename) + + sheet = excelfile[file.range] - keywords2 = copy(file.keywords) - keywords2 = filter(i -> !(i[1] in (:skipstartrows, :skipstartcols, :nrows, :ncols)), file.keywords) + keywords = filter(i -> !(i[1] in (:header, :colnames)), file.keywords) + startrow, startcol, endrow, endcol = ExcelReaders.convert_args_to_row_col(sheet; keywords...) - _readxl(excelfile, file.range, startrow, startcol, endrow, endcol; keywords2...) + keywords2 = copy(file.keywords) + keywords2 = filter(i -> !(i[1] in (:skipstartrows, :skipstartcols, :nrows, :ncols)), file.keywords) + + _readxls(excelfile, file.range, startrow, startcol, endrow, endcol; keywords2...) + end end return create_tableiterator(column_data, col_names) diff --git a/test/TestData.xls b/test/TestData.xls new file mode 100644 index 0000000000000000000000000000000000000000..af2ebbed5da6903e2706a85eb9cafa2e864616d1 GIT binary patch literal 29184 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 literal 0 HcmV?d00001 diff --git a/test/TestData.xlsx b/test/TestData.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..817ae13911eadce4063a26df26c660395020e97d GIT binary patch literal 17767 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 EFGxw%9RL6T literal 0 HcmV?d00001 diff --git a/test/runtests.jl b/test/runtests.jl index d1d0372..b9e874d 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1,149 +1,3 @@ -using ExcelFiles -using ExcelReaders -using IteratorInterfaceExtensions -using TableTraits -using TableTraitsUtils -using Dates -using DataValues -using DataFrames -using Test +using TestItemRunner -@testset "ExcelFiles" begin - - filename = normpath(dirname(pathof(ExcelReaders)), "..", "test", "TestData.xlsx") - - efile = load(filename, "Sheet1") - - @test sprint((stream, data) -> show(stream, "text/html", data), efile) == "
Some Float64sSome StringsSome BoolsMixed columnMixed with NAFloat64 with NAString with NABool with NASome datesDates with NASome errorsErrors with NAColumn with NULL and then mixed
1.0"A"true2.09.03.0"FF"#NA2015-03-03T00:00:001965-04-03T00:00:00#DIV/0!#DIV/0!#NA
1.5"BB"false"EEEEE""III"#NA#NAtrue2015-02-04T10:14:001950-08-09T18:40:00#N/A#N/A3.4
2.0"CCC"falsefalse#NA3.5"GGG"#NA1988-04-09T00:00:0019:00:00#REF!#NAME?"HKEJW"
2.5"DDDD"true1.5true4.0"HHHH"false15:02:00#NA#NAME?#NA#NA
" - - @test sprint((stream, data) -> show(stream, "application/vnd.dataresource+json", data), efile) == "{\"schema\":{\"fields\":[{\"name\":\"Some Float64s\",\"type\":\"number\"},{\"name\":\"Some Strings\",\"type\":\"string\"},{\"name\":\"Some Bools\",\"type\":\"boolean\"},{\"name\":\"Mixed column\",\"type\":\"string\"},{\"name\":\"Mixed with NA\",\"type\":\"string\"},{\"name\":\"Float64 with NA\",\"type\":\"number\"},{\"name\":\"String with NA\",\"type\":\"string\"},{\"name\":\"Bool with NA\",\"type\":\"boolean\"},{\"name\":\"Some dates\",\"type\":\"string\"},{\"name\":\"Dates with NA\",\"type\":\"string\"},{\"name\":\"Some errors\",\"type\":\"string\"},{\"name\":\"Errors with NA\",\"type\":\"string\"},{\"name\":\"Column with NULL and then mixed\",\"type\":\"string\"}]},\"data\":[{\"Some Float64s\":1.0,\"Some Strings\":\"A\",\"Some Bools\":true,\"Mixed column\":2.0,\"Mixed with NA\":9.0,\"Float64 with NA\":3.0,\"String with NA\":\"FF\",\"Bool with NA\":null,\"Some dates\":\"2015-03-03T00:00:00\",\"Dates with NA\":\"1965-04-03T00:00:00\",\"Some errors\":{\"errorcode\":7},\"Errors with NA\":{\"errorcode\":7},\"Column with NULL and then mixed\":null},{\"Some Float64s\":1.5,\"Some Strings\":\"BB\",\"Some Bools\":false,\"Mixed column\":\"EEEEE\",\"Mixed with NA\":\"III\",\"Float64 with NA\":null,\"String with NA\":null,\"Bool with NA\":true,\"Some dates\":\"2015-02-04T10:14:00\",\"Dates with NA\":\"1950-08-09T18:40:00\",\"Some errors\":{\"errorcode\":42},\"Errors with NA\":{\"errorcode\":42},\"Column with NULL and then mixed\":3.4},{\"Some Float64s\":2.0,\"Some Strings\":\"CCC\",\"Some Bools\":false,\"Mixed column\":false,\"Mixed with NA\":null,\"Float64 with NA\":3.5,\"String with NA\":\"GGG\",\"Bool with NA\":null,\"Some dates\":\"1988-04-09T00:00:00\",\"Dates with NA\":\"19:00:00\",\"Some errors\":{\"errorcode\":23},\"Errors with NA\":{\"errorcode\":29},\"Column with NULL and then mixed\":\"HKEJW\"},{\"Some Float64s\":2.5,\"Some Strings\":\"DDDD\",\"Some Bools\":true,\"Mixed column\":1.5,\"Mixed with NA\":true,\"Float64 with NA\":4.0,\"String with NA\":\"HHHH\",\"Bool with NA\":false,\"Some dates\":\"15:02:00\",\"Dates with NA\":null,\"Some errors\":{\"errorcode\":29},\"Errors with NA\":null,\"Column with NULL and then mixed\":null}]}" - - @test sprint(show, efile) == "4x13 Excel file\nSome Float64s │ Some Strings │ Some Bools │ Mixed column │ Mixed with NA\n──────────────┼──────────────┼────────────┼──────────────┼──────────────\n1.0 │ A │ true │ 2.0 │ 9.0 \n1.5 │ BB │ false │ \"EEEEE\" │ \"III\" \n2.0 │ CCC │ false │ false │ #NA \n2.5 │ DDDD │ true │ 1.5 │ true \n... with 8 more columns: Float64 with NA, String with NA, Bool with NA, Some dates, Dates with NA, Some errors, Errors with NA, Column with NULL and then mixed" - - @test TableTraits.isiterabletable(efile) == true - @test IteratorInterfaceExtensions.isiterable(efile) == true - @test showable("text/html", efile) == true - @test showable("application/vnd.dataresource+json", efile) == true - - @test isiterable(efile) == true - - full_dfs = [create_columns_from_iterabletable(load(filename, "Sheet1!C3:O7")), create_columns_from_iterabletable(load(filename, "Sheet1"))] - for (df, names) in full_dfs - @test length(df) == 13 - @test length(df[1]) == 4 - - @test df[1] == [1., 1.5, 2., 2.5] - @test df[2] == ["A", "BB", "CCC", "DDDD"] - @test df[3] == [true, false, false, true] - @test df[4] == [2, "EEEEE", false, 1.5] - @test df[5] == [9., "III", NA, true] - @test df[6] == [3., NA, 3.5, 4] - @test df[7] == ["FF", NA, "GGG", "HHHH"] - @test df[8] == [NA, true, NA, false] - @test df[9] == [Date(2015, 3, 3), DateTime(2015, 2, 4, 10, 14), Date(1988, 4, 9), Dates.Time(15, 2, 0)] - @test df[10] == [Date(1965, 4, 3), DateTime(1950, 8, 9, 18, 40), Dates.Time(19, 0, 0), NA] - @test eltype(df[11]) == ExcelReaders.ExcelErrorCell - @test df[12][1][] isa ExcelReaders.ExcelErrorCell - @test df[12][2][] isa ExcelReaders.ExcelErrorCell - @test df[12][3][] isa ExcelReaders.ExcelErrorCell - @test df[12][4] == NA - @test df[13] == [NA, 3.4, "HKEJW", NA] - end - - df, names = create_columns_from_iterabletable(load(filename, "Sheet1!C4:O7", header=false)) - @test names == [:x1,:x2,:x3,:x4,:x5,:x6,:x7,:x8,:x9,:x10,:x11,:x12,:x13] - @test length(df[1]) == 4 - @test length(df) == 13 - @test df[1] == [1., 1.5, 2., 2.5] - @test df[2] == ["A", "BB", "CCC", "DDDD"] - @test df[3] == [true, false, false, true] - @test df[4] == [2, "EEEEE", false, 1.5] - @test df[5] == [9., "III", NA, true] - @test df[6] == [3, NA, 3.5, 4] - @test df[7] == ["FF", NA, "GGG", "HHHH"] - @test df[8] == [NA, true, NA, false] - @test df[9] == [Date(2015, 3, 3), DateTime(2015, 2, 4, 10, 14), DateTime(1988, 4, 9), Dates.Time(15, 2, 0)] - @test df[10] == [Date(1965, 4, 3), DateTime(1950, 8, 9, 18, 40), Dates.Time(19, 0, 0), NA] - @test isa(df[11][1], ExcelReaders.ExcelErrorCell) - @test isa(df[11][2], ExcelReaders.ExcelErrorCell) - @test isa(df[11][3], ExcelReaders.ExcelErrorCell) - @test isa(df[11][4], ExcelReaders.ExcelErrorCell) - @test isa(df[12][1][], ExcelReaders.ExcelErrorCell) - @test isa(df[12][2][], ExcelReaders.ExcelErrorCell) - @test isa(df[12][3][], ExcelReaders.ExcelErrorCell) - @test DataValues.isna(df[12][4]) - @test df[13] == [NA, 3.4, "HKEJW", NA] - - good_colnames = [:c1, :c2, :c3, :c4, :c5, :c6, :c7, :c8, :c9, :c10, :c11, :c12, :c13] - - df, names = create_columns_from_iterabletable(load(filename, "Sheet1!C4:O7", header=false, colnames=good_colnames)) - @test names == good_colnames - @test length(df[1]) == 4 - @test length(df) == 13 - @test df[1] == [1., 1.5, 2., 2.5] - @test df[2] == ["A", "BB", "CCC", "DDDD"] - @test df[3] == [true, false, false, true] - @test df[4] == [2, "EEEEE", false, 1.5] - @test df[5] == [9., "III", NA, true] - @test df[6] == [3, NA, 3.5, 4] - @test df[7] == ["FF", NA, "GGG", "HHHH"] - @test df[8] == [NA, true, NA, false] - @test df[9] == [Date(2015, 3, 3), DateTime(2015, 2, 4, 10, 14), DateTime(1988, 4, 9), Dates.Time(15, 2, 0)] - @test df[10] == [Date(1965, 4, 3), DateTime(1950, 8, 9, 18, 40), Dates.Time(19, 0, 0), NA] - @test isa(df[11][1], ExcelReaders.ExcelErrorCell) - @test isa(df[11][2], ExcelReaders.ExcelErrorCell) - @test isa(df[11][3], ExcelReaders.ExcelErrorCell) - @test isa(df[11][4], ExcelReaders.ExcelErrorCell) - @test isa(df[12][1][], ExcelReaders.ExcelErrorCell) - @test isa(df[12][2][], ExcelReaders.ExcelErrorCell) - @test isa(df[12][3][], ExcelReaders.ExcelErrorCell) - @test DataValues.isna(df[12][4]) - @test df[13] == [NA, 3.4, "HKEJW", NA] - -# Test for saving DataFrame to XLSX - input = (Day = ["Nov. 27","Nov. 28","Nov. 29"], Highest = [78,79,75]) |> DataFrame - file = save("file.xlsx", input) - output = load("file.xlsx", "Sheet1") |> DataFrame - @test input == output - rm("file.xlsx") - -# Test for saving DataFrame to XLSX with sheetname keyword - input = (Day = ["Nov. 27","Nov. 28","Nov. 29"], Highest = [78,79,75]) |> DataFrame - file = save("file.xlsx", input, sheetname="SheetName") - output = load("file.xlsx", "SheetName") |> DataFrame - @test input == output - rm("file.xlsx") - - df, names = create_columns_from_iterabletable(load(filename, "Sheet1", colnames=good_colnames)) - @test names == good_colnames - @test length(df[1]) == 4 - @test length(df) == 13 - @test df[1] == [1., 1.5, 2., 2.5] - @test df[2] == ["A", "BB", "CCC", "DDDD"] - @test df[3] == [true, false, false, true] - @test df[4] == [2, "EEEEE", false, 1.5] - @test df[5] == [9., "III", NA, true] - @test df[6] == [3, NA, 3.5, 4] - @test df[7] == ["FF", NA, "GGG", "HHHH"] - @test df[8] == [NA, true, NA, false] - @test df[9] == [Date(2015, 3, 3), DateTime(2015, 2, 4, 10, 14), DateTime(1988, 4, 9), Dates.Time(15, 2, 0)] - @test df[10] == [Date(1965, 4, 3), DateTime(1950, 8, 9, 18, 40), Dates.Time(19, 0, 0), NA] - @test isa(df[11][1], ExcelReaders.ExcelErrorCell) - @test isa(df[11][2], ExcelReaders.ExcelErrorCell) - @test isa(df[11][3], ExcelReaders.ExcelErrorCell) - @test isa(df[11][4], ExcelReaders.ExcelErrorCell) - @test isa(df[12][1][], ExcelReaders.ExcelErrorCell) - @test isa(df[12][2][], ExcelReaders.ExcelErrorCell) - @test isa(df[12][3][], ExcelReaders.ExcelErrorCell) - @test DataValues.isna(df[12][4]) - @test df[13] == [NA, 3.4, "HKEJW", NA] - -# Too few colnames - @test_throws ErrorException create_columns_from_iterabletable(load(filename, "Sheet1!C4:O7", header=true, colnames=[:c1, :c2, :c3, :c4])) - -# Test for constructing DataFrame with empty header cell - data, names = create_columns_from_iterabletable(load(filename, "Sheet2!C5:E7")) - @test names == [:Col1, :x1, :Col3] - - -end +@run_package_tests diff --git a/test/test_excelfiles.jl b/test/test_excelfiles.jl new file mode 100644 index 0000000..ed915f0 --- /dev/null +++ b/test/test_excelfiles.jl @@ -0,0 +1,147 @@ +@testitem "ExcelFiles" begin + using ExcelReaders + using IteratorInterfaceExtensions + using TableTraits + using TableTraitsUtils + using Dates + using DataValues + using DataFrames + + for filename in [joinpath(@__DIR__, "TestData.xls"), joinpath(@__DIR__, "TestData.xlsx")] + + efile = load(filename, "Sheet1") + + @test sprint((stream, data) -> show(stream, "text/html", data), efile) == "
Some Float64sSome StringsSome BoolsMixed columnMixed with NAFloat64 with NAString with NABool with NASome datesDates with NASome errorsErrors with NAColumn with NULL and then mixed
1.0"A"true2.09.03.0"FF"#NA2015-03-03T00:00:001965-04-03T00:00:00#DIV/0!#DIV/0!#NA
1.5"BB"false"EEEEE""III"#NA#NAtrue2015-02-04T10:14:001950-08-09T18:40:00#N/A#N/A3.4
2.0"CCC"falsefalse#NA3.5"GGG"#NA1988-04-09T00:00:0019:00:00#REF!#NAME?"HKEJW"
2.5"DDDD"true1.5true4.0"HHHH"false15:02:00#NA#NAME?#NA#NA
" + + @test sprint((stream, data) -> show(stream, "application/vnd.dataresource+json", data), efile) == "{\"schema\":{\"fields\":[{\"name\":\"Some Float64s\",\"type\":\"number\"},{\"name\":\"Some Strings\",\"type\":\"string\"},{\"name\":\"Some Bools\",\"type\":\"boolean\"},{\"name\":\"Mixed column\",\"type\":\"string\"},{\"name\":\"Mixed with NA\",\"type\":\"string\"},{\"name\":\"Float64 with NA\",\"type\":\"number\"},{\"name\":\"String with NA\",\"type\":\"string\"},{\"name\":\"Bool with NA\",\"type\":\"boolean\"},{\"name\":\"Some dates\",\"type\":\"string\"},{\"name\":\"Dates with NA\",\"type\":\"string\"},{\"name\":\"Some errors\",\"type\":\"string\"},{\"name\":\"Errors with NA\",\"type\":\"string\"},{\"name\":\"Column with NULL and then mixed\",\"type\":\"string\"}]},\"data\":[{\"Some Float64s\":1.0,\"Some Strings\":\"A\",\"Some Bools\":true,\"Mixed column\":2.0,\"Mixed with NA\":9.0,\"Float64 with NA\":3.0,\"String with NA\":\"FF\",\"Bool with NA\":null,\"Some dates\":\"2015-03-03T00:00:00\",\"Dates with NA\":\"1965-04-03T00:00:00\",\"Some errors\":{\"errorcode\":7},\"Errors with NA\":{\"errorcode\":7},\"Column with NULL and then mixed\":null},{\"Some Float64s\":1.5,\"Some Strings\":\"BB\",\"Some Bools\":false,\"Mixed column\":\"EEEEE\",\"Mixed with NA\":\"III\",\"Float64 with NA\":null,\"String with NA\":null,\"Bool with NA\":true,\"Some dates\":\"2015-02-04T10:14:00\",\"Dates with NA\":\"1950-08-09T18:40:00\",\"Some errors\":{\"errorcode\":42},\"Errors with NA\":{\"errorcode\":42},\"Column with NULL and then mixed\":3.4},{\"Some Float64s\":2.0,\"Some Strings\":\"CCC\",\"Some Bools\":false,\"Mixed column\":false,\"Mixed with NA\":null,\"Float64 with NA\":3.5,\"String with NA\":\"GGG\",\"Bool with NA\":null,\"Some dates\":\"1988-04-09T00:00:00\",\"Dates with NA\":\"19:00:00\",\"Some errors\":{\"errorcode\":23},\"Errors with NA\":{\"errorcode\":29},\"Column with NULL and then mixed\":\"HKEJW\"},{\"Some Float64s\":2.5,\"Some Strings\":\"DDDD\",\"Some Bools\":true,\"Mixed column\":1.5,\"Mixed with NA\":true,\"Float64 with NA\":4.0,\"String with NA\":\"HHHH\",\"Bool with NA\":false,\"Some dates\":\"15:02:00\",\"Dates with NA\":null,\"Some errors\":{\"errorcode\":29},\"Errors with NA\":null,\"Column with NULL and then mixed\":null}]}" + + @test sprint(show, efile) == "4x13 Excel file\nSome Float64s │ Some Strings │ Some Bools │ Mixed column │ Mixed with NA\n──────────────┼──────────────┼────────────┼──────────────┼──────────────\n1.0 │ A │ true │ 2.0 │ 9.0 \n1.5 │ BB │ false │ \"EEEEE\" │ \"III\" \n2.0 │ CCC │ false │ false │ #NA \n2.5 │ DDDD │ true │ 1.5 │ true \n... with 8 more columns: Float64 with NA, String with NA, Bool with NA, Some dates, Dates with NA, Some errors, Errors with NA, Column with NULL and then mixed" + + @test TableTraits.isiterabletable(efile) == true + @test IteratorInterfaceExtensions.isiterable(efile) == true + @test showable("text/html", efile) == true + @test showable("application/vnd.dataresource+json", efile) == true + + @test isiterable(efile) == true + + full_dfs = [create_columns_from_iterabletable(load(filename, "Sheet1!C3:O7")), create_columns_from_iterabletable(load(filename, "Sheet1"))] + for (df, names) in full_dfs + @test length(df) == 13 + @test length(df[1]) == 4 + + @test df[1] == [1., 1.5, 2., 2.5] + @test df[2] == ["A", "BB", "CCC", "DDDD"] + @test df[3] == [true, false, false, true] + @test df[4] == [2, "EEEEE", false, 1.5] + @test df[5] == [9., "III", NA, true] + @test df[6] == [3., NA, 3.5, 4] + @test df[7] == ["FF", NA, "GGG", "HHHH"] + @test df[8] == [NA, true, NA, false] + @test df[9] == [Date(2015, 3, 3), DateTime(2015, 2, 4, 10, 14), Date(1988, 4, 9), Dates.Time(15, 2, 0)] + @test df[10] == [Date(1965, 4, 3), DateTime(1950, 8, 9, 18, 40), Dates.Time(19, 0, 0), NA] + @test eltype(df[11]) == ExcelReaders.ExcelErrorCell + @test df[12][1][] isa ExcelReaders.ExcelErrorCell + @test df[12][2][] isa ExcelReaders.ExcelErrorCell + @test df[12][3][] isa ExcelReaders.ExcelErrorCell + @test df[12][4] == NA + @test df[13] == [NA, 3.4, "HKEJW", NA] + end + + df, names = create_columns_from_iterabletable(load(filename, "Sheet1!C4:O7", header=false)) + @test names == [:x1,:x2,:x3,:x4,:x5,:x6,:x7,:x8,:x9,:x10,:x11,:x12,:x13] + @test length(df[1]) == 4 + @test length(df) == 13 + @test df[1] == [1., 1.5, 2., 2.5] + @test df[2] == ["A", "BB", "CCC", "DDDD"] + @test df[3] == [true, false, false, true] + @test df[4] == [2, "EEEEE", false, 1.5] + @test df[5] == [9., "III", NA, true] + @test df[6] == [3, NA, 3.5, 4] + @test df[7] == ["FF", NA, "GGG", "HHHH"] + @test df[8] == [NA, true, NA, false] + @test df[9] == [Date(2015, 3, 3), DateTime(2015, 2, 4, 10, 14), DateTime(1988, 4, 9), Dates.Time(15, 2, 0)] + @test df[10] == [Date(1965, 4, 3), DateTime(1950, 8, 9, 18, 40), Dates.Time(19, 0, 0), NA] + @test isa(df[11][1], ExcelReaders.ExcelErrorCell) + @test isa(df[11][2], ExcelReaders.ExcelErrorCell) + @test isa(df[11][3], ExcelReaders.ExcelErrorCell) + @test isa(df[11][4], ExcelReaders.ExcelErrorCell) + @test isa(df[12][1][], ExcelReaders.ExcelErrorCell) + @test isa(df[12][2][], ExcelReaders.ExcelErrorCell) + @test isa(df[12][3][], ExcelReaders.ExcelErrorCell) + @test DataValues.isna(df[12][4]) + @test df[13] == [NA, 3.4, "HKEJW", NA] + + good_colnames = [:c1, :c2, :c3, :c4, :c5, :c6, :c7, :c8, :c9, :c10, :c11, :c12, :c13] + + df, names = create_columns_from_iterabletable(load(filename, "Sheet1!C4:O7", header=false, colnames=good_colnames)) + @test names == good_colnames + @test length(df[1]) == 4 + @test length(df) == 13 + @test df[1] == [1., 1.5, 2., 2.5] + @test df[2] == ["A", "BB", "CCC", "DDDD"] + @test df[3] == [true, false, false, true] + @test df[4] == [2, "EEEEE", false, 1.5] + @test df[5] == [9., "III", NA, true] + @test df[6] == [3, NA, 3.5, 4] + @test df[7] == ["FF", NA, "GGG", "HHHH"] + @test df[8] == [NA, true, NA, false] + @test df[9] == [Date(2015, 3, 3), DateTime(2015, 2, 4, 10, 14), DateTime(1988, 4, 9), Dates.Time(15, 2, 0)] + @test df[10] == [Date(1965, 4, 3), DateTime(1950, 8, 9, 18, 40), Dates.Time(19, 0, 0), NA] + @test isa(df[11][1], ExcelReaders.ExcelErrorCell) + @test isa(df[11][2], ExcelReaders.ExcelErrorCell) + @test isa(df[11][3], ExcelReaders.ExcelErrorCell) + @test isa(df[11][4], ExcelReaders.ExcelErrorCell) + @test isa(df[12][1][], ExcelReaders.ExcelErrorCell) + @test isa(df[12][2][], ExcelReaders.ExcelErrorCell) + @test isa(df[12][3][], ExcelReaders.ExcelErrorCell) + @test DataValues.isna(df[12][4]) + @test df[13] == [NA, 3.4, "HKEJW", NA] + + # Test for saving DataFrame to XLSX + input = (Day = ["Nov. 27","Nov. 28","Nov. 29"], Highest = [78,79,75]) |> DataFrame + + mktempdir() do path + file = save(joinpath(path, "file.xlsx"), input) + output = load(joinpath(path, "file.xlsx"), "Sheet1") |> DataFrame + @test input == output + end + + # Test for saving DataFrame to XLSX with sheetname keyword + input = (Day = ["Nov. 27","Nov. 28","Nov. 29"], Highest = [78,79,75]) |> DataFrame + mktempdir() do path + file = save(joinpath(path, "file.xlsx"), input, sheetname="SheetName") + output = load(joinpath(path, "file.xlsx"), "SheetName") |> DataFrame + end + + df, names = create_columns_from_iterabletable(load(filename, "Sheet1", colnames=good_colnames)) + @test names == good_colnames + @test length(df[1]) == 4 + @test length(df) == 13 + @test df[1] == [1., 1.5, 2., 2.5] + @test df[2] == ["A", "BB", "CCC", "DDDD"] + @test df[3] == [true, false, false, true] + @test df[4] == [2, "EEEEE", false, 1.5] + @test df[5] == [9., "III", NA, true] + @test df[6] == [3, NA, 3.5, 4] + @test df[7] == ["FF", NA, "GGG", "HHHH"] + @test df[8] == [NA, true, NA, false] + @test df[9] == [Date(2015, 3, 3), DateTime(2015, 2, 4, 10, 14), DateTime(1988, 4, 9), Dates.Time(15, 2, 0)] + @test df[10] == [Date(1965, 4, 3), DateTime(1950, 8, 9, 18, 40), Dates.Time(19, 0, 0), NA] + @test isa(df[11][1], ExcelReaders.ExcelErrorCell) + @test isa(df[11][2], ExcelReaders.ExcelErrorCell) + @test isa(df[11][3], ExcelReaders.ExcelErrorCell) + @test isa(df[11][4], ExcelReaders.ExcelErrorCell) + @test isa(df[12][1][], ExcelReaders.ExcelErrorCell) + @test isa(df[12][2][], ExcelReaders.ExcelErrorCell) + @test isa(df[12][3][], ExcelReaders.ExcelErrorCell) + @test DataValues.isna(df[12][4]) + @test df[13] == [NA, 3.4, "HKEJW", NA] + + # Too few colnames + @test_throws ErrorException create_columns_from_iterabletable(load(filename, "Sheet1!C4:O7", header=true, colnames=[:c1, :c2, :c3, :c4])) + + # Test for constructing DataFrame with empty header cell + data, names = create_columns_from_iterabletable(load(filename, "Sheet2!C5:E7")) + @test names == [:Col1, :x1, :Col3] + end +end