Skip to content

Commit

Permalink
Add nrow and ncol fallback implementations (#343)
Browse files Browse the repository at this point in the history
  • Loading branch information
bkamins authored Sep 19, 2023
1 parent 1b5bbe2 commit a695836
Show file tree
Hide file tree
Showing 7 changed files with 97 additions and 17 deletions.
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "Tables"
uuid = "bd369af6-aec1-5ad0-b16a-f7cc5008161c"
authors = ["quinnj <[email protected]>"]
version = "1.10.1"
version = "1.11.0"

[deps]
DataAPI = "9a962f9c-6df0-11e9-0e5d-c546b8b5ee8a"
Expand Down
28 changes: 15 additions & 13 deletions docs/src/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -229,19 +229,21 @@ make my custom type valid for Tables.jl consumers?
For a type `MyTable`, the interface to becoming a proper table is straightforward:
| Required Methods | Default Definition | Brief Description |
|----------------------------------------|------------------------------|---------------------------------------------------------------------------------------------------------------------------------|
| `Tables.istable(::Type{MyTable})` | | Declare that your table type implements the interface |
| **One of:** | | |
| `Tables.rowaccess(::Type{MyTable})` | | Declare that your table type defines a `Tables.rows(::MyTable)` method |
| `Tables.rows(x::MyTable)` | | Return an `Tables.AbstractRow`-compatible iterator from your table |
| **Or:** | | |
| `Tables.columnaccess(::Type{MyTable})` | | Declare that your table type defines a `Tables.columns(::MyTable)` method |
| `Tables.columns(x::MyTable)` | | Return an `Tables.AbstractColumns`-compatible object from your table |
| **Optional methods** | | |
| `Tables.schema(x::MyTable)` | `Tables.schema(x) = nothing` | Return a [`Tables.Schema`](@ref) object from your `Tables.AbstractRow` iterator or `Tables.AbstractColumns` object; or `nothing` for unknown schema |
| `Tables.materializer(::Type{MyTable})` | `Tables.columntable` | Declare a "materializer" sink function for your table type that can construct an instance of your type from any Tables.jl input |
| `Tables.subset(x::MyTable, inds; viewhint)` | | Return a row or a sub-table of the original table
| Required Methods | Default Definition | Brief Description |
|----------------------------------------------|------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------|
| `Tables.istable(::Type{MyTable})` | | Declare that your table type implements the interface |
| **One of:** | | |
| `Tables.rowaccess(::Type{MyTable})` | | Declare that your table type defines a `Tables.rows(::MyTable)` method |
| `Tables.rows(x::MyTable)` | | Return an `Tables.AbstractRow`-compatible iterator from your table |
| **Or:** | | |
| `Tables.columnaccess(::Type{MyTable})` | | Declare that your table type defines a `Tables.columns(::MyTable)` method |
| `Tables.columns(x::MyTable)` | | Return an `Tables.AbstractColumns`-compatible object from your table |
| **Optional methods** | | |
| `Tables.schema(x::MyTable)` | `Tables.schema(x) = nothing` | Return a [`Tables.Schema`](@ref) object from your `Tables.AbstractRow` iterator or `Tables.AbstractColumns` object; or `nothing` for unknown schema |
| `Tables.materializer(::Type{MyTable})` | `Tables.columntable` | Declare a "materializer" sink function for your table type that can construct an instance of your type from any Tables.jl input |
| `Tables.subset(x::MyTable, inds; viewhint)` | | Return a row or a sub-table of the original table |
| `DataAPI.nrow(x::MyTable)` | | Return number of rows of table `x` |
| `DataAPI.ncol(x::MyTable)` | | Return number of columns of table `x` |
Based on whether your table type has defined `Tables.rows` or `Tables.columns`, you then ensure that the `Tables.AbstractRow` iterator
or `Tables.AbstractColumns` object satisfies the respective interface.
Expand Down
5 changes: 5 additions & 0 deletions src/dicts.jl
Original file line number Diff line number Diff line change
Expand Up @@ -197,3 +197,8 @@ function dictrowtable(x)
end
return DictRowTable(names, types, out)
end

# implement default nrow and ncol methods for DataAPI.jl

DataAPI.nrow(table::DictRowTable) = length(table)
DataAPI.ncol(table::DictRowTable) = length(getfield(table, :names))
9 changes: 9 additions & 0 deletions src/fallbacks.jl
Original file line number Diff line number Diff line change
Expand Up @@ -275,3 +275,12 @@ columnnames(x::CopiedColumns) = columnnames(source(x))
end
throw(ArgumentError("no default `Tables.columns` implementation for type: $T"))
end

# implement default nrow and ncol methods for DataAPI.jl

# this covers also MatrixTable
DataAPI.nrow(table::AbstractColumns) = rowcount(table)
DataAPI.ncol(table::AbstractColumns) = length(columnnames(table))

DataAPI.nrow(table::AbstractRowTable) = length(table)
DataAPI.ncol(table::AbstractRowTable) = isempty(table) ? 0 : length(columnnames(first(table)))
5 changes: 5 additions & 0 deletions src/matrix.jl
Original file line number Diff line number Diff line change
Expand Up @@ -111,3 +111,8 @@ function matrix(table::MatrixTable; transpose::Bool=false)
return matrix
end
end

# implement default nrow and ncol methods for DataAPI.jl

DataAPI.nrow(table::MatrixRowTable) = length(table)
DataAPI.ncol(table::MatrixRowTable) = size(getfield(table, :matrix), 2) # this is correct even if m is a vector
8 changes: 8 additions & 0 deletions src/namedtuples.jl
Original file line number Diff line number Diff line change
Expand Up @@ -190,3 +190,11 @@ function columntable(itr::T) where {T}
return columntable(schema(cols), cols)
end
columntable(x::ColumnTable) = x

# implement default nrow and ncol methods for DataAPI.jl

DataAPI.nrow(table::ColumnTable) = isempty(table) ? 0 : length(first(table))
DataAPI.ncol(table::ColumnTable) = length(table)

DataAPI.nrow(table::RowTable) = length(table)
DataAPI.ncol(table::RowTable) = isempty(table) ? 0 : length(first(table))
57 changes: 54 additions & 3 deletions test/runtests.jl
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using Test, Tables, OrderedCollections, TableTraits, DataValues, QueryOperators, IteratorInterfaceExtensions, SparseArrays
using Test, Tables, OrderedCollections, TableTraits, DataValues, QueryOperators, IteratorInterfaceExtensions, SparseArrays, DataAPI

@testset "utils.jl" begin

Expand Down Expand Up @@ -957,7 +957,7 @@ end
@test Tables.istable(Vector{Dict{String}})
@test Tables.istable(Vector{Dict{SubString}})
@test Tables.istable(Vector{Dict{AbstractString}})

@test Set(Tables.columnnames(Dict(:a=>1, :b=>2))) == Set([:a, :b])
@test Set(Tables.columnnames(Dict("a"=>1, "b"=>2))) == Set([:a, :b])
@test Set(Tables.columnnames(Dict("a"=>1, SubString("b")=>2))) == Set([:a, :b])
Expand All @@ -976,4 +976,55 @@ end
@test Tables.getcolumn(Dict("a"=>1, SubString("b")=>2), Int, 1, :a) == 1
@test Tables.getcolumn(Dict(SubString("a")=>1, SubString("b")=>2), Int, 1, :a) == 1
end


@testset "test nrow and ncol" begin
# AbstractColumns
@test DataAPI.nrow(Tables.CopiedColumns(NamedTuple())) == 0
@test DataAPI.ncol(Tables.CopiedColumns(NamedTuple())) == 0
@test DataAPI.nrow(Tables.CopiedColumns((a=1:3, b=2:4))) == 3
@test DataAPI.ncol(Tables.CopiedColumns((a=1:3, b=2:4))) == 2

# ColumnTable
@test DataAPI.nrow(NamedTuple()) == 0
@test DataAPI.ncol(NamedTuple()) == 0
@test DataAPI.nrow((a=1:3, b=2:4)) == 3
@test DataAPI.ncol((a=1:3, b=2:4)) == 2

# AbstractRowTable
@test DataAPI.nrow(collect(Tables.rows(Tables.table(ones(0, 0))))) == 0
@test DataAPI.ncol(collect(Tables.rows(Tables.table(ones(0, 0))))) == 0
@test DataAPI.nrow(collect(Tables.rows(Tables.table(ones(2, 3))))) == 2
@test DataAPI.ncol(collect(Tables.rows(Tables.table(ones(2, 3))))) == 3

# RowTable
@test DataAPI.nrow(NamedTuple[]) == 0
@test DataAPI.ncol(NamedTuple[]) == 0
@test DataAPI.nrow([(a=1,b=2), (a=3, b=4), (a=5, b=6)]) == 3
@test DataAPI.ncol([(a=1, b=2), (a=3, b=4), (a=5, b=6)]) == 2

# MatrixTable
@test DataAPI.nrow(Tables.table(ones(0, 0))) == 0
@test DataAPI.ncol(Tables.table(ones(0, 0))) == 0
@test DataAPI.nrow(Tables.table(ones(2, 3))) == 2
@test DataAPI.ncol(Tables.table(ones(2, 3))) == 3
@test DataAPI.nrow(Tables.table([])) == 0
@test DataAPI.ncol(Tables.table([])) == 1
@test DataAPI.nrow(Tables.table([1, 2])) == 2
@test DataAPI.ncol(Tables.table([1, 2])) == 1

# MatrixRowTable
@test DataAPI.nrow(Tables.rows(Tables.table(ones(0, 0)))) == 0
@test DataAPI.ncol(Tables.rows(Tables.table(ones(0, 0)))) == 0
@test DataAPI.nrow(Tables.rows(Tables.table(ones(2, 3)))) == 2
@test DataAPI.ncol(Tables.rows(Tables.table(ones(2, 3)))) == 3
@test DataAPI.nrow(Tables.rows(Tables.table([]))) == 0
@test DataAPI.ncol(Tables.rows(Tables.table([]))) == 1
@test DataAPI.nrow(Tables.rows(Tables.table([1, 2]))) == 2
@test DataAPI.ncol(Tables.rows(Tables.table([1, 2]))) == 1

# DictRowTable
@test DataAPI.nrow(Tables.dictrowtable(NamedTuple[])) == 0
@test DataAPI.ncol(Tables.dictrowtable(NamedTuple[])) == 0
@test DataAPI.nrow(Tables.dictrowtable([(a=1, b=2), (a=3, b=4), (a=5, b=6)])) == 3
@test DataAPI.ncol(Tables.dictrowtable([(a=1, b=2), (a=3, b=4), (a=5, b=6)])) == 2
end

3 comments on commit a695836

@bkamins
Copy link
Member Author

Choose a reason for hiding this comment

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

@JuliaRegistrator
Copy link

Choose a reason for hiding this comment

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

Registration pull request created: JuliaRegistries/General/91716

After the above pull request is merged, it is recommended that a tag is created on this repository for the registered package version.

This will be done automatically if the Julia TagBot GitHub Action is installed, or can be done manually through the github interface, or via:

git tag -a v1.11.0 -m "<description of version>" a69583674e697a3fc329d2ec405d8ffdf29d6c00
git push origin v1.11.0

@bkamins
Copy link
Member Author

Choose a reason for hiding this comment

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

CC @quinnj @nalimilan
@ronisbr - now you have a proper support for nrow and ncol for PrettyTables.jl.

Please sign in to comment.