diff --git a/Project.toml b/Project.toml index 81d667c4db..f1ecc2e4fe 100644 --- a/Project.toml +++ b/Project.toml @@ -34,7 +34,7 @@ julia = "1" Missings = ">= 0.2.3" CategoricalArrays = ">= 0.5.4" StatsBase = ">= 0.11.0" -Compat = ">= 0.59.0" +Compat = "2.0.0" Tables = ">= 0.2.3" IteratorInterfaceExtensions = "0.1.1, 1" TableTraits = "0.4, 1" diff --git a/src/DataFrames.jl b/src/DataFrames.jl index 7366d974f1..8dbd2034a8 100644 --- a/src/DataFrames.jl +++ b/src/DataFrames.jl @@ -54,7 +54,6 @@ export AbstractDataFrame, rename, select, select!, - showcols, stack, stackdf, unique!, @@ -67,6 +66,10 @@ else export eachcol, eachrow end +if VERSION < v"1.2" + export hasproperty +end + ############################################################################## ## ## Load files diff --git a/src/abstractdataframe/abstractdataframe.jl b/src/abstractdataframe/abstractdataframe.jl index 1ecb7f0569..8d2a611276 100644 --- a/src/abstractdataframe/abstractdataframe.jl +++ b/src/abstractdataframe/abstractdataframe.jl @@ -86,6 +86,8 @@ abstract type AbstractDataFrame end Base.names(df::AbstractDataFrame) = names(index(df)) _names(df::AbstractDataFrame) = _names(index(df)) +Compat.hasproperty(df::AbstractDataFrame, s::Symbol) = haskey(index(df), s) + """ Set column names @@ -1137,7 +1139,7 @@ function _vcat(dfs::AbstractVector{<:AbstractDataFrame}; all_cols = Vector{AbstractVector}(undef, length(header)) for (i, name) in enumerate(header) newcols = map(dfs) do df - if haskey(index(df), name) + if hasproperty(df, name) return df[name] else Iterators.repeated(missing, nrow(df)) diff --git a/src/abstractdataframe/join.jl b/src/abstractdataframe/join.jl index f73ecc1f6e..aebb6691ef 100644 --- a/src/abstractdataframe/join.jl +++ b/src/abstractdataframe/join.jl @@ -299,8 +299,8 @@ function Base.join(df1::AbstractDataFrame, if indicator !== nothing indicator_cols = ["_left", "_right"] for i in 1:2 - while (haskey(index(df1), Symbol(indicator_cols[i])) || - haskey(index(df2), Symbol(indicator_cols[i])) || + while (hasproperty(df1, Symbol(indicator_cols[i])) || + hasproperty(df2, Symbol(indicator_cols[i])) || Symbol(indicator_cols[i]) == indicator) indicator_cols[i] *= 'X' end @@ -400,7 +400,7 @@ function Base.join(df1::AbstractDataFrame, indicatorcol = CategoricalArray{String,1}(refs, CategoricalPool{String,UInt8}(["left_only", "right_only", "both"])) unique_indicator = indicator try_idx = 0 - while haskey(index(joined), unique_indicator) + while hasproperty(joined, unique_indicator) try_idx += 1 unique_indicator = Symbol(string(indicator, "_", try_idx)) end diff --git a/src/dataframe/dataframe.jl b/src/dataframe/dataframe.jl index c8d03d4e4f..402c0575b0 100644 --- a/src/dataframe/dataframe.jl +++ b/src/dataframe/dataframe.jl @@ -395,11 +395,11 @@ end function nextcolname(df::DataFrame) col = Symbol(string("x", ncol(df) + 1)) - haskey(index(df), col) || return col + hasproperty(df, col) || return col i = 1 while true col = Symbol(string("x", ncol(df) + 1, "_", i)) - haskey(index(df), col) || return col + hasproperty(df, col) || return col i += 1 end end @@ -417,7 +417,7 @@ function insert_single_column!(df::DataFrame, j = index(df)[col_ind] _columns(df)[j] = dv else - if typeof(col_ind) <: Symbol + if col_ind isa Symbol push!(index(df), col_ind) push!(_columns(df), dv) else @@ -778,14 +778,14 @@ function insertcols!(df::DataFrame, col_ind::Int, name_col::Pair{Symbol, <:Abstr 0 < col_ind <= ncol(df) + 1 || throw(BoundsError()) size(df, 1) == length(item) || size(df, 2) == 0 || error("number of rows does not match") - if haskey(index(df), name) + if hasproperty(df, name) if makeunique k = 1 while true # we only make sure that new column name is unique # if df originally had duplicates in names we do not fix it nn = Symbol("$(name)_$k") - if !haskey(index(df), nn) + if !hasproperty(df, nn) name = nn break end diff --git a/src/dataframerow/dataframerow.jl b/src/dataframerow/dataframerow.jl index f408425990..8b4549555a 100644 --- a/src/dataframerow/dataframerow.jl +++ b/src/dataframerow/dataframerow.jl @@ -100,7 +100,7 @@ Base.haskey(r::DataFrameRow, key::Bool) = throw(ArgumentError("invalid key: $key of type Bool")) Base.haskey(r::DataFrameRow, key::Integer) = 1 ≤ key ≤ size(r, 1) function Base.haskey(r::DataFrameRow, key::Symbol) - haskey(parent(r), key) || return false + hasproperty(parent(r), key) || return false index(r) isa Index && return true # here index(r) is a SubIndex pos = index(parent(r))[key] diff --git a/src/deprecated.jl b/src/deprecated.jl index b25cc25bef..cd346aef50 100644 --- a/src/deprecated.jl +++ b/src/deprecated.jl @@ -1399,7 +1399,9 @@ import Base: get @deprecate get(df::AbstractDataFrame, key::Any, default::Any) key in names(df) ? df[key] : default import Base: haskey -@deprecate haskey(df::AbstractDataFrame, key::Any) key in names(df) +@deprecate haskey(df::AbstractDataFrame, key::Symbol) hasproperty(df, key) +@deprecate haskey(df::AbstractDataFrame, key::Integer) key in 1:ncol(df) +@deprecate haskey(df::AbstractDataFrame, key::Any) key in 1:ncol(df) || key in names(df) import Base: empty! -@deprecate empty!(df::DataFrame) deletecols!(df, 1:ncol(df)) \ No newline at end of file +@deprecate empty!(df::DataFrame) deletecols!(df, 1:ncol(df)) diff --git a/src/other/broadcasting.jl b/src/other/broadcasting.jl index 920924cebf..f9bff03f3c 100644 --- a/src/other/broadcasting.jl +++ b/src/other/broadcasting.jl @@ -13,7 +13,7 @@ function Base.maybeview(df::AbstractDataFrame, idxs) throw(ArgumentError("Broadcasting into a data frame with no columns is not allowed")) end if idxs isa Symbol - if !haskey(index(df), idxs) + if !hasproperty(df, idxs) if !(df isa DataFrame) # this will throw an appropriate error message df[idxs] diff --git a/test/dataframe.jl b/test/dataframe.jl index 2107279f1d..f331bda189 100644 --- a/test/dataframe.jl +++ b/test/dataframe.jl @@ -65,6 +65,15 @@ end @test size(similar(df, 2)) == size(missingdf) end +@testset "hasproperty" begin + df = DataFrame(a=[1, 2]) + @test hasproperty(df, :a) + @test !hasproperty(df, :c) + @test_throws MethodError hasproperty(df, 1) + @test_throws MethodError hasproperty(df, 1.5) + @test_throws MethodError hasproperty(df, true) +end + @testset "insertcols!" begin df = DataFrame(a=Union{Int, Missing}[1, 2], b=Union{Float64, Missing}[3.0, 4.0]) @test_throws BoundsError insertcols!(df, 5, :newcol => ["a", "b"], ) diff --git a/test/deprecated.jl b/test/deprecated.jl index ad7f8c28ef..69d493710d 100644 --- a/test/deprecated.jl +++ b/test/deprecated.jl @@ -215,4 +215,15 @@ end @test isempty(DataFrame(a=[], b=[])) end +@testset "haskey" begin + df = DataFrame(x=1:3) + @test haskey(df, 1) + @test !haskey(DataFrame(), 1) + @test !haskey(df, 2) + @test !haskey(df, 0) + @test haskey(df, :x) + @test !haskey(df, :a) + @test !haskey(df, "a") +end + end # module \ No newline at end of file