Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Updates CI and updates to work with current DataFrames #7

Merged
merged 1 commit into from Sep 24, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
49 changes: 19 additions & 30 deletions .appveyor.yml
@@ -1,42 +1,31 @@
environment:
matrix:
- JULIA_URL: "https://julialang-s3.julialang.org/bin/winnt/x86/0.6/julia-0.6-latest-win32.exe"
- JULIA_URL: "https://julialang-s3.julialang.org/bin/winnt/x64/0.6/julia-0.6-latest-win64.exe"
- JULIA_URL: "https://julialangnightlies-s3.julialang.org/bin/winnt/x86/julia-latest-win32.exe"
- JULIA_URL: "https://julialangnightlies-s3.julialang.org/bin/winnt/x64/julia-latest-win64.exe"
- julia_version: 0.6
- julia_version: 0.7
- julia_version: 1
- julia_version: nightly

platform:
- x86 # 32-bit
- x64 # 64-bit

matrix:
allow_failures:
- JULIA_URL: "https://julialangnightlies-s3.julialang.org/bin/winnt/x86/julia-latest-win32.exe"
- JULIA_URL: "https://julialangnightlies-s3.julialang.org/bin/winnt/x64/julia-latest-win64.exe"

branches:
only:
- master
- /release-.*/

notifications:
- provider: Email
on_build_success: false
on_build_failure: false
on_build_status_changed: false
- julia_version: nightly

install:
- ps: "[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12"
# Download most recent Julia Windows binary
- ps: (new-object net.webclient).DownloadFile(
$env:JULIA_URL,
"C:\projects\julia-binary.exe")
# Run installer silently, output to C:\projects\julia
- C:\projects\julia-binary.exe /S /D=C:\projects\julia
- ps: iex ((new-object net.webclient).DownloadString("https://raw.githubusercontent.com/JuliaCI/Appveyor.jl/version-1/bin/install.ps1"))

build_script:
# Need to convert from shallow to complete for Pkg.clone to work
- IF EXIST .git\shallow (git fetch --unshallow)
- C:\projects\julia\bin\julia -e "versioninfo(); Pkg.clone(pwd(), \"KeyedFrames\"); Pkg.build(\"KeyedFrames\")"
- echo "%JL_BUILD_SCRIPT%"
- C:\julia\bin\julia -e "%JL_BUILD_SCRIPT%"

test_script:
- C:\projects\julia\bin\julia -e "Pkg.test(\"KeyedFrames\"; coverage=true)"
- echo "%JL_TEST_SCRIPT%"
- C:\julia\bin\julia -e "%JL_TEST_SCRIPT%"

after_test:
- C:\projects\julia\bin\julia -e "cd(Pkg.dir(\"KeyedFrames\")); Pkg.add(\"Coverage\"); using Coverage; Codecov.submit(process_folder())"
# # Uncomment to support code coverage upload. Should only be enabled for packages
# # which would have coverage gaps without running on Windows
# on_success:
# - echo "%JL_CODECOV_SCRIPT%"
# - C:\julia\bin\julia -e "%JL_CODECOV_SCRIPT%"
18 changes: 13 additions & 5 deletions .travis.yml
Expand Up @@ -5,16 +5,24 @@ os:
- osx
julia:
- 0.6
- 0.7
- 1.0
- nightly
matrix:
allow_failures:
- julia: nightly
fast_finish: true
notifications:
email: false
script:
- if [[ -a .git/shallow ]]; then git fetch --unshallow; fi
- julia -e 'Pkg.clone(pwd()); Pkg.build("KeyedFrames"); Pkg.test("KeyedFrames"; coverage=true)'
# uncomment the following lines to override the default test script
# script:
# - if [[ -a .git/shallow ]]; then git fetch --unshallow; fi
# - julia -e 'Pkg.clone(pwd()); Pkg.build("KeyedFrames"); Pkg.test("KeyedFrames"; coverage=true)'
after_success:
- julia -e 'cd(Pkg.dir("KeyedFrames")); Pkg.add("Coverage"); using Coverage; Codecov.submit(process_folder())'
- julia -e 'Pkg.add("Documenter"); cd(Pkg.dir("KeyedFrames")); include(joinpath("docs", "make.jl"))'
# push coverage results to Codecov

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Simon Byrne added a nifty thing so that coverage submission can be simplified to

codecov: true

which submits coverage in a cross-version manner (as you've done manually here) after success. Something to try out the next time we update this stuff in a public package.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dang

- |
julia -e '
VERSION >= v"0.7.0-DEV.3656" && using Pkg
VERSION >= v"0.7.0-DEV.5183" || cd(Pkg.dir("KeyedFrames"))
Pkg.add("KeyedFrames"); using Coverage
Codecov.submit(process_folder())'
1 change: 1 addition & 0 deletions REQUIRE
@@ -1,2 +1,3 @@
julia 0.6
DataFrames 0.11.6
Compat 0.60
92 changes: 47 additions & 45 deletions src/KeyedFrames.jl
@@ -1,6 +1,6 @@
__precompile__()
module KeyedFrames

using Compat: findfirst
using DataFrames
import DataFrames: SubDataFrame, nrow, ncol, index, deleterows!, delete!, rename!, rename,
unique!, nonunique, head, tail
Expand Down Expand Up @@ -58,45 +58,47 @@ by virtue of having the columns listed in a different order in their `key`s.
"""
KeyedFrame

DataFrame(kf::KeyedFrame) = frame(kf)
Base.copy(kf::KeyedFrame) = KeyedFrame(copy(DataFrame(kf)), copy(keys(kf)))
Base.deepcopy(kf::KeyedFrame) = KeyedFrame(deepcopy(DataFrame(kf)), deepcopy(keys(kf)))

Base.convert(::Type{DataFrame}, kf::KeyedFrame) = kf.frame
Base.convert(::Type{DataFrame}, kf::KeyedFrame) = frame(kf)

SubDataFrame(kf::KeyedFrame, args...) = SubDataFrame(kf.frame, args...)
SubDataFrame(kf::KeyedFrame, args...) = SubDataFrame(frame(kf), args...)

##### EQUALITY #####

Base.:(==)(a::KeyedFrame, b::KeyedFrame) = a.frame == b.frame && sort(a.key) == sort(b.key)
Base.:(==)(a::KeyedFrame, b::KeyedFrame) = frame(a) == frame(b) && sort(keys(a)) == sort(keys(b))

Base.isequal(a::KeyedFrame, b::KeyedFrame) = isequal(a.frame,b.frame)&&isequal(a.key,b.key)
Base.isequal(a::KeyedFrame, b::KeyedFrame) = isequal(frame(a), frame(b))&&isequal(keys(a), keys(b))
Base.isequal(a::KeyedFrame, b::AbstractDataFrame) = false
Base.isequal(a::AbstractDataFrame, b::KeyedFrame) = false

Base.hash(kf::KeyedFrame, h::UInt) = hash(kf.key, hash(kf.frame, h))
Base.hash(kf::KeyedFrame, h::UInt) = hash(keys(kf), hash(frame(kf), h))

##### SIZE #####

nrow(kf::KeyedFrame) = nrow(kf.frame)
ncol(kf::KeyedFrame) = ncol(kf.frame)
nrow(kf::KeyedFrame) = nrow(frame(kf))
ncol(kf::KeyedFrame) = ncol(frame(kf))

##### ACCESSORS #####

index(kf::KeyedFrame) = index(kf.frame)
Base.names(kf::KeyedFrame) = names(kf.frame)
index(kf::KeyedFrame) = index(frame(kf))
Base.names(kf::KeyedFrame) = names(frame(kf))

##### INDEXING #####

const ColumnIndex = Union{Real, Symbol}

Base.keys(kf::KeyedFrame) = kf.key
Base.setindex!(kf::KeyedFrame, value, ind...) = setindex!(kf.frame, value, ind...)
frame(kf::KeyedFrame) = getfield(kf, :frame)
Base.keys(kf::KeyedFrame) = getfield(kf, :key)
Base.setindex!(kf::KeyedFrame, value, ind...) = setindex!(frame(kf), value, ind...)

# I don't want to have to write the same function body several times, so...
function _kf_getindex(kf::KeyedFrame, index...)
# If indexing by column, some keys might be removed.
df = getindex(kf.frame, index...)
return KeyedFrame(df, intersect(names(df), kf.key))
df = getindex(frame(kf), index...)
return KeyedFrame(df, intersect(names(df), keys(kf)))
end

# Returns a KeyedFrame
Expand All @@ -107,19 +109,19 @@ Base.getindex(kf::KeyedFrame, ::Colon, ::Colon) = copy(kf)
Base.getindex(kf::KeyedFrame, col::AbstractVector) = _kf_getindex(kf, col)

# Returns a column
Base.getindex(kf::KeyedFrame, col::ColumnIndex) = kf.frame[col]
Base.getindex(kf::KeyedFrame, col::ColumnIndex) = frame(kf)[col]

# Returns a KeyedFrame or a column (depending on the type of col)
Base.getindex(kf::KeyedFrame, ::Colon, col) = kf[col]

# Returns a scalar
Base.getindex(kf::KeyedFrame, row::Real, col::ColumnIndex) = kf.frame[row, col]
Base.getindex(kf::KeyedFrame, row::Real, col::ColumnIndex) = frame(kf)[row, col]

# Returns a KeyedFrame
Base.getindex(kf::KeyedFrame, row::Real, col::AbstractVector) = _kf_getindex(kf, row, col)

# Returns a column
Base.getindex(kf::KeyedFrame, row::AbstractVector, col::ColumnIndex) = kf.frame[row, col]
Base.getindex(kf::KeyedFrame, row::AbstractVector, col::ColumnIndex) = frame(kf)[row, col]

# Returns a KeyedFrame
function Base.getindex(kf::KeyedFrame, row::AbstractVector, col::AbstractVector)
Expand All @@ -137,43 +139,43 @@ Base.getindex(kf::KeyedFrame, row::Real, col::Colon) = kf[[row], col]
##### SORTING #####

function Base.sort(kf::KeyedFrame, cols=nothing; kwargs...)
return KeyedFrame(sort(kf.frame, cols === nothing ? kf.key : cols; kwargs...), kf.key)
return KeyedFrame(sort(frame(kf), cols === nothing ? keys(kf) : cols; kwargs...), keys(kf))
end

function Base.sort!(kf::KeyedFrame, cols=nothing; kwargs...)
sort!(kf.frame, cols === nothing ? kf.key : cols; kwargs...)
sort!(frame(kf), cols === nothing ? keys(kf) : cols; kwargs...)
return kf
end

function Base.issorted(kf::KeyedFrame, cols=nothing; kwargs...)
return issorted(kf.frame, cols === nothing ? kf.key : cols; kwargs...)
return issorted(frame(kf), cols === nothing ? keys(kf) : cols; kwargs...)
end

##### PUSH/APPEND/DELETE #####

Base.push!(kf::KeyedFrame, data) = push!(kf.frame, data)
Base.append!(kf::KeyedFrame, data) = append!(kf.frame, data)
Base.push!(kf::KeyedFrame, data) = push!(frame(kf), data)
Base.append!(kf::KeyedFrame, data) = append!(frame(kf), data)

deleterows!(kf::KeyedFrame, ind) = deleterows!(kf.frame, ind)
deleterows!(kf::KeyedFrame, ind) = deleterows!(frame(kf), ind)

delete!(kf::KeyedFrame, ind::Union{Integer, Symbol}) = delete!(kf, [ind])
delete!(kf::KeyedFrame, ind::Vector{<:Integer}) = delete!(kf, names(kf)[ind])

function delete!(kf::KeyedFrame, ind::Vector{<:Symbol})
delete!(kf.frame, ind)
filter!(x -> !in(x, ind), kf.key)
delete!(frame(kf), ind)
filter!(x -> !in(x, ind), keys(kf))
return kf
end

##### RENAME #####

function rename!(kf::KeyedFrame, nms)
rename!(kf.frame, nms)
rename!(frame(kf), nms)

for (from, to) in nms
i = findfirst(kf.key, from)
if i != 0
kf.key[i] = to
i = findfirst(isequal(from), keys(kf))
if i !== nothing
keys(kf)[i] = to
end
end

Expand All @@ -189,67 +191,67 @@ rename(f::Function, kf::KeyedFrame) = rename!(f, copy(kf))
##### UNIQUE #####

function Base.unique(kf::KeyedFrame, cols=nothing)
return KeyedFrame(unique(kf.frame, cols === nothing ? kf.key : cols), kf.key)
return KeyedFrame(unique(frame(kf), cols === nothing ? keys(kf) : cols), keys(kf))
end

function unique!(kf::KeyedFrame, cols=nothing)
unique!(kf.frame, cols === nothing ? kf.key : cols)
unique!(frame(kf), cols === nothing ? keys(kf) : cols)
return kf
end

nonunique(kf::KeyedFrame) = nonunique(kf.frame, kf.key)
nonunique(kf::KeyedFrame) = nonunique(frame(kf), keys(kf))

##### JOIN #####

# Returns a KeyedFrame
function Base.join(a::KeyedFrame, b::KeyedFrame; on=nothing, kind=:inner, kwargs...)
df = join(
a.frame,
b.frame;
on=on === nothing ? intersect(a.key, b.key) : on,
frame(a),
frame(b);
on=on === nothing ? intersect(keys(a), keys(b)) : on,
kind=kind,
kwargs...,
)

if kind in (:semi, :anti)
key = intersect(a.key, names(df))
key = intersect(keys(a), names(df))
else
# A join can sometimes rename columns, meaning some of the key columns "disappear"
key = intersect(union(a.key, b.key), names(df))
key = intersect(union(keys(a), keys(b)), names(df))
end

return KeyedFrame(df, key)
end

# Returns a KeyedFrame
function Base.join(a::KeyedFrame, b::AbstractDataFrame; on=nothing, kwargs...)
df = join(a.frame, b; on=on === nothing ? intersect(a.key, names(b)) : on, kwargs...)
df = join(frame(a), b; on=on === nothing ? intersect(keys(a), names(b)) : on, kwargs...)

# A join can sometimes rename columns, meaning some of the key columns "disappear"
return KeyedFrame(df, intersect(a.key, names(df)))
return KeyedFrame(df, intersect(keys(a), names(df)))
end

# Does NOT return a KeyedFrame
function Base.join(a::AbstractDataFrame, b::KeyedFrame; on=nothing, kwargs...)
return join(a, b.frame; on=on === nothing ? intersect(b.key, names(a)) : on, kwargs...)
return join(a, frame(b); on=on === nothing ? intersect(keys(b), names(a)) : on, kwargs...)
end

##### HEAD/TAIL #####

head(kf::KeyedFrame, r::Int) = KeyedFrame(head(kf.frame, r), kf.key)
tail(kf::KeyedFrame, r::Int) = KeyedFrame(tail(kf.frame, r), kf.key)
head(kf::KeyedFrame, r::Int) = KeyedFrame(head(frame(kf), r), keys(kf))
tail(kf::KeyedFrame, r::Int) = KeyedFrame(tail(frame(kf), r), keys(kf))

##### PERMUTE #####

function Base.permute!(df::DataFrame, index::AbstractVector)
permute!(DataFrames.columns(df), index)
df.colindex = DataFrames.Index(
setfield!(df, :colindex, DataFrames.Index(
Dict(names(df)[j] => i for (i, j) in enumerate(index)),
[names(df)[j] for j in index]
)
))
end

Base.permute!(kf::KeyedFrame, index::AbstractVector) = permute!(kf.frame, index)
Base.permute!(kf::KeyedFrame, index::AbstractVector) = permute!(frame(kf), index)

export KeyedFrame

Expand Down