From ff31aa7c9b0454a19f1522a6df634e1a03ce1615 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bogumi=C5=82=20Kami=C5=84ski?= Date: Sun, 8 May 2022 08:16:26 +0200 Subject: [PATCH 01/44] add `getmetadata` --- src/DataAPI.jl | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/DataAPI.jl b/src/DataAPI.jl index 567b8e8..d9d0d21 100644 --- a/src/DataAPI.jl +++ b/src/DataAPI.jl @@ -287,4 +287,11 @@ using a `sink` function to materialize the table. """ function allcombinations end +""" + getmetadata(x, ...) + +Return metadata associated with object `x` or `nothing` if it doest not support metadata. +""" +getmetadata(::Any) = nothing + end # module From 96b1e396152e0603f8085cda03ec10ff002e8978 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bogumi=C5=82=20Kami=C5=84ski?= Date: Sun, 8 May 2022 08:19:21 +0200 Subject: [PATCH 02/44] Update Project.toml --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index 729668d..5106aa0 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "DataAPI" uuid = "9a962f9c-6df0-11e9-0e5d-c546b8b5ee8a" authors = ["quinnj "] -version = "1.10.0" +version = "1.11.0" [compat] julia = "1" From f7cb3050e67087b0d3723bc53b38674c5fa7d3ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bogumi=C5=82=20Kami=C5=84ski?= Date: Sun, 22 May 2022 13:04:20 +0200 Subject: [PATCH 03/44] Apply suggestions from code review Co-authored-by: Milan Bouchet-Valat --- src/DataAPI.jl | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/DataAPI.jl b/src/DataAPI.jl index d9d0d21..184bc68 100644 --- a/src/DataAPI.jl +++ b/src/DataAPI.jl @@ -288,10 +288,11 @@ using a `sink` function to materialize the table. function allcombinations end """ - getmetadata(x, ...) + metadata(x) -Return metadata associated with object `x` or `nothing` if it doest not support metadata. +Return metadata associated with object `x` as an `AbstractDict{String}` object +(or an object implementing the same interface), or `nothing` if `x` does not support metadata. """ -getmetadata(::Any) = nothing +metadata(::Any) = nothing end # module From 77e3604ec2f18c1e266ef60b3e8a53302d8c40fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bogumi=C5=82=20Kami=C5=84ski?= Date: Sun, 22 May 2022 13:07:21 +0200 Subject: [PATCH 04/44] Update runtests.jl --- test/runtests.jl | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test/runtests.jl b/test/runtests.jl index 9782ac2..e533f8a 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -9,6 +9,7 @@ end Base.size(x::TestArray) = size(x.x) Base.getindex(x::TestArray, i) = x.x[i] DataAPI.levels(x::TestArray) = reverse(DataAPI.levels(x.x)) +DataAPI.metadata(x::TestArray) = Dict("length" => length(x)) @testset "DataAPI" begin @@ -173,4 +174,9 @@ end @test DataAPI.unwrap(missing) === missing end +@testset "metadata" begin + @test isnothing(DataAPI.metadata(1)) + @test DataAPI.metadata(TestArray([1, 2])) === Dict("length => 2) +end + end # @testset "DataAPI" From 7d53c4b7cbd78703580b1a21cbb82ee6e2c0a9a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bogumi=C5=82=20Kami=C5=84ski?= Date: Sun, 22 May 2022 13:10:08 +0200 Subject: [PATCH 05/44] Update src/DataAPI.jl --- src/DataAPI.jl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/DataAPI.jl b/src/DataAPI.jl index 184bc68..8f0d31f 100644 --- a/src/DataAPI.jl +++ b/src/DataAPI.jl @@ -292,6 +292,8 @@ function allcombinations end Return metadata associated with object `x` as an `AbstractDict{String}` object (or an object implementing the same interface), or `nothing` if `x` does not support metadata. + +Note that some systems, like Arrow.jl, might assume that metadata values are also `String`. """ metadata(::Any) = nothing From c28d7c5a9471b4fe54505403a2eb7bf185d0e43e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bogumi=C5=82=20Kami=C5=84ski?= Date: Sun, 22 May 2022 14:02:57 +0200 Subject: [PATCH 06/44] Update test/runtests.jl --- test/runtests.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/runtests.jl b/test/runtests.jl index e533f8a..61d898e 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -176,7 +176,7 @@ end @testset "metadata" begin @test isnothing(DataAPI.metadata(1)) - @test DataAPI.metadata(TestArray([1, 2])) === Dict("length => 2) + @test DataAPI.metadata(TestArray([1, 2])) === Dict("length" => 2) end end # @testset "DataAPI" From 37ef469c2889323525eb3be6e0e2662869d53a40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bogumi=C5=82=20Kami=C5=84ski?= Date: Sun, 22 May 2022 14:05:15 +0200 Subject: [PATCH 07/44] Update test/runtests.jl --- test/runtests.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/runtests.jl b/test/runtests.jl index 61d898e..78c277d 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -176,7 +176,7 @@ end @testset "metadata" begin @test isnothing(DataAPI.metadata(1)) - @test DataAPI.metadata(TestArray([1, 2])) === Dict("length" => 2) + @test DataAPI.metadata(TestArray([1, 2])) == Dict("length" => 2) end end # @testset "DataAPI" From 4617f602a63cf13a1fa408f193a477e2742dc5bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bogumi=C5=82=20Kami=C5=84ski?= Date: Sun, 22 May 2022 14:07:26 +0200 Subject: [PATCH 08/44] Update test/runtests.jl --- test/runtests.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/runtests.jl b/test/runtests.jl index 78c277d..373775c 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -175,7 +175,7 @@ end end @testset "metadata" begin - @test isnothing(DataAPI.metadata(1)) + @test DataAPI.metadata(1) === nothing @test DataAPI.metadata(TestArray([1, 2])) == Dict("length" => 2) end From 5a493b6b997c94ad2d9e302e707dd5d56d2c1c4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bogumi=C5=82=20Kami=C5=84ski?= Date: Mon, 23 May 2022 11:04:14 +0200 Subject: [PATCH 09/44] update API --- src/DataAPI.jl | 26 +++++++++++++++++++++++--- test/runtests.jl | 9 ++++++++- 2 files changed, 31 insertions(+), 4 deletions(-) diff --git a/src/DataAPI.jl b/src/DataAPI.jl index 8f0d31f..0c09c34 100644 --- a/src/DataAPI.jl +++ b/src/DataAPI.jl @@ -288,13 +288,33 @@ using a `sink` function to materialize the table. function allcombinations end """ - metadata(x) + metadata(x, [column]) Return metadata associated with object `x` as an `AbstractDict{String}` object -(or an object implementing the same interface), or `nothing` if `x` does not support metadata. +(or an object implementing the same interface). + +Optionally for Tables.jl tables a `columns` argument can be passed, in which case +return metadata associated with the indicated column. + +Note that some systems, like Arrow.jl, might assume that metadata values are also `String`. +""" +metadata(::T) where {T} = throw(ArgumentError("Metadata is currently not " * + "supported for values of type $T")) +metadata(::T, ::Any) where {T} = throw(ArgumentError("Column metadata is currently not " * + "supported for values of type $T")) + +""" + hasmetadata(x, [column]) + +Return `true` if `x` has non-empty metadata, and return `false` if metadata is empty. +Return `nothing` if `x` does not support metadata. + +Optionally for Tables.jl tables a `columns` argument can be passed, in which case +return the same information about metadata associated with the indicated column. Note that some systems, like Arrow.jl, might assume that metadata values are also `String`. """ -metadata(::Any) = nothing +hasmetadata(::Any) = nothing +hasmetadata(::Any, ::Any) = nothing end # module diff --git a/test/runtests.jl b/test/runtests.jl index 373775c..32353a2 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -10,6 +10,9 @@ Base.size(x::TestArray) = size(x.x) Base.getindex(x::TestArray, i) = x.x[i] DataAPI.levels(x::TestArray) = reverse(DataAPI.levels(x.x)) DataAPI.metadata(x::TestArray) = Dict("length" => length(x)) +DataAPI.metadata(x::TestArray, col) = Dict("name" => col) +DataAPI.hasmetadata(x::TestArray) = true +DataAPI.hasmetadata(x::TestArray, col) = true @testset "DataAPI" begin @@ -175,8 +178,12 @@ end end @testset "metadata" begin - @test DataAPI.metadata(1) === nothing + @test_throws ArgumentError DataAPI.metadata(1) + @test DataAPI.hasmetadata(1) === nothing @test DataAPI.metadata(TestArray([1, 2])) == Dict("length" => 2) + @test DataAPI.hasmetadata(TestArray([1, 2])) + @test DataAPI.metadata(TestArray([1, 2]), "col") == Dict("name" => "col") + @test DataAPI.hasmetadata(TestArray([1, 2]), "col") == true end end # @testset "DataAPI" From aa15118d3a5c8fe2f5a42ee3ba1415b138627524 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bogumi=C5=82=20Kami=C5=84ski?= Date: Mon, 23 May 2022 11:07:51 +0200 Subject: [PATCH 10/44] improve test coverage --- test/runtests.jl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/runtests.jl b/test/runtests.jl index 32353a2..84a87eb 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -180,6 +180,8 @@ end @testset "metadata" begin @test_throws ArgumentError DataAPI.metadata(1) @test DataAPI.hasmetadata(1) === nothing + @test_throws ArgumentError DataAPI.metadata(1, 1) + @test DataAPI.hasmetadata(1, 1) === nothing @test DataAPI.metadata(TestArray([1, 2])) == Dict("length" => 2) @test DataAPI.hasmetadata(TestArray([1, 2])) @test DataAPI.metadata(TestArray([1, 2]), "col") == Dict("name" => "col") From 992d1e8f6a98e92fa04edd9ae96e45958f7dd6a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bogumi=C5=82=20Kami=C5=84ski?= Date: Mon, 23 May 2022 15:13:17 +0200 Subject: [PATCH 11/44] change column to key --- src/DataAPI.jl | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/DataAPI.jl b/src/DataAPI.jl index 0c09c34..fd52b41 100644 --- a/src/DataAPI.jl +++ b/src/DataAPI.jl @@ -288,29 +288,32 @@ using a `sink` function to materialize the table. function allcombinations end """ - metadata(x, [column]) + metadata(x, [key]) Return metadata associated with object `x` as an `AbstractDict{String}` object (or an object implementing the same interface). -Optionally for Tables.jl tables a `columns` argument can be passed, in which case -return metadata associated with the indicated column. +Optionally `key` argument can be passed, in which case return metadata +associated with the indicated key (this feature can be used, for example, +by Tables.jl table to return metadata attached to columns of a table). -Note that some systems, like Arrow.jl, might assume that metadata values are also `String`. +Note that some systems, like Arrow.jl, might assume that metadata values are +also `String`. """ metadata(::T) where {T} = throw(ArgumentError("Metadata is currently not " * "supported for values of type $T")) -metadata(::T, ::Any) where {T} = throw(ArgumentError("Column metadata is currently not " * +metadata(::T, ::Any) where {T} = throw(ArgumentError("Key metadata is currently not " * "supported for values of type $T")) """ - hasmetadata(x, [column]) + hasmetadata(x, [key]) Return `true` if `x` has non-empty metadata, and return `false` if metadata is empty. Return `nothing` if `x` does not support metadata. -Optionally for Tables.jl tables a `columns` argument can be passed, in which case -return the same information about metadata associated with the indicated column. +Optionally `key` argument can be passed, in which case return information if +metadata is associated with the indicated key (this feature can be used, for example, +by Tables.jl table to query about metadata attached to columns of a table). Note that some systems, like Arrow.jl, might assume that metadata values are also `String`. """ From bbeda8073a0c11216b08837761dfabf3a18f99e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bogumi=C5=82=20Kami=C5=84ski?= Date: Mon, 23 May 2022 23:20:07 +0200 Subject: [PATCH 12/44] Apply suggestions from code review Co-authored-by: Milan Bouchet-Valat --- src/DataAPI.jl | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/DataAPI.jl b/src/DataAPI.jl index fd52b41..64dd197 100644 --- a/src/DataAPI.jl +++ b/src/DataAPI.jl @@ -293,17 +293,17 @@ function allcombinations end Return metadata associated with object `x` as an `AbstractDict{String}` object (or an object implementing the same interface). -Optionally `key` argument can be passed, in which case return metadata +If the optional `key` argument is passed, return metadata associated with the indicated key (this feature can be used, for example, -by Tables.jl table to return metadata attached to columns of a table). +to return metadata attached to a given column in a Tables.jl table). Note that some systems, like Arrow.jl, might assume that metadata values are also `String`. """ -metadata(::T) where {T} = throw(ArgumentError("Metadata is currently not " * - "supported for values of type $T")) -metadata(::T, ::Any) where {T} = throw(ArgumentError("Key metadata is currently not " * - "supported for values of type $T")) +metadata(::T) where {T} = + throw(ArgumentError("Metadata is currently not supported for values of type $T")) +metadata(::T, ::Any) where {T} = + throw(ArgumentError("Key metadata is currently not supported for values of type $T")) """ hasmetadata(x, [key]) @@ -311,9 +311,9 @@ metadata(::T, ::Any) where {T} = throw(ArgumentError("Key metadata is currently Return `true` if `x` has non-empty metadata, and return `false` if metadata is empty. Return `nothing` if `x` does not support metadata. -Optionally `key` argument can be passed, in which case return information if +If the optional `key` argument is passed, return information about whether metadata is associated with the indicated key (this feature can be used, for example, -by Tables.jl table to query about metadata attached to columns of a table). +to query about metadata attached to a given column in a Tables.jl table). Note that some systems, like Arrow.jl, might assume that metadata values are also `String`. """ From 45b433aa819aff9a72ec3ff539853c5d3a2c0fba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bogumi=C5=82=20Kami=C5=84ski?= Date: Mon, 23 May 2022 23:22:14 +0200 Subject: [PATCH 13/44] Update src/DataAPI.jl --- src/DataAPI.jl | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/DataAPI.jl b/src/DataAPI.jl index 64dd197..6b050af 100644 --- a/src/DataAPI.jl +++ b/src/DataAPI.jl @@ -314,8 +314,6 @@ Return `nothing` if `x` does not support metadata. If the optional `key` argument is passed, return information about whether metadata is associated with the indicated key (this feature can be used, for example, to query about metadata attached to a given column in a Tables.jl table). - -Note that some systems, like Arrow.jl, might assume that metadata values are also `String`. """ hasmetadata(::Any) = nothing hasmetadata(::Any, ::Any) = nothing From 6897052102788fb8a49017667048708400f86d12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bogumi=C5=82=20Kami=C5=84ski?= Date: Mon, 23 May 2022 23:22:58 +0200 Subject: [PATCH 14/44] Update src/DataAPI.jl --- src/DataAPI.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/DataAPI.jl b/src/DataAPI.jl index 6b050af..5f3c16e 100644 --- a/src/DataAPI.jl +++ b/src/DataAPI.jl @@ -311,8 +311,8 @@ metadata(::T, ::Any) where {T} = Return `true` if `x` has non-empty metadata, and return `false` if metadata is empty. Return `nothing` if `x` does not support metadata. -If the optional `key` argument is passed, return information about whether -metadata is associated with the indicated key (this feature can be used, for example, +If the optional `key` argument is passed, return information if metadata +is associated with `key` (this feature can be used, for example, to query about metadata attached to a given column in a Tables.jl table). """ hasmetadata(::Any) = nothing From 2ac9c8842a4c8fdffc667c00007323b2d483f477 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bogumi=C5=82=20Kami=C5=84ski?= Date: Mon, 30 May 2022 11:32:41 +0200 Subject: [PATCH 15/44] add colmetadata --- src/DataAPI.jl | 57 ++++++++++++++++++++++++++++++++++++++---------- test/runtests.jl | 24 +++++++++++++++----- 2 files changed, 64 insertions(+), 17 deletions(-) diff --git a/src/DataAPI.jl b/src/DataAPI.jl index 5f3c16e..773698b 100644 --- a/src/DataAPI.jl +++ b/src/DataAPI.jl @@ -288,34 +288,67 @@ using a `sink` function to materialize the table. function allcombinations end """ - metadata(x, [key]) + metadata(x) Return metadata associated with object `x` as an `AbstractDict{String}` object (or an object implementing the same interface). -If the optional `key` argument is passed, return metadata -associated with the indicated key (this feature can be used, for example, -to return metadata attached to a given column in a Tables.jl table). - Note that some systems, like Arrow.jl, might assume that metadata values are also `String`. """ metadata(::T) where {T} = throw(ArgumentError("Metadata is currently not supported for values of type $T")) -metadata(::T, ::Any) where {T} = + +""" + colmetadata(table, column) + +Return metadata associated with column `column` of Tables.jl table `table` as an +`AbstractDict{String}` object (or an object implementing the same interface). + +Note that some systems, like Arrow.jl, might assume that metadata values are +also `String`. +""" +colmetadata(::T, ::Any) where {T} = throw(ArgumentError("Key metadata is currently not supported for values of type $T")) """ - hasmetadata(x, [key]) + colmetadata(table) + +Return metadata associated with columns of Tables.jl table `table` as an +`AbstractDict{<:Any, <:AbstractString{String}}` object (or an object implementing +the same interface). + +The returned dictionary must contain columns `column` for which +`hascolmetadata(table, column)` returns `true` and a value associated to such +key must be `colmetadata(table, column)`. +""" +colmetadata(::T, ::Any) where {T} = + throw(ArgumentError("Key metadata is currently not supported for values of type $T")) + +""" + hasmetadata(x) Return `true` if `x` has non-empty metadata, and return `false` if metadata is empty. Return `nothing` if `x` does not support metadata. - -If the optional `key` argument is passed, return information if metadata -is associated with `key` (this feature can be used, for example, -to query about metadata attached to a given column in a Tables.jl table). """ hasmetadata(::Any) = nothing -hasmetadata(::Any, ::Any) = nothing + +""" + hascolmetadata(table, column) + +Return `true` if column `column` of Tables.jl table `table` has non-empty metadata, +and return `false` if metadata is empty. +Return `nothing` if metadata is not supported. +""" +hascolmetadata(::Any, ::Any) = nothing + +""" + hascolmetadata(table) + +Return `true` if at least one column of of Tables.jl table `table` has non-empty +metadata, and return `false` if metadata is empty for all columns. +Return `nothing` if metadata is not supported. +""" +hascolmetadata(::Any) = nothing end # module diff --git a/test/runtests.jl b/test/runtests.jl index 84a87eb..0df2ebd 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -9,10 +9,15 @@ end Base.size(x::TestArray) = size(x.x) Base.getindex(x::TestArray, i) = x.x[i] DataAPI.levels(x::TestArray) = reverse(DataAPI.levels(x.x)) + DataAPI.metadata(x::TestArray) = Dict("length" => length(x)) -DataAPI.metadata(x::TestArray, col) = Dict("name" => col) +DataAPI.colmetadata(x::TestArray, col) = + col === "x" ? Dict("name" => col) : throw ArgumentError("no metadata") +DataAPI.colmetadata(x::TestArray) = Dict("x" => Dict("name" => col)) + DataAPI.hasmetadata(x::TestArray) = true -DataAPI.hasmetadata(x::TestArray, col) = true +DataAPI.colhasmetadata(x::TestArray) = true +DataAPI.colhasmetadata(x::TestArray, col) = col === "x" @testset "DataAPI" begin @@ -181,11 +186,20 @@ end @test_throws ArgumentError DataAPI.metadata(1) @test DataAPI.hasmetadata(1) === nothing @test_throws ArgumentError DataAPI.metadata(1, 1) - @test DataAPI.hasmetadata(1, 1) === nothing + @test DataAPI.hascolmetadata(1, 1) === nothing + @test_throws ArgumentError DataAPI.colmetadata(1, 1) + @test DataAPI.hascolmetadata(1) === nothing + @test_throws ArgumentError DataAPI.colmetadata(1) + + @test DataAPI.metadata(TestArray([1, 2])) == Dict("length" => 2) @test DataAPI.hasmetadata(TestArray([1, 2])) - @test DataAPI.metadata(TestArray([1, 2]), "col") == Dict("name" => "col") - @test DataAPI.hasmetadata(TestArray([1, 2]), "col") == true + @test DataAPI.colmetadata(TestArray([1, 2]), "x") == Dict("name" => "col") + @test DataAPI.hascolmetadata(TestArray([1, 2]), "x") == true + @test_throws ArgumentError DataAPI.colmetadata(TestArray([1, 2]), "y") + @test DataAPI.hascolmetadata(TestArray([1, 2]), "y") == false + @test DataAPI.colmetadata(TestArray([1, 2])) == Dict("x" => Dict("name" => "col")) + @test DataAPI.hascolmetadata(TestArray([1, 2])) == true end end # @testset "DataAPI" From 43cec64bb9a6ac7e404cc2821a318eb9b6359dc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bogumi=C5=82=20Kami=C5=84ski?= Date: Mon, 30 May 2022 11:36:06 +0200 Subject: [PATCH 16/44] fix typo --- test/runtests.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/runtests.jl b/test/runtests.jl index 0df2ebd..5045a2e 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -12,7 +12,7 @@ DataAPI.levels(x::TestArray) = reverse(DataAPI.levels(x.x)) DataAPI.metadata(x::TestArray) = Dict("length" => length(x)) DataAPI.colmetadata(x::TestArray, col) = - col === "x" ? Dict("name" => col) : throw ArgumentError("no metadata") + col === "x" ? Dict("name" => col) : throw(ArgumentError("no metadata")) DataAPI.colmetadata(x::TestArray) = Dict("x" => Dict("name" => col)) DataAPI.hasmetadata(x::TestArray) = true From 320f9db10f1d97f9fbb54a4da69690c944377ecc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bogumi=C5=82=20Kami=C5=84ski?= Date: Mon, 30 May 2022 12:05:43 +0200 Subject: [PATCH 17/44] fix another typo --- test/runtests.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/runtests.jl b/test/runtests.jl index 5045a2e..d35a7de 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -16,8 +16,8 @@ DataAPI.colmetadata(x::TestArray, col) = DataAPI.colmetadata(x::TestArray) = Dict("x" => Dict("name" => col)) DataAPI.hasmetadata(x::TestArray) = true -DataAPI.colhasmetadata(x::TestArray) = true -DataAPI.colhasmetadata(x::TestArray, col) = col === "x" +DataAPI.hascolmetadata(x::TestArray) = true +DataAPI.hascolmetadata(x::TestArray, col) = col === "x" @testset "DataAPI" begin From 3e7ed286a5b0bf6a2b29b3e648e711157e80aa08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bogumi=C5=82=20Kami=C5=84ski?= Date: Mon, 30 May 2022 12:47:19 +0200 Subject: [PATCH 18/44] fix tests --- test/runtests.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/runtests.jl b/test/runtests.jl index d35a7de..ce375fe 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -13,7 +13,7 @@ DataAPI.levels(x::TestArray) = reverse(DataAPI.levels(x.x)) DataAPI.metadata(x::TestArray) = Dict("length" => length(x)) DataAPI.colmetadata(x::TestArray, col) = col === "x" ? Dict("name" => col) : throw(ArgumentError("no metadata")) -DataAPI.colmetadata(x::TestArray) = Dict("x" => Dict("name" => col)) +DataAPI.colmetadata(x::TestArray) = Dict("x" => DataAPI.colmetadata(x, "x")) DataAPI.hasmetadata(x::TestArray) = true DataAPI.hascolmetadata(x::TestArray) = true From f2e4eb1a24ba0ba2a68618320f603fe966893676 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bogumi=C5=82=20Kami=C5=84ski?= Date: Mon, 30 May 2022 12:58:32 +0200 Subject: [PATCH 19/44] improve contract description --- src/DataAPI.jl | 13 +++++++++++-- test/runtests.jl | 17 ++++++++--------- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/src/DataAPI.jl b/src/DataAPI.jl index 773698b..4941093 100644 --- a/src/DataAPI.jl +++ b/src/DataAPI.jl @@ -322,7 +322,7 @@ The returned dictionary must contain columns `column` for which `hascolmetadata(table, column)` returns `true` and a value associated to such key must be `colmetadata(table, column)`. """ -colmetadata(::T, ::Any) where {T} = +colmetadata(::T) where {T} = throw(ArgumentError("Key metadata is currently not supported for values of type $T")) """ @@ -330,6 +330,9 @@ colmetadata(::T, ::Any) where {T} = Return `true` if `x` has non-empty metadata, and return `false` if metadata is empty. Return `nothing` if `x` does not support metadata. + +If `hasmetadata` returns `Bool` then it is guaranteed that call to `metatada(x)` +will not throw an error. """ hasmetadata(::Any) = nothing @@ -338,7 +341,10 @@ hasmetadata(::Any) = nothing Return `true` if column `column` of Tables.jl table `table` has non-empty metadata, and return `false` if metadata is empty. -Return `nothing` if metadata is not supported. +Return `nothing` if metadata is not supported for `column`. + +If `hascolmetadata` returns `Bool` then it is guaranteed that call to +`colmetatada(table, columns)` will not throw an error. """ hascolmetadata(::Any, ::Any) = nothing @@ -348,6 +354,9 @@ hascolmetadata(::Any, ::Any) = nothing Return `true` if at least one column of of Tables.jl table `table` has non-empty metadata, and return `false` if metadata is empty for all columns. Return `nothing` if metadata is not supported. + +If `hascolmetadata` returns `Bool` then it is guaranteed that call to +`colmetatada(table)` will not throw an error. """ hascolmetadata(::Any) = nothing diff --git a/test/runtests.jl b/test/runtests.jl index ce375fe..49d0ff6 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -17,7 +17,7 @@ DataAPI.colmetadata(x::TestArray) = Dict("x" => DataAPI.colmetadata(x, "x")) DataAPI.hasmetadata(x::TestArray) = true DataAPI.hascolmetadata(x::TestArray) = true -DataAPI.hascolmetadata(x::TestArray, col) = col === "x" +DataAPI.hascolmetadata(x::TestArray, col) = col === "x" ? true : nothing @testset "DataAPI" begin @@ -183,23 +183,22 @@ end end @testset "metadata" begin - @test_throws ArgumentError DataAPI.metadata(1) @test DataAPI.hasmetadata(1) === nothing - @test_throws ArgumentError DataAPI.metadata(1, 1) + @test_throws ArgumentError DataAPI.metadata(1) @test DataAPI.hascolmetadata(1, 1) === nothing @test_throws ArgumentError DataAPI.colmetadata(1, 1) @test DataAPI.hascolmetadata(1) === nothing @test_throws ArgumentError DataAPI.colmetadata(1) - @test DataAPI.metadata(TestArray([1, 2])) == Dict("length" => 2) @test DataAPI.hasmetadata(TestArray([1, 2])) - @test DataAPI.colmetadata(TestArray([1, 2]), "x") == Dict("name" => "col") - @test DataAPI.hascolmetadata(TestArray([1, 2]), "x") == true + @test DataAPI.metadata(TestArray([1, 2])) == Dict("length" => 2) + @test DataAPI.hascolmetadata(TestArray([1, 2]), "x") === true + @test DataAPI.colmetadata(TestArray([1, 2]), "x") == Dict("name" => "x") + @test DataAPI.hascolmetadata(TestArray([1, 2]), "y") === nothing @test_throws ArgumentError DataAPI.colmetadata(TestArray([1, 2]), "y") - @test DataAPI.hascolmetadata(TestArray([1, 2]), "y") == false - @test DataAPI.colmetadata(TestArray([1, 2])) == Dict("x" => Dict("name" => "col")) - @test DataAPI.hascolmetadata(TestArray([1, 2])) == true + @test DataAPI.hascolmetadata(TestArray([1, 2])) === true + @test DataAPI.colmetadata(TestArray([1, 2])) == Dict("x" => Dict("name" => "x")) end end # @testset "DataAPI" From 76bfba580956886462360d982dd8f3336190fd30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bogumi=C5=82=20Kami=C5=84ski?= Date: Tue, 31 May 2022 09:06:00 +0200 Subject: [PATCH 20/44] update error message --- src/DataAPI.jl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/DataAPI.jl b/src/DataAPI.jl index 4941093..b0642a5 100644 --- a/src/DataAPI.jl +++ b/src/DataAPI.jl @@ -297,7 +297,7 @@ Note that some systems, like Arrow.jl, might assume that metadata values are also `String`. """ metadata(::T) where {T} = - throw(ArgumentError("Metadata is currently not supported for values of type $T")) + throw(ArgumentError("Objects of type $T do not support metadata")) """ colmetadata(table, column) @@ -309,7 +309,7 @@ Note that some systems, like Arrow.jl, might assume that metadata values are also `String`. """ colmetadata(::T, ::Any) where {T} = - throw(ArgumentError("Key metadata is currently not supported for values of type $T")) + throw(ArgumentError("Objects of type $T do not support column metadata")) """ colmetadata(table) @@ -323,7 +323,7 @@ The returned dictionary must contain columns `column` for which key must be `colmetadata(table, column)`. """ colmetadata(::T) where {T} = - throw(ArgumentError("Key metadata is currently not supported for values of type $T")) + throw(ArgumentError("Objects of type $T do not support column metadata")) """ hasmetadata(x) From 9db264a069d70e5a26d5b4ac13494b3f57e299d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bogumi=C5=82=20Kami=C5=84ski?= Date: Wed, 1 Jun 2022 23:14:57 +0200 Subject: [PATCH 21/44] drop table-level colmetadata --- src/DataAPI.jl | 26 -------------------------- test/runtests.jl | 4 ---- 2 files changed, 30 deletions(-) diff --git a/src/DataAPI.jl b/src/DataAPI.jl index b0642a5..a930f92 100644 --- a/src/DataAPI.jl +++ b/src/DataAPI.jl @@ -311,20 +311,6 @@ also `String`. colmetadata(::T, ::Any) where {T} = throw(ArgumentError("Objects of type $T do not support column metadata")) -""" - colmetadata(table) - -Return metadata associated with columns of Tables.jl table `table` as an -`AbstractDict{<:Any, <:AbstractString{String}}` object (or an object implementing -the same interface). - -The returned dictionary must contain columns `column` for which -`hascolmetadata(table, column)` returns `true` and a value associated to such -key must be `colmetadata(table, column)`. -""" -colmetadata(::T) where {T} = - throw(ArgumentError("Objects of type $T do not support column metadata")) - """ hasmetadata(x) @@ -348,16 +334,4 @@ If `hascolmetadata` returns `Bool` then it is guaranteed that call to """ hascolmetadata(::Any, ::Any) = nothing -""" - hascolmetadata(table) - -Return `true` if at least one column of of Tables.jl table `table` has non-empty -metadata, and return `false` if metadata is empty for all columns. -Return `nothing` if metadata is not supported. - -If `hascolmetadata` returns `Bool` then it is guaranteed that call to -`colmetatada(table)` will not throw an error. -""" -hascolmetadata(::Any) = nothing - end # module diff --git a/test/runtests.jl b/test/runtests.jl index 49d0ff6..ee7fba6 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -13,10 +13,8 @@ DataAPI.levels(x::TestArray) = reverse(DataAPI.levels(x.x)) DataAPI.metadata(x::TestArray) = Dict("length" => length(x)) DataAPI.colmetadata(x::TestArray, col) = col === "x" ? Dict("name" => col) : throw(ArgumentError("no metadata")) -DataAPI.colmetadata(x::TestArray) = Dict("x" => DataAPI.colmetadata(x, "x")) DataAPI.hasmetadata(x::TestArray) = true -DataAPI.hascolmetadata(x::TestArray) = true DataAPI.hascolmetadata(x::TestArray, col) = col === "x" ? true : nothing @testset "DataAPI" begin @@ -197,8 +195,6 @@ end @test DataAPI.colmetadata(TestArray([1, 2]), "x") == Dict("name" => "x") @test DataAPI.hascolmetadata(TestArray([1, 2]), "y") === nothing @test_throws ArgumentError DataAPI.colmetadata(TestArray([1, 2]), "y") - @test DataAPI.hascolmetadata(TestArray([1, 2])) === true - @test DataAPI.colmetadata(TestArray([1, 2])) == Dict("x" => Dict("name" => "x")) end end # @testset "DataAPI" From b863431cd3de8117a32e3413727dd983f9449274 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bogumi=C5=82=20Kami=C5=84ski?= Date: Fri, 3 Jun 2022 14:11:23 +0200 Subject: [PATCH 22/44] Update test/runtests.jl Co-authored-by: Milan Bouchet-Valat --- test/runtests.jl | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/runtests.jl b/test/runtests.jl index ee7fba6..f46a1aa 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -185,8 +185,6 @@ end @test_throws ArgumentError DataAPI.metadata(1) @test DataAPI.hascolmetadata(1, 1) === nothing @test_throws ArgumentError DataAPI.colmetadata(1, 1) - @test DataAPI.hascolmetadata(1) === nothing - @test_throws ArgumentError DataAPI.colmetadata(1) @test DataAPI.hasmetadata(TestArray([1, 2])) From 0df50d7dc9dca9d46f6d214838f797251e121909 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bogumi=C5=82=20Kami=C5=84ski?= Date: Thu, 23 Jun 2022 11:39:34 +0200 Subject: [PATCH 23/44] Apply suggestions from code review --- src/DataAPI.jl | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/DataAPI.jl b/src/DataAPI.jl index a930f92..9b9012f 100644 --- a/src/DataAPI.jl +++ b/src/DataAPI.jl @@ -305,6 +305,8 @@ metadata(::T) where {T} = Return metadata associated with column `column` of Tables.jl table `table` as an `AbstractDict{String}` object (or an object implementing the same interface). +`column` should be any accepted column identifier by `table`, but at least `Symbol` must be supported. + Note that some systems, like Arrow.jl, might assume that metadata values are also `String`. """ @@ -329,6 +331,9 @@ Return `true` if column `column` of Tables.jl table `table` has non-empty metada and return `false` if metadata is empty. Return `nothing` if metadata is not supported for `column`. + +`column` should be any accepted column identifier by `table`, but at least `Symbol` must be supported. + If `hascolmetadata` returns `Bool` then it is guaranteed that call to `colmetatada(table, columns)` will not throw an error. """ From 0c685adee8717766359a6bcef6c681a0a3d708c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bogumi=C5=82=20Kami=C5=84ski?= Date: Mon, 27 Jun 2022 17:01:37 +0200 Subject: [PATCH 24/44] add hascolmetadata for whole table --- src/DataAPI.jl | 12 +++++++++++- test/runtests.jl | 4 +++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/DataAPI.jl b/src/DataAPI.jl index 9b9012f..67c40e7 100644 --- a/src/DataAPI.jl +++ b/src/DataAPI.jl @@ -331,7 +331,6 @@ Return `true` if column `column` of Tables.jl table `table` has non-empty metada and return `false` if metadata is empty. Return `nothing` if metadata is not supported for `column`. - `column` should be any accepted column identifier by `table`, but at least `Symbol` must be supported. If `hascolmetadata` returns `Bool` then it is guaranteed that call to @@ -339,4 +338,15 @@ If `hascolmetadata` returns `Bool` then it is guaranteed that call to """ hascolmetadata(::Any, ::Any) = nothing +""" + hascolmetadata(table) + +Return `true` if there is exists at least one column `column` of Tables.jl table +`table` for which `hascolmetadata(table, column)` returns `true`; otherwise +return `false`. + +Return `nothing` if metadata is not supported. +""" +hascolmetadata(::Any) = nothing + end # module diff --git a/test/runtests.jl b/test/runtests.jl index f46a1aa..1fc7892 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -16,6 +16,7 @@ DataAPI.colmetadata(x::TestArray, col) = DataAPI.hasmetadata(x::TestArray) = true DataAPI.hascolmetadata(x::TestArray, col) = col === "x" ? true : nothing +DataAPI.hascolmetadata(x::TestArray) = true @testset "DataAPI" begin @@ -185,10 +186,11 @@ end @test_throws ArgumentError DataAPI.metadata(1) @test DataAPI.hascolmetadata(1, 1) === nothing @test_throws ArgumentError DataAPI.colmetadata(1, 1) - + @test DataAPI.hascolmetadata(1) === nothing @test DataAPI.hasmetadata(TestArray([1, 2])) @test DataAPI.metadata(TestArray([1, 2])) == Dict("length" => 2) + @test DataAPI.hascolmetadata(TestArray([1, 2])) === true @test DataAPI.hascolmetadata(TestArray([1, 2]), "x") === true @test DataAPI.colmetadata(TestArray([1, 2]), "x") == Dict("name" => "x") @test DataAPI.hascolmetadata(TestArray([1, 2]), "y") === nothing From 0d75fce5b999850d02fd96db8cdb4f21377a6664 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bogumi=C5=82=20Kami=C5=84ski?= Date: Sun, 31 Jul 2022 00:03:01 +0200 Subject: [PATCH 25/44] new metadata style --- src/DataAPI.jl | 106 ++++++++++++++++++++++++++++--------------- test/runtests.jl | 116 +++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 167 insertions(+), 55 deletions(-) diff --git a/src/DataAPI.jl b/src/DataAPI.jl index 67c40e7..c3c4820 100644 --- a/src/DataAPI.jl +++ b/src/DataAPI.jl @@ -287,66 +287,100 @@ using a `sink` function to materialize the table. """ function allcombinations end +const STYLE_INFO = """ +One of the uses of the metadata style information is decision +how the metadata should be propagated when `x` is transformed. This interface +defines `:none` style that indicates that metadata should not be propagated +under transformations. At least this style must be supported by any type +defining support for metadata. """ - metadata(x) -Return metadata associated with object `x` as an `AbstractDict{String}` object -(or an object implementing the same interface). +""" + metadata(x, key, [default]; full::Bool=false) + +Return metadata value associated with object `x` for key `key`. +If `x` does not support metadata throw `ArgumentError`. +If `x` supports metadata, but does not have a mapping for `key` throw `KeyError`. + +If `full=true` return a tuple of metadata value and metadata style. Metadata +style is an additional information about the kind of metadata that is stored +for the `key`. + +$STYLE_INFO + +If `default` is passed then return it if `x` does not support metadata or +does not have a mapping for `key`. The style of `default` value is `:none`. +""" +metadata(::T, ::Any; full::Bool=false) where {T} = + throw(ArgumentError("Objects of type $T do not support getting metadata")) +metadata(::Any, ::Any, default; full::Bool=false) = full ? (default, :none) : default -Note that some systems, like Arrow.jl, might assume that metadata values are -also `String`. """ -metadata(::T) where {T} = - throw(ArgumentError("Objects of type $T do not support metadata")) + metadatakeys(x) +Return an iterator of metadata keys for which `metadata(x, key)` returns a +metdata value. If `x` does not support metadata return `()`. """ - colmetadata(table, column) +metadatakeys(::Any) = () -Return metadata associated with column `column` of Tables.jl table `table` as an -`AbstractDict{String}` object (or an object implementing the same interface). +""" + metadata!(x, key, value; style) -`column` should be any accepted column identifier by `table`, but at least `Symbol` must be supported. +Set metadata for object `x` for key `key` to have value `value` and style `style` +and return `x`. +If `x` does not support setting metadata throw `ArgumentError`. -Note that some systems, like Arrow.jl, might assume that metadata values are -also `String`. +$STYLE_INFO """ -colmetadata(::T, ::Any) where {T} = - throw(ArgumentError("Objects of type $T do not support column metadata")) +metadata!(::T, ::Any; style) where {T} = + throw(ArgumentError("Objects of type $T do not support setting metadata")) """ - hasmetadata(x) + colmetadata(x, col, key, [default]; full::Bool=false) -Return `true` if `x` has non-empty metadata, and return `false` if metadata is empty. -Return `nothing` if `x` does not support metadata. +Return metadata value associated with table `x` for column `col` and key `key`. +If `x` does not support metadata for column `col` throw `ArgumentError`. If `x` +supports metadata, but does not have a mapping for column `col` for `key` throw +`KeyError`. -If `hasmetadata` returns `Bool` then it is guaranteed that call to `metatada(x)` -will not throw an error. -""" -hasmetadata(::Any) = nothing +If `full=true` return a tuple of metadata value and metadata style. Metadata +style is an additional information about the kind of metadata that is stored for +the `key`. +$STYLE_INFO + +If `default` is passed then return it if `x` does not support metadata for +column `col` or does not have a mapping for `key` for column `col`. The style of +`default` value is `:none`. """ - hascolmetadata(table, column) +colmetadata(::T, ::Any, ::Any; full::Bool=false) where {T} = + throw(ArgumentError("Objects of type $T do not support getting column metadata")) +colmetadata(::Any, ::Any, ::Any, default; full::Bool=false) = full ? (default, :none) : default -Return `true` if column `column` of Tables.jl table `table` has non-empty metadata, -and return `false` if metadata is empty. -Return `nothing` if metadata is not supported for `column`. +""" + colmetadatakeys(x, [col]) -`column` should be any accepted column identifier by `table`, but at least `Symbol` must be supported. +If `col` is passed return an iterator of metadata keys for which +`metadata(x, col, key)` returns a metdata value. +If `x` does not support metadata for column `col` return `()`. -If `hascolmetadata` returns `Bool` then it is guaranteed that call to -`colmetatada(table, columns)` will not throw an error. +If `col` is not passed return an iterator of `col => colmetadatakeys(x, col)` +pairs for all columns that have metadata. +If `x` does not support metadata for any column return `()`. """ -hascolmetadata(::Any, ::Any) = nothing +colmetadatakeys(::Any, ::Any) = () +colmetadatakeys(::Any) = () """ - hascolmetadata(table) + colmetadata!(x, key, value; style) -Return `true` if there is exists at least one column `column` of Tables.jl table -`table` for which `hascolmetadata(table, column)` returns `true`; otherwise -return `false`. +Set metadata for table `x` for column `col` for key `key` to have value `value` +and style `style`. +If `x` does not support setting metadata for column `col` throw `ArgumentError`. -Return `nothing` if metadata is not supported. +$STYLE_INFO """ -hascolmetadata(::Any) = nothing +colmetadata!(::T, ::Any, ::Any; style) where {T} = + throw(ArgumentError("Objects of type $T do not support setting metadata")) end # module diff --git a/test/runtests.jl b/test/runtests.jl index 1fc7892..9bf283a 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -10,13 +10,57 @@ Base.size(x::TestArray) = size(x.x) Base.getindex(x::TestArray, i) = x.x[i] DataAPI.levels(x::TestArray) = reverse(DataAPI.levels(x.x)) -DataAPI.metadata(x::TestArray) = Dict("length" => length(x)) -DataAPI.colmetadata(x::TestArray, col) = - col === "x" ? Dict("name" => col) : throw(ArgumentError("no metadata")) +struct TestMeta + table::Dict + col::Dict + + TestMeta() = new(Dict(), Dict()) +end + +function DataAPI.metadata(x::TestMeta, key; full::Bool=false) + return full ? x.table[key] : x.table[key][1] +end + +function DataAPI.metadata(x::TestMeta, key, default) + haskey(x.test, key) && return DataAPI.metadata(x, key, full=full) + full ? (default, :none) : default +end + +DataAPI.metadatakeys(x::TestMeta) = keys(x.table) + +function DataAPI.metadata!(x::TestMeta, key, value; style) + x.table[key] = (value, style) + return x +end + +function DataAPI.colmetadata(x::TestMeta, col, key; full::Bool=false) + return full ? x.col[col][key] : x.col[col][key][1] +end + +function DataAPI.colmetadata(x::TestMeta, col, key, default) + haskey(x.col, col) && haskey(x.col[col], key) && return DataAPI.metadata(x, col, key, full=full) + full ? (default, :none) : default +end + +function DataAPI.colmetadatakeys(x::TestMeta, col) + haskey(x.col, col) && return keys(x.col[col]) + return () +end + +function DataAPI.colmetadatakeys(x::TestMeta) + isempty(x.col) && return () + return Any[col => keys(x.col[col]) for col in keys(x.col)] +end + +function DataAPI.metadata!(x::TestMeta, col, key, value; style) + if haskey(x.col, col) + x.col[col][key] = (value, style) + else + x.col[col] = Dict{Any, Any}(key => (value, style)) + end + return x +end -DataAPI.hasmetadata(x::TestArray) = true -DataAPI.hascolmetadata(x::TestArray, col) = col === "x" ? true : nothing -DataAPI.hascolmetadata(x::TestArray) = true @testset "DataAPI" begin @@ -182,19 +226,53 @@ end end @testset "metadata" begin - @test DataAPI.hasmetadata(1) === nothing - @test_throws ArgumentError DataAPI.metadata(1) - @test DataAPI.hascolmetadata(1, 1) === nothing - @test_throws ArgumentError DataAPI.colmetadata(1, 1) - @test DataAPI.hascolmetadata(1) === nothing - - @test DataAPI.hasmetadata(TestArray([1, 2])) - @test DataAPI.metadata(TestArray([1, 2])) == Dict("length" => 2) - @test DataAPI.hascolmetadata(TestArray([1, 2])) === true - @test DataAPI.hascolmetadata(TestArray([1, 2]), "x") === true - @test DataAPI.colmetadata(TestArray([1, 2]), "x") == Dict("name" => "x") - @test DataAPI.hascolmetadata(TestArray([1, 2]), "y") === nothing - @test_throws ArgumentError DataAPI.colmetadata(TestArray([1, 2]), "y") + @test_throws ArgumentError DataAPI.metadata!(1, "a", 10, style=:none) + @test_throws ArgumentError DataAPI.metadata(1, "a") + @test_throws ArgumentError DataAPI.metadata(1, "a", full=true) + @test DataAPI.metadata(1, "a", 10) == 10 + @test DataAPI.metadata(1, "a", 10, full=true) == (10, :none) + @test DataAPI.metadatakeys(1) == () + + @test_throws ArgumentError DataAPI.colmetadata!(1, "col", "a", 10, style=:none) + @test_throws ArgumentError DataAPI.colmetadata(1, "col", "a") + @test_throws ArgumentError DataAPI.colmetadata(1, "col", "a", full=true) + @test DataAPI.colmetadata(1, "col", "a", 10) == 10 + @test DataAPI.colmetadata(1, "col", "a", 10, full=true) == (10, :none) + @test DataAPI.colmetadatakeys(1, "col") == () + @test DataAPI.colmetadatakeys(1) == () + + tm = TestMeta() + @test DataAPI.metadatakeys(tm) == () + @test DataAPI.metadata!(tm, "a", "100", style=:note) == tm + @test collect(DataAPI.metadatakeys(tm)) == ["a"] + @test_throws ArgumentError DataAPI.metadata(tm, "b") + @test_throws ArgumentError DataAPI.metadata(tm, "b", full=true) + @test DataAPI.metadata(tm, "a") == "100" + @test DataAPI.metadata(tm, "a", full=true) == ("100", :note) + @test DataAPI.metadata(tm, "b", 10) == 10 + @test DataAPI.metadata(tm, "b", 10, full=true) == (10, :none) + @test DataAPI.metadata(tm, "a", 10) == "100" + @test DataAPI.metadata(tm, "a", 10, full=true) == ("100", :note) + + + @test DataAPI.colmetadatakeys(tm) == () + @test DataAPI.colmetadatakeys(tm, "col") == () + @test_throws ArgumentError DataAPI.colmetadata!(tm, "col", "a", "100", style=:note) + @test [k => collect(v) for (k, v) in DataAPI.colmetadatakeys(tm)] == ["col" => ["a"]] + @test collect(DataAPI.colmetadatakeys(tm, "col")) == ["a"] + @test_throws ArgumentError DataAPI.colmetadata(tm, "col", "b") + @test_throws ArgumentError DataAPI.colmetadata(tm, "col", "b", full=true) + @test_throws ArgumentError DataAPI.colmetadata(tm, "col2", "a") + @test_throws ArgumentError DataAPI.colmetadata(tm, "col2", "a", full=true) + @test DataAPI.colmetadata(tm, "col", "b", 10) == 10 + @test DataAPI.colmetadata(tm, "col", "b", 10, full=true) == (10, :none) + @test DataAPI.colmetadata(tm, "col2", "a", 10) == 10 + @test DataAPI.colmetadata(tm, "col2", "a", 10, full=true) == (10, :none) + @test DataAPI.colmetadata(tm, "col", "a") == "100" + @test DataAPI.colmetadata(tm, "col", "a", full=true) == ("100", :note) + @test DataAPI.colmetadata(tm, "col", "a", 10) == "100" + @test DataAPI.colmetadata(tm, "col", "a", 10, full=true) == ("100", :note) + end end # @testset "DataAPI" From 40edcd9464cdd8a247b00a8a3e0eeca0a2654123 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bogumi=C5=82=20Kami=C5=84ski?= Date: Sun, 31 Jul 2022 00:19:56 +0200 Subject: [PATCH 26/44] small fixes --- src/DataAPI.jl | 4 ++-- test/runtests.jl | 29 +++++++++++++---------------- 2 files changed, 15 insertions(+), 18 deletions(-) diff --git a/src/DataAPI.jl b/src/DataAPI.jl index c3c4820..138d13f 100644 --- a/src/DataAPI.jl +++ b/src/DataAPI.jl @@ -332,7 +332,7 @@ If `x` does not support setting metadata throw `ArgumentError`. $STYLE_INFO """ -metadata!(::T, ::Any; style) where {T} = +metadata!(::T, ::Any, ::Any; style) where {T} = throw(ArgumentError("Objects of type $T do not support setting metadata")) """ @@ -380,7 +380,7 @@ If `x` does not support setting metadata for column `col` throw `ArgumentError`. $STYLE_INFO """ -colmetadata!(::T, ::Any, ::Any; style) where {T} = +colmetadata!(::T, ::Any, ::Any, ::Any; style) where {T} = throw(ArgumentError("Objects of type $T do not support setting metadata")) end # module diff --git a/test/runtests.jl b/test/runtests.jl index 9bf283a..f2100f6 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -21,8 +21,8 @@ function DataAPI.metadata(x::TestMeta, key; full::Bool=false) return full ? x.table[key] : x.table[key][1] end -function DataAPI.metadata(x::TestMeta, key, default) - haskey(x.test, key) && return DataAPI.metadata(x, key, full=full) +function DataAPI.metadata(x::TestMeta, key, default; full::Bool=false) + haskey(x.table, key) && return DataAPI.metadata(x, key, full=full) full ? (default, :none) : default end @@ -37,8 +37,8 @@ function DataAPI.colmetadata(x::TestMeta, col, key; full::Bool=false) return full ? x.col[col][key] : x.col[col][key][1] end -function DataAPI.colmetadata(x::TestMeta, col, key, default) - haskey(x.col, col) && haskey(x.col[col], key) && return DataAPI.metadata(x, col, key, full=full) +function DataAPI.colmetadata(x::TestMeta, col, key, default; full::Bool=false) + haskey(x.col, col) && haskey(x.col[col], key) && return DataAPI.colmetadata(x, col, key, full=full) full ? (default, :none) : default end @@ -52,7 +52,7 @@ function DataAPI.colmetadatakeys(x::TestMeta) return Any[col => keys(x.col[col]) for col in keys(x.col)] end -function DataAPI.metadata!(x::TestMeta, col, key, value; style) +function DataAPI.colmetadata!(x::TestMeta, col, key, value; style) if haskey(x.col, col) x.col[col][key] = (value, style) else @@ -242,28 +242,26 @@ end @test DataAPI.colmetadatakeys(1) == () tm = TestMeta() - @test DataAPI.metadatakeys(tm) == () + @test isempty(DataAPI.metadatakeys(tm)) @test DataAPI.metadata!(tm, "a", "100", style=:note) == tm @test collect(DataAPI.metadatakeys(tm)) == ["a"] - @test_throws ArgumentError DataAPI.metadata(tm, "b") - @test_throws ArgumentError DataAPI.metadata(tm, "b", full=true) + @test_throws KeyError DataAPI.metadata(tm, "b") + @test_throws KeyError DataAPI.metadata(tm, "b", full=true) @test DataAPI.metadata(tm, "a") == "100" @test DataAPI.metadata(tm, "a", full=true) == ("100", :note) @test DataAPI.metadata(tm, "b", 10) == 10 @test DataAPI.metadata(tm, "b", 10, full=true) == (10, :none) @test DataAPI.metadata(tm, "a", 10) == "100" @test DataAPI.metadata(tm, "a", 10, full=true) == ("100", :note) - - @test DataAPI.colmetadatakeys(tm) == () @test DataAPI.colmetadatakeys(tm, "col") == () - @test_throws ArgumentError DataAPI.colmetadata!(tm, "col", "a", "100", style=:note) + @test DataAPI.colmetadata!(tm, "col", "a", "100", style=:note) == tm @test [k => collect(v) for (k, v) in DataAPI.colmetadatakeys(tm)] == ["col" => ["a"]] @test collect(DataAPI.colmetadatakeys(tm, "col")) == ["a"] - @test_throws ArgumentError DataAPI.colmetadata(tm, "col", "b") - @test_throws ArgumentError DataAPI.colmetadata(tm, "col", "b", full=true) - @test_throws ArgumentError DataAPI.colmetadata(tm, "col2", "a") - @test_throws ArgumentError DataAPI.colmetadata(tm, "col2", "a", full=true) + @test_throws KeyError DataAPI.colmetadata(tm, "col", "b") + @test_throws KeyError DataAPI.colmetadata(tm, "col", "b", full=true) + @test_throws KeyError DataAPI.colmetadata(tm, "col2", "a") + @test_throws KeyError DataAPI.colmetadata(tm, "col2", "a", full=true) @test DataAPI.colmetadata(tm, "col", "b", 10) == 10 @test DataAPI.colmetadata(tm, "col", "b", 10, full=true) == (10, :none) @test DataAPI.colmetadata(tm, "col2", "a", 10) == 10 @@ -272,7 +270,6 @@ end @test DataAPI.colmetadata(tm, "col", "a", full=true) == ("100", :note) @test DataAPI.colmetadata(tm, "col", "a", 10) == "100" @test DataAPI.colmetadata(tm, "col", "a", 10, full=true) == ("100", :note) - end end # @testset "DataAPI" From c3d7f943c99c0ab3749037080e3f64d470f5efba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bogumi=C5=82=20Kami=C5=84ski?= Date: Sun, 31 Jul 2022 22:32:07 +0200 Subject: [PATCH 27/44] Apply suggestions from code review Co-authored-by: Milan Bouchet-Valat --- src/DataAPI.jl | 6 +++--- test/runtests.jl | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/DataAPI.jl b/src/DataAPI.jl index 138d13f..ab8791c 100644 --- a/src/DataAPI.jl +++ b/src/DataAPI.jl @@ -290,7 +290,7 @@ function allcombinations end const STYLE_INFO = """ One of the uses of the metadata style information is decision how the metadata should be propagated when `x` is transformed. This interface -defines `:none` style that indicates that metadata should not be propagated +defines the `:none` style that indicates that metadata should not be propagated under transformations. At least this style must be supported by any type defining support for metadata. """ @@ -319,7 +319,7 @@ metadata(::Any, ::Any, default; full::Bool=false) = full ? (default, :none) : de metadatakeys(x) Return an iterator of metadata keys for which `metadata(x, key)` returns a -metdata value. If `x` does not support metadata return `()`. +metadata value. If `x` does not support metadata return `()`. """ metadatakeys(::Any) = () @@ -361,7 +361,7 @@ colmetadata(::Any, ::Any, ::Any, default; full::Bool=false) = full ? (default, : colmetadatakeys(x, [col]) If `col` is passed return an iterator of metadata keys for which -`metadata(x, col, key)` returns a metdata value. +`metadata(x, col, key)` returns a metadata value. If `x` does not support metadata for column `col` return `()`. If `col` is not passed return an iterator of `col => colmetadatakeys(x, col)` diff --git a/test/runtests.jl b/test/runtests.jl index f2100f6..440370a 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -49,7 +49,7 @@ end function DataAPI.colmetadatakeys(x::TestMeta) isempty(x.col) && return () - return Any[col => keys(x.col[col]) for col in keys(x.col)] + return (col => keys(x.col[col]) for col in keys(x.col)) end function DataAPI.colmetadata!(x::TestMeta, col, key, value; style) From a75b9655390cf6c6354693a6dac8dfcdd44d8418 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bogumi=C5=82=20Kami=C5=84ski?= Date: Sun, 31 Jul 2022 23:10:35 +0200 Subject: [PATCH 28/44] changes after code review --- src/DataAPI.jl | 66 ++++++++++++++++++++++++++------------ test/runtests.jl | 82 ++++++++++++++++++------------------------------ 2 files changed, 77 insertions(+), 71 deletions(-) diff --git a/src/DataAPI.jl b/src/DataAPI.jl index ab8791c..c93a832 100644 --- a/src/DataAPI.jl +++ b/src/DataAPI.jl @@ -295,25 +295,33 @@ under transformations. At least this style must be supported by any type defining support for metadata. """ +const COL_INFO = """ +`col` must be a type that is supported by table `x`. Following the Tables.jl +contract `Symbol` and `Int` must be supported. However, tables that allow other +column indexing (e.g., using strings or integers other than `Int`) are allowed +to accept such types of `col` argument. Passing `col` that is not a column +of `x` must throw an error. """ - metadata(x, key, [default]; full::Bool=false) + +""" + metadata(x, key::AbstractString; style::Bool=false) Return metadata value associated with object `x` for key `key`. If `x` does not support metadata throw `ArgumentError`. If `x` supports metadata, but does not have a mapping for `key` throw `KeyError`. -If `full=true` return a tuple of metadata value and metadata style. Metadata +Functions adding methods to `metadata` should define them only with +`key::AbstractString` signature. Passing `key` that is not a string to +`metadata` must throw `MethodError`. + +If `style=true` return a tuple of metadata value and metadata style. Metadata style is an additional information about the kind of metadata that is stored for the `key`. $STYLE_INFO - -If `default` is passed then return it if `x` does not support metadata or -does not have a mapping for `key`. The style of `default` value is `:none`. """ -metadata(::T, ::Any; full::Bool=false) where {T} = +metadata(::T, ::AbstractString; style::Bool=false) where {T} = throw(ArgumentError("Objects of type $T do not support getting metadata")) -metadata(::Any, ::Any, default; full::Bool=false) = full ? (default, :none) : default """ metadatakeys(x) @@ -324,38 +332,45 @@ metadata value. If `x` does not support metadata return `()`. metadatakeys(::Any) = () """ - metadata!(x, key, value; style) + metadata!(x, key::AbstractString, value; style) Set metadata for object `x` for key `key` to have value `value` and style `style` and return `x`. If `x` does not support setting metadata throw `ArgumentError`. +Functions adding methods to `metadata!` should define them only with +`key::AbstractString` signature. Passing `key` that is not a string to +`metadata` must throw `MethodError`. + $STYLE_INFO """ -metadata!(::T, ::Any, ::Any; style) where {T} = +metadata!(::T, ::AbstractString, ::Any; style) where {T} = throw(ArgumentError("Objects of type $T do not support setting metadata")) """ - colmetadata(x, col, key, [default]; full::Bool=false) + colmetadata(x, col, key::AbstractString; style::Bool=false) Return metadata value associated with table `x` for column `col` and key `key`. If `x` does not support metadata for column `col` throw `ArgumentError`. If `x` supports metadata, but does not have a mapping for column `col` for `key` throw `KeyError`. -If `full=true` return a tuple of metadata value and metadata style. Metadata +Functions adding methods to `colmetadata` should define them only with +`key::AbstractString` signature. Passing `key` that is not a string to +`metadata` must throw `MethodError`. + +$COL_INFO + +If `style=true` return a tuple of metadata value and metadata style. Metadata style is an additional information about the kind of metadata that is stored for the `key`. $STYLE_INFO - -If `default` is passed then return it if `x` does not support metadata for -column `col` or does not have a mapping for `key` for column `col`. The style of -`default` value is `:none`. """ -colmetadata(::T, ::Any, ::Any; full::Bool=false) where {T} = +colmetadata(::T, ::Int, ::AbstractString; style::Bool=false) where {T} = + throw(ArgumentError("Objects of type $T do not support getting column metadata")) +colmetadata(::T, ::Symbol, ::AbstractString; style::Bool=false) where {T} = throw(ArgumentError("Objects of type $T do not support getting column metadata")) -colmetadata(::Any, ::Any, ::Any, default; full::Bool=false) = full ? (default, :none) : default """ colmetadatakeys(x, [col]) @@ -364,23 +379,34 @@ If `col` is passed return an iterator of metadata keys for which `metadata(x, col, key)` returns a metadata value. If `x` does not support metadata for column `col` return `()`. +$COL_INFO + If `col` is not passed return an iterator of `col => colmetadatakeys(x, col)` pairs for all columns that have metadata. If `x` does not support metadata for any column return `()`. """ -colmetadatakeys(::Any, ::Any) = () +colmetadatakeys(::Any, ::Int) = () +colmetadatakeys(::Any, ::Symbol) = () colmetadatakeys(::Any) = () """ - colmetadata!(x, key, value; style) + colmetadata!(x, col, key::AbstractString, value; style) Set metadata for table `x` for column `col` for key `key` to have value `value` and style `style`. If `x` does not support setting metadata for column `col` throw `ArgumentError`. +Functions adding methods to `colmetadata!` should define them only with +`key::AbstractString` signature. Passing `key` that is not a string to +`metadata` must throw `MethodError`. + +$COL_INFO + $STYLE_INFO """ -colmetadata!(::T, ::Any, ::Any, ::Any; style) where {T} = +colmetadata!(::T, ::Int, ::AbstractString, ::Any; style) where {T} = + throw(ArgumentError("Objects of type $T do not support setting metadata")) +colmetadata!(::T, ::Symbol, ::AbstractString, ::Any; style) where {T} = throw(ArgumentError("Objects of type $T do not support setting metadata")) end # module diff --git a/test/runtests.jl b/test/runtests.jl index 440370a..63bc0b8 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -10,39 +10,33 @@ Base.size(x::TestArray) = size(x.x) Base.getindex(x::TestArray, i) = x.x[i] DataAPI.levels(x::TestArray) = reverse(DataAPI.levels(x.x)) -struct TestMeta - table::Dict - col::Dict +# An example implementation of metadata +# For simplicity Int col indexing is not implemented +# and no checking if col is a column of a table is performed - TestMeta() = new(Dict(), Dict()) -end +struct TestMeta + table::Dict{String, Any} + col::Dict{Symbol, Dict{String, Any}} -function DataAPI.metadata(x::TestMeta, key; full::Bool=false) - return full ? x.table[key] : x.table[key][1] + TestMeta() = new(Dict{String, Any}(), Dict{Symbol, Dict{String, Any}}()) end -function DataAPI.metadata(x::TestMeta, key, default; full::Bool=false) - haskey(x.table, key) && return DataAPI.metadata(x, key, full=full) - full ? (default, :none) : default +function DataAPI.metadata(x::TestMeta, key::AbstractString; style::Bool=false) + return style ? x.table[key] : x.table[key][1] end DataAPI.metadatakeys(x::TestMeta) = keys(x.table) -function DataAPI.metadata!(x::TestMeta, key, value; style) +function DataAPI.metadata!(x::TestMeta, key::AbstractString, value; style) x.table[key] = (value, style) return x end -function DataAPI.colmetadata(x::TestMeta, col, key; full::Bool=false) - return full ? x.col[col][key] : x.col[col][key][1] -end - -function DataAPI.colmetadata(x::TestMeta, col, key, default; full::Bool=false) - haskey(x.col, col) && haskey(x.col[col], key) && return DataAPI.colmetadata(x, col, key, full=full) - full ? (default, :none) : default +function DataAPI.colmetadata(x::TestMeta, col::Symbol, key::AbstractString; style::Bool=false) + return style ? x.col[col][key] : x.col[col][key][1] end -function DataAPI.colmetadatakeys(x::TestMeta, col) +function DataAPI.colmetadatakeys(x::TestMeta, col::Symbol) haskey(x.col, col) && return keys(x.col[col]) return () end @@ -52,7 +46,7 @@ function DataAPI.colmetadatakeys(x::TestMeta) return (col => keys(x.col[col]) for col in keys(x.col)) end -function DataAPI.colmetadata!(x::TestMeta, col, key, value; style) +function DataAPI.colmetadata!(x::TestMeta, col::Symbol, key::AbstractString, value; style) if haskey(x.col, col) x.col[col][key] = (value, style) else @@ -228,17 +222,13 @@ end @testset "metadata" begin @test_throws ArgumentError DataAPI.metadata!(1, "a", 10, style=:none) @test_throws ArgumentError DataAPI.metadata(1, "a") - @test_throws ArgumentError DataAPI.metadata(1, "a", full=true) - @test DataAPI.metadata(1, "a", 10) == 10 - @test DataAPI.metadata(1, "a", 10, full=true) == (10, :none) + @test_throws ArgumentError DataAPI.metadata(1, "a", style=true) @test DataAPI.metadatakeys(1) == () - @test_throws ArgumentError DataAPI.colmetadata!(1, "col", "a", 10, style=:none) - @test_throws ArgumentError DataAPI.colmetadata(1, "col", "a") - @test_throws ArgumentError DataAPI.colmetadata(1, "col", "a", full=true) - @test DataAPI.colmetadata(1, "col", "a", 10) == 10 - @test DataAPI.colmetadata(1, "col", "a", 10, full=true) == (10, :none) - @test DataAPI.colmetadatakeys(1, "col") == () + @test_throws ArgumentError DataAPI.colmetadata!(1, :col, "a", 10, style=:none) + @test_throws ArgumentError DataAPI.colmetadata(1, :col, "a") + @test_throws ArgumentError DataAPI.colmetadata(1, :col, "a", style=true) + @test DataAPI.colmetadatakeys(1, :col) == () @test DataAPI.colmetadatakeys(1) == () tm = TestMeta() @@ -246,30 +236,20 @@ end @test DataAPI.metadata!(tm, "a", "100", style=:note) == tm @test collect(DataAPI.metadatakeys(tm)) == ["a"] @test_throws KeyError DataAPI.metadata(tm, "b") - @test_throws KeyError DataAPI.metadata(tm, "b", full=true) + @test_throws KeyError DataAPI.metadata(tm, "b", style=true) @test DataAPI.metadata(tm, "a") == "100" - @test DataAPI.metadata(tm, "a", full=true) == ("100", :note) - @test DataAPI.metadata(tm, "b", 10) == 10 - @test DataAPI.metadata(tm, "b", 10, full=true) == (10, :none) - @test DataAPI.metadata(tm, "a", 10) == "100" - @test DataAPI.metadata(tm, "a", 10, full=true) == ("100", :note) + @test DataAPI.metadata(tm, "a", style=true) == ("100", :note) @test DataAPI.colmetadatakeys(tm) == () - @test DataAPI.colmetadatakeys(tm, "col") == () - @test DataAPI.colmetadata!(tm, "col", "a", "100", style=:note) == tm - @test [k => collect(v) for (k, v) in DataAPI.colmetadatakeys(tm)] == ["col" => ["a"]] - @test collect(DataAPI.colmetadatakeys(tm, "col")) == ["a"] - @test_throws KeyError DataAPI.colmetadata(tm, "col", "b") - @test_throws KeyError DataAPI.colmetadata(tm, "col", "b", full=true) - @test_throws KeyError DataAPI.colmetadata(tm, "col2", "a") - @test_throws KeyError DataAPI.colmetadata(tm, "col2", "a", full=true) - @test DataAPI.colmetadata(tm, "col", "b", 10) == 10 - @test DataAPI.colmetadata(tm, "col", "b", 10, full=true) == (10, :none) - @test DataAPI.colmetadata(tm, "col2", "a", 10) == 10 - @test DataAPI.colmetadata(tm, "col2", "a", 10, full=true) == (10, :none) - @test DataAPI.colmetadata(tm, "col", "a") == "100" - @test DataAPI.colmetadata(tm, "col", "a", full=true) == ("100", :note) - @test DataAPI.colmetadata(tm, "col", "a", 10) == "100" - @test DataAPI.colmetadata(tm, "col", "a", 10, full=true) == ("100", :note) + @test DataAPI.colmetadatakeys(tm, :col) == () + @test DataAPI.colmetadata!(tm, :col, "a", "100", style=:note) == tm + @test [k => collect(v) for (k, v) in DataAPI.colmetadatakeys(tm)] == [:col => ["a"]] + @test collect(DataAPI.colmetadatakeys(tm, :col)) == ["a"] + @test_throws KeyError DataAPI.colmetadata(tm, :col, "b") + @test_throws KeyError DataAPI.colmetadata(tm, :col, "b", style=true) + @test_throws KeyError DataAPI.colmetadata(tm, :col2, "a") + @test_throws KeyError DataAPI.colmetadata(tm, :col2, "a", style=true) + @test DataAPI.colmetadata(tm, :col, "a") == "100" + @test DataAPI.colmetadata(tm, :col, "a", style=true) == ("100", :note) end end # @testset "DataAPI" From 47629ed1dbec5438564eb3a4b83235be4ee130fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bogumi=C5=82=20Kami=C5=84ski?= Date: Sun, 31 Jul 2022 23:25:00 +0200 Subject: [PATCH 29/44] update specification --- src/DataAPI.jl | 7 ++++++- test/runtests.jl | 4 ++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/DataAPI.jl b/src/DataAPI.jl index c93a832..00362b5 100644 --- a/src/DataAPI.jl +++ b/src/DataAPI.jl @@ -379,7 +379,12 @@ If `col` is passed return an iterator of metadata keys for which `metadata(x, col, key)` returns a metadata value. If `x` does not support metadata for column `col` return `()`. -$COL_INFO +`col` must be a type that is supported by table `x`. Following the Tables.jl +contract `Symbol` and `Int` must be supported. However, tables that allow other +column indexing (e.g., using strings or integers other than `Int`) are allowed +to accept such types of `col` argument. Passing `col` that is not a column +of `x` can either throw an error or return `()` (this duality is allowed as +some Tables.jl do not have schema). If `col` is not passed return an iterator of `col => colmetadatakeys(x, col)` pairs for all columns that have metadata. diff --git a/test/runtests.jl b/test/runtests.jl index 63bc0b8..29fe0db 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -228,7 +228,11 @@ end @test_throws ArgumentError DataAPI.colmetadata!(1, :col, "a", 10, style=:none) @test_throws ArgumentError DataAPI.colmetadata(1, :col, "a") @test_throws ArgumentError DataAPI.colmetadata(1, :col, "a", style=true) + @test_throws ArgumentError DataAPI.colmetadata!(1, 1, "a", 10, style=:none) + @test_throws ArgumentError DataAPI.colmetadata(1, 1, "a") + @test_throws ArgumentError DataAPI.colmetadata(1, 1, "a", style=true) @test DataAPI.colmetadatakeys(1, :col) == () + @test DataAPI.colmetadatakeys(1, 1) == () @test DataAPI.colmetadatakeys(1) == () tm = TestMeta() From 51add3c25bda35c198d61adede0bd5960b9cf8d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bogumi=C5=82=20Kami=C5=84ski?= Date: Mon, 1 Aug 2022 23:26:33 +0200 Subject: [PATCH 30/44] update docstrings --- src/DataAPI.jl | 60 +++++++++++++++++++++++--------------------------- 1 file changed, 27 insertions(+), 33 deletions(-) diff --git a/src/DataAPI.jl b/src/DataAPI.jl index 00362b5..8c4b902 100644 --- a/src/DataAPI.jl +++ b/src/DataAPI.jl @@ -288,19 +288,17 @@ using a `sink` function to materialize the table. function allcombinations end const STYLE_INFO = """ -One of the uses of the metadata style information is decision +One of the uses of the metadata `style` is decision how the metadata should be propagated when `x` is transformed. This interface defines the `:none` style that indicates that metadata should not be propagated -under transformations. At least this style must be supported by any type +under transformations. At least this style is allowed by any type defining support for metadata. """ const COL_INFO = """ -`col` must be a type that is supported by table `x`. Following the Tables.jl -contract `Symbol` and `Int` must be supported. However, tables that allow other -column indexing (e.g., using strings or integers other than `Int`) are allowed -to accept such types of `col` argument. Passing `col` that is not a column -of `x` must throw an error. +`col` must have a type that is supported by table `x` for column indexing. +Following the Tables.jl contract `Symbol` and `Int` are always allowed. +Passing `col` that is not a column of `x` throws an error. """ """ @@ -308,11 +306,11 @@ of `x` must throw an error. Return metadata value associated with object `x` for key `key`. If `x` does not support metadata throw `ArgumentError`. -If `x` supports metadata, but does not have a mapping for `key` throw `KeyError`. +If `x` supports metadata, but does not have a mapping for `key` throw +`KeyError`. -Functions adding methods to `metadata` should define them only with -`key::AbstractString` signature. Passing `key` that is not a string to -`metadata` must throw `MethodError`. +Passing `key` that is not an `AbstractString` to `metadata` throws +`MethodError`. If `style=true` return a tuple of metadata value and metadata style. Metadata style is an additional information about the kind of metadata that is stored @@ -334,13 +332,12 @@ metadatakeys(::Any) = () """ metadata!(x, key::AbstractString, value; style) -Set metadata for object `x` for key `key` to have value `value` and style `style` -and return `x`. +Set metadata for object `x` for key `key` to have value `value` +and style `style` and return `x`. If `x` does not support setting metadata throw `ArgumentError`. -Functions adding methods to `metadata!` should define them only with -`key::AbstractString` signature. Passing `key` that is not a string to -`metadata` must throw `MethodError`. +Passing `key` that is not an `AbstractString` to `metadata!` +throws `MethodError`. $STYLE_INFO """ @@ -355,9 +352,8 @@ If `x` does not support metadata for column `col` throw `ArgumentError`. If `x` supports metadata, but does not have a mapping for column `col` for `key` throw `KeyError`. -Functions adding methods to `colmetadata` should define them only with -`key::AbstractString` signature. Passing `key` that is not a string to -`metadata` must throw `MethodError`. +Passing `key` that is not an `AbstractString` to `colmetadata` +throws `MethodError`. $COL_INFO @@ -375,20 +371,19 @@ colmetadata(::T, ::Symbol, ::AbstractString; style::Bool=false) where {T} = """ colmetadatakeys(x, [col]) -If `col` is passed return an iterator of metadata keys for which -`metadata(x, col, key)` returns a metadata value. -If `x` does not support metadata for column `col` return `()`. +If `col` is passed return an iterator of metadata keys for which `metadata(x, +col, key)` returns a metadata value. If `x` does not support metadata for column +`col` return `()`. -`col` must be a type that is supported by table `x`. Following the Tables.jl -contract `Symbol` and `Int` must be supported. However, tables that allow other -column indexing (e.g., using strings or integers other than `Int`) are allowed -to accept such types of `col` argument. Passing `col` that is not a column -of `x` can either throw an error or return `()` (this duality is allowed as -some Tables.jl do not have schema). +`col` must have a type that is supported by table `x` for column indexing. +Following the Tables.jl contract `Symbol` and `Int` are always allowed. Passing +`col` that is not a column of `x` can either throws an error (this is a +preferred behavior if it is possible) or returns `()` (this duality is allowed +as some Tables.jl tables do not have schema). If `col` is not passed return an iterator of `col => colmetadatakeys(x, col)` -pairs for all columns that have metadata. -If `x` does not support metadata for any column return `()`. +pairs for all columns that have metadata. If `x` does not support metadata for +any column return `()`. """ colmetadatakeys(::Any, ::Int) = () colmetadatakeys(::Any, ::Symbol) = () @@ -401,9 +396,8 @@ Set metadata for table `x` for column `col` for key `key` to have value `value` and style `style`. If `x` does not support setting metadata for column `col` throw `ArgumentError`. -Functions adding methods to `colmetadata!` should define them only with -`key::AbstractString` signature. Passing `key` that is not a string to -`metadata` must throw `MethodError`. +Passing `key` that is not an `AbstractString` to `colmetadata!` +throws `MethodError`. $COL_INFO From f0c9fc021cda1ecebd60a3161bc61bce0a031f5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bogumi=C5=82=20Kami=C5=84ski?= Date: Tue, 2 Aug 2022 14:00:07 +0200 Subject: [PATCH 31/44] Apply suggestions from code review Co-authored-by: Milan Bouchet-Valat --- src/DataAPI.jl | 21 ++++----------------- 1 file changed, 4 insertions(+), 17 deletions(-) diff --git a/src/DataAPI.jl b/src/DataAPI.jl index 8c4b902..acde04b 100644 --- a/src/DataAPI.jl +++ b/src/DataAPI.jl @@ -291,8 +291,7 @@ const STYLE_INFO = """ One of the uses of the metadata `style` is decision how the metadata should be propagated when `x` is transformed. This interface defines the `:none` style that indicates that metadata should not be propagated -under transformations. At least this style is allowed by any type -defining support for metadata. +under transformations. All types supporting metadata allow at least this style. """ const COL_INFO = """ @@ -309,9 +308,6 @@ If `x` does not support metadata throw `ArgumentError`. If `x` supports metadata, but does not have a mapping for `key` throw `KeyError`. -Passing `key` that is not an `AbstractString` to `metadata` throws -`MethodError`. - If `style=true` return a tuple of metadata value and metadata style. Metadata style is an additional information about the kind of metadata that is stored for the `key`. @@ -336,9 +332,6 @@ Set metadata for object `x` for key `key` to have value `value` and style `style` and return `x`. If `x` does not support setting metadata throw `ArgumentError`. -Passing `key` that is not an `AbstractString` to `metadata!` -throws `MethodError`. - $STYLE_INFO """ metadata!(::T, ::AbstractString, ::Any; style) where {T} = @@ -352,9 +345,6 @@ If `x` does not support metadata for column `col` throw `ArgumentError`. If `x` supports metadata, but does not have a mapping for column `col` for `key` throw `KeyError`. -Passing `key` that is not an `AbstractString` to `colmetadata` -throws `MethodError`. - $COL_INFO If `style=true` return a tuple of metadata value and metadata style. Metadata @@ -379,11 +369,11 @@ col, key)` returns a metadata value. If `x` does not support metadata for column Following the Tables.jl contract `Symbol` and `Int` are always allowed. Passing `col` that is not a column of `x` can either throws an error (this is a preferred behavior if it is possible) or returns `()` (this duality is allowed -as some Tables.jl tables do not have schema). +as some Tables.jl tables do not have a schema). If `col` is not passed return an iterator of `col => colmetadatakeys(x, col)` -pairs for all columns that have metadata. If `x` does not support metadata for -any column return `()`. +pairs for all columns that have metadata. If `x` does not support column +metadata return `()`. """ colmetadatakeys(::Any, ::Int) = () colmetadatakeys(::Any, ::Symbol) = () @@ -396,9 +386,6 @@ Set metadata for table `x` for column `col` for key `key` to have value `value` and style `style`. If `x` does not support setting metadata for column `col` throw `ArgumentError`. -Passing `key` that is not an `AbstractString` to `colmetadata!` -throws `MethodError`. - $COL_INFO $STYLE_INFO From be8102f995e5ef88b3976091f617a4c91838baf4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bogumi=C5=82=20Kami=C5=84ski?= Date: Tue, 2 Aug 2022 14:08:09 +0200 Subject: [PATCH 32/44] Apply suggestions from code review --- src/DataAPI.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/DataAPI.jl b/src/DataAPI.jl index acde04b..d6c6663 100644 --- a/src/DataAPI.jl +++ b/src/DataAPI.jl @@ -367,7 +367,7 @@ col, key)` returns a metadata value. If `x` does not support metadata for column `col` must have a type that is supported by table `x` for column indexing. Following the Tables.jl contract `Symbol` and `Int` are always allowed. Passing -`col` that is not a column of `x` can either throws an error (this is a +`col` that is not a column of `x` either throws an error (this is a preferred behavior if it is possible) or returns `()` (this duality is allowed as some Tables.jl tables do not have a schema). From 435e06298957b8703fee7d8bab9b14c43d9b5299 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bogumi=C5=82=20Kami=C5=84ski?= Date: Wed, 3 Aug 2022 18:05:02 +0200 Subject: [PATCH 33/44] add metadata deletion --- src/DataAPI.jl | 35 ++++++++++++++++++++++++++++++++++- test/runtests.jl | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+), 1 deletion(-) diff --git a/src/DataAPI.jl b/src/DataAPI.jl index d6c6663..cf0736e 100644 --- a/src/DataAPI.jl +++ b/src/DataAPI.jl @@ -337,6 +337,19 @@ $STYLE_INFO metadata!(::T, ::AbstractString, ::Any; style) where {T} = throw(ArgumentError("Objects of type $T do not support setting metadata")) +""" + deletemetadata!(x, [key::AbstractString]) + +Delete metadata for object `x` for key `key` and return `x` +(if metadata for `key` is not present do not perform any action). +If `key` is not passed delete all metadata for object `x`. +If `x` does not support metadata deletion throw `ArgumentError`. +""" +deletemetadata!(::T, ::AbstractString) where {T} = + throw(ArgumentError("Objects of type $T do not support metadata deletion")) +deletemetadata!(::T) where {T} = + throw(ArgumentError("Objects of type $T do not support metadata deletion")) + """ colmetadata(x, col, key::AbstractString; style::Bool=false) @@ -383,7 +396,7 @@ colmetadatakeys(::Any) = () colmetadata!(x, col, key::AbstractString, value; style) Set metadata for table `x` for column `col` for key `key` to have value `value` -and style `style`. +and style `style` and return `x`. If `x` does not support setting metadata for column `col` throw `ArgumentError`. $COL_INFO @@ -395,4 +408,24 @@ colmetadata!(::T, ::Int, ::AbstractString, ::Any; style) where {T} = colmetadata!(::T, ::Symbol, ::AbstractString, ::Any; style) where {T} = throw(ArgumentError("Objects of type $T do not support setting metadata")) +""" + deletecolmetadata!(x, [col], [key::AbstractString]) + +Delete metadata for table `x` for column `col` for key `key` and return `x` +(if metadata for `key` is not present do not perform any action). +If `key` is not passed delete all metadata for table `x` for column `col`. +If only `x` is passed delete all column level metadata for table `x`. +If `x` does not support metadata deletion for column `col` throw `ArgumentError`. +""" +deletecolmetadata!(::T, :Symbol, ::AbstractString) where {T} = + throw(ArgumentError("Objects of type $T do not support metadata deletion")) +deletecolmetadata!(::T, :Int, ::AbstractString) where {T} = + throw(ArgumentError("Objects of type $T do not support metadata deletion")) +deletecolmetadata!(::T, :Symbol) where {T} = + throw(ArgumentError("Objects of type $T do not support metadata deletion")) +deletecolmetadata!(::T, :Int) where {T} = + throw(ArgumentError("Objects of type $T do not support metadata deletion")) +deletecolmetadata!(::T) where {T} = + throw(ArgumentError("Objects of type $T do not support metadata deletion")) + end # module diff --git a/test/runtests.jl b/test/runtests.jl index 29fe0db..929073c 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -32,6 +32,14 @@ function DataAPI.metadata!(x::TestMeta, key::AbstractString, value; style) return x end +function DataAPI.metadata!(x::TestMeta, key::AbstractString, value; style) + x.table[key] = (value, style) + return x +end + +DataAPI.deletemetadata!(x::TestMeta, key::AbstractString) = delete!(x.table, key) +DataAPI.deletemetadata!(x::TestMeta) = empty!(x.table, key) + function DataAPI.colmetadata(x::TestMeta, col::Symbol, key::AbstractString; style::Bool=false) return style ? x.col[col][key] : x.col[col][key][1] end @@ -55,6 +63,25 @@ function DataAPI.colmetadata!(x::TestMeta, col::Symbol, key::AbstractString, val return x end +function DataAPI.deletecolmetadata!(x::TestMeta, col::Symbol, key::AbstractString) + if haskey(x.col, col) + delete!(x.col[col], key) + else + throw(ArgumentError("column $col not found")) + end + return x +end + +function DataAPI.deletecolmetadata!(x::TestMeta, col::Symbol) + if haskey(x.col, col) + delete!(x.col, col) + else + throw(ArgumentError("column $col not found")) + end + return x +end + +DataAPI.deletecolmetadata!(x::TestMeta) = empty!(x.col) @testset "DataAPI" begin @@ -221,11 +248,16 @@ end @testset "metadata" begin @test_throws ArgumentError DataAPI.metadata!(1, "a", 10, style=:none) + @test_throws ArgumentError DataAPI.deletemetadata!(1, "a") + @test_throws ArgumentError DataAPI.deletemetadata!(1) @test_throws ArgumentError DataAPI.metadata(1, "a") @test_throws ArgumentError DataAPI.metadata(1, "a", style=true) @test DataAPI.metadatakeys(1) == () @test_throws ArgumentError DataAPI.colmetadata!(1, :col, "a", 10, style=:none) + @test_throws ArgumentError DataAPI.deletecolmetadata!(1, :col, "a") + @test_throws ArgumentError DataAPI.deletecolmetadata!(1, :col) + @test_throws ArgumentError DataAPI.deletecolmetadata!(1) @test_throws ArgumentError DataAPI.colmetadata(1, :col, "a") @test_throws ArgumentError DataAPI.colmetadata(1, :col, "a", style=true) @test_throws ArgumentError DataAPI.colmetadata!(1, 1, "a", 10, style=:none) @@ -243,6 +275,12 @@ end @test_throws KeyError DataAPI.metadata(tm, "b", style=true) @test DataAPI.metadata(tm, "a") == "100" @test DataAPI.metadata(tm, "a", style=true) == ("100", :note) + DataAPI.deletemetadata!(1, "a") + @test isempty(DataAPI.metadatakeys(tm)) + @test DataAPI.metadata!(tm, "a", "100", style=:note) == tm + DataAPI.deletemetadata!(1) + @test isempty(DataAPI.metadatakeys(tm)) + @test DataAPI.colmetadatakeys(tm) == () @test DataAPI.colmetadatakeys(tm, :col) == () @test DataAPI.colmetadata!(tm, :col, "a", "100", style=:note) == tm @@ -254,6 +292,14 @@ end @test_throws KeyError DataAPI.colmetadata(tm, :col2, "a", style=true) @test DataAPI.colmetadata(tm, :col, "a") == "100" @test DataAPI.colmetadata(tm, :col, "a", style=true) == ("100", :note) + @test DataAPI.deletecolmetadata!(tm, :col, "a") + @test DataAPI.colmetadatakeys(tm, :col) == () + @test DataAPI.colmetadata!(tm, :col, "a", "100", style=:note) == tm + @test DataAPI.deletecolmetadata!(tm, :col) + @test DataAPI.colmetadatakeys(tm, :col) == () + @test DataAPI.colmetadata!(tm, :col, "a", "100", style=:note) == tm + @test DataAPI.deletecolmetadata!(tm) + @test DataAPI.colmetadatakeys(tm) == () end end # @testset "DataAPI" From 56f98b7dbedab4448708e93b94d2f46e0ed38f45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bogumi=C5=82=20Kami=C5=84ski?= Date: Wed, 3 Aug 2022 18:08:38 +0200 Subject: [PATCH 34/44] fix typo --- src/DataAPI.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/DataAPI.jl b/src/DataAPI.jl index cf0736e..16fccca 100644 --- a/src/DataAPI.jl +++ b/src/DataAPI.jl @@ -417,11 +417,11 @@ If `key` is not passed delete all metadata for table `x` for column `col`. If only `x` is passed delete all column level metadata for table `x`. If `x` does not support metadata deletion for column `col` throw `ArgumentError`. """ -deletecolmetadata!(::T, :Symbol, ::AbstractString) where {T} = +deletecolmetadata!(::T, ::Symbol, ::AbstractString) where {T} = throw(ArgumentError("Objects of type $T do not support metadata deletion")) deletecolmetadata!(::T, :Int, ::AbstractString) where {T} = throw(ArgumentError("Objects of type $T do not support metadata deletion")) -deletecolmetadata!(::T, :Symbol) where {T} = +deletecolmetadata!(::T, ::Symbol) where {T} = throw(ArgumentError("Objects of type $T do not support metadata deletion")) deletecolmetadata!(::T, :Int) where {T} = throw(ArgumentError("Objects of type $T do not support metadata deletion")) From b909f0187bc6432be04f0b3c7abfde985d0c72ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bogumi=C5=82=20Kami=C5=84ski?= Date: Wed, 3 Aug 2022 18:10:34 +0200 Subject: [PATCH 35/44] fix another typo --- src/DataAPI.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/DataAPI.jl b/src/DataAPI.jl index 16fccca..12ab111 100644 --- a/src/DataAPI.jl +++ b/src/DataAPI.jl @@ -419,11 +419,11 @@ If `x` does not support metadata deletion for column `col` throw `ArgumentError` """ deletecolmetadata!(::T, ::Symbol, ::AbstractString) where {T} = throw(ArgumentError("Objects of type $T do not support metadata deletion")) -deletecolmetadata!(::T, :Int, ::AbstractString) where {T} = +deletecolmetadata!(::T, ::Int, ::AbstractString) where {T} = throw(ArgumentError("Objects of type $T do not support metadata deletion")) deletecolmetadata!(::T, ::Symbol) where {T} = throw(ArgumentError("Objects of type $T do not support metadata deletion")) -deletecolmetadata!(::T, :Int) where {T} = +deletecolmetadata!(::T, ::Int) where {T} = throw(ArgumentError("Objects of type $T do not support metadata deletion")) deletecolmetadata!(::T) where {T} = throw(ArgumentError("Objects of type $T do not support metadata deletion")) From 3e32920aaecd93ce30cf6db2150f83bc44dfc865 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bogumi=C5=82=20Kami=C5=84ski?= Date: Wed, 3 Aug 2022 18:13:53 +0200 Subject: [PATCH 36/44] fix tests --- test/runtests.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/runtests.jl b/test/runtests.jl index 929073c..4ffe89f 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -275,10 +275,10 @@ end @test_throws KeyError DataAPI.metadata(tm, "b", style=true) @test DataAPI.metadata(tm, "a") == "100" @test DataAPI.metadata(tm, "a", style=true) == ("100", :note) - DataAPI.deletemetadata!(1, "a") + DataAPI.deletemetadata!(tm, "a") @test isempty(DataAPI.metadatakeys(tm)) @test DataAPI.metadata!(tm, "a", "100", style=:note) == tm - DataAPI.deletemetadata!(1) + DataAPI.deletemetadata!(tm) @test isempty(DataAPI.metadatakeys(tm)) @test DataAPI.colmetadatakeys(tm) == () From b2d2636758dc614d863102a6bde3daf3d1cbc448 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bogumi=C5=82=20Kami=C5=84ski?= Date: Wed, 3 Aug 2022 18:17:56 +0200 Subject: [PATCH 37/44] one more fix to tests --- test/runtests.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/runtests.jl b/test/runtests.jl index 4ffe89f..3ad0d6c 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -38,7 +38,7 @@ function DataAPI.metadata!(x::TestMeta, key::AbstractString, value; style) end DataAPI.deletemetadata!(x::TestMeta, key::AbstractString) = delete!(x.table, key) -DataAPI.deletemetadata!(x::TestMeta) = empty!(x.table, key) +DataAPI.deletemetadata!(x::TestMeta) = empty!(x.table) function DataAPI.colmetadata(x::TestMeta, col::Symbol, key::AbstractString; style::Bool=false) return style ? x.col[col][key] : x.col[col][key][1] From a589ceeb5c4d6c02b9a20e95620ebc80a16ec161 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bogumi=C5=82=20Kami=C5=84ski?= Date: Wed, 3 Aug 2022 18:23:30 +0200 Subject: [PATCH 38/44] final test fix --- test/runtests.jl | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/test/runtests.jl b/test/runtests.jl index 3ad0d6c..1133c4b 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -292,14 +292,14 @@ end @test_throws KeyError DataAPI.colmetadata(tm, :col2, "a", style=true) @test DataAPI.colmetadata(tm, :col, "a") == "100" @test DataAPI.colmetadata(tm, :col, "a", style=true) == ("100", :note) - @test DataAPI.deletecolmetadata!(tm, :col, "a") - @test DataAPI.colmetadatakeys(tm, :col) == () + DataAPI.deletecolmetadata!(tm, :col, "a") + @test isempty(DataAPI.colmetadatakeys(tm, :col)) @test DataAPI.colmetadata!(tm, :col, "a", "100", style=:note) == tm - @test DataAPI.deletecolmetadata!(tm, :col) - @test DataAPI.colmetadatakeys(tm, :col) == () + DataAPI.deletecolmetadata!(tm, :col) + @test isempty(DataAPI.colmetadatakeys(tm, :col)) @test DataAPI.colmetadata!(tm, :col, "a", "100", style=:note) == tm - @test DataAPI.deletecolmetadata!(tm) - @test DataAPI.colmetadatakeys(tm) == () + DataAPI.deletecolmetadata!(tm) + @test isempty(DataAPI.colmetadatakeys(tm)) end end # @testset "DataAPI" From c612a12539469c79ccae247b39c4ecadf7540de0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bogumi=C5=82=20Kami=C5=84ski?= Date: Wed, 3 Aug 2022 22:12:54 +0200 Subject: [PATCH 39/44] improve test coverage --- test/runtests.jl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/runtests.jl b/test/runtests.jl index 1133c4b..2a550d9 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -257,6 +257,8 @@ end @test_throws ArgumentError DataAPI.colmetadata!(1, :col, "a", 10, style=:none) @test_throws ArgumentError DataAPI.deletecolmetadata!(1, :col, "a") @test_throws ArgumentError DataAPI.deletecolmetadata!(1, :col) + @test_throws ArgumentError DataAPI.deletecolmetadata!(1, 1, "a") + @test_throws ArgumentError DataAPI.deletecolmetadata!(1, 1) @test_throws ArgumentError DataAPI.deletecolmetadata!(1) @test_throws ArgumentError DataAPI.colmetadata(1, :col, "a") @test_throws ArgumentError DataAPI.colmetadata(1, :col, "a", style=true) From 15303a6763cbd262fe4e4adce4fcfc22d405be20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bogumi=C5=82=20Kami=C5=84ski?= Date: Thu, 4 Aug 2022 16:56:48 +0200 Subject: [PATCH 40/44] add emptymetadata! and emptycolmetadata! --- src/DataAPI.jl | 29 +++++++++++++++++++++-------- test/runtests.jl | 20 ++++++++++---------- 2 files changed, 31 insertions(+), 18 deletions(-) diff --git a/src/DataAPI.jl b/src/DataAPI.jl index 12ab111..c0352bc 100644 --- a/src/DataAPI.jl +++ b/src/DataAPI.jl @@ -338,7 +338,7 @@ metadata!(::T, ::AbstractString, ::Any; style) where {T} = throw(ArgumentError("Objects of type $T do not support setting metadata")) """ - deletemetadata!(x, [key::AbstractString]) + deletemetadata!(x, key::AbstractString) Delete metadata for object `x` for key `key` and return `x` (if metadata for `key` is not present do not perform any action). @@ -347,7 +347,14 @@ If `x` does not support metadata deletion throw `ArgumentError`. """ deletemetadata!(::T, ::AbstractString) where {T} = throw(ArgumentError("Objects of type $T do not support metadata deletion")) -deletemetadata!(::T) where {T} = + +""" + emptymetadata!(x) + +Delete all metadata for object `x`. +If `x` does not support metadata deletion throw `ArgumentError`. +""" +emptymetadata!(::T) where {T} = throw(ArgumentError("Objects of type $T do not support metadata deletion")) """ @@ -409,23 +416,29 @@ colmetadata!(::T, ::Symbol, ::AbstractString, ::Any; style) where {T} = throw(ArgumentError("Objects of type $T do not support setting metadata")) """ - deletecolmetadata!(x, [col], [key::AbstractString]) + deletecolmetadata!(x, col, key::AbstractString) Delete metadata for table `x` for column `col` for key `key` and return `x` (if metadata for `key` is not present do not perform any action). -If `key` is not passed delete all metadata for table `x` for column `col`. -If only `x` is passed delete all column level metadata for table `x`. If `x` does not support metadata deletion for column `col` throw `ArgumentError`. """ deletecolmetadata!(::T, ::Symbol, ::AbstractString) where {T} = throw(ArgumentError("Objects of type $T do not support metadata deletion")) deletecolmetadata!(::T, ::Int, ::AbstractString) where {T} = throw(ArgumentError("Objects of type $T do not support metadata deletion")) -deletecolmetadata!(::T, ::Symbol) where {T} = + +""" + emptycolmetadata!(x, [col]) + +Delete all metadata for table `x` for column `col`. +If `col` is not passed delete all column level metadata for table `x`. +If `x` does not support metadata deletion for column `col` throw `ArgumentError`. +""" +emptycolmetadata!(::T, ::Symbol) where {T} = throw(ArgumentError("Objects of type $T do not support metadata deletion")) -deletecolmetadata!(::T, ::Int) where {T} = +emptycolmetadata!(::T, ::Int) where {T} = throw(ArgumentError("Objects of type $T do not support metadata deletion")) -deletecolmetadata!(::T) where {T} = +emptycolmetadata!(::T) where {T} = throw(ArgumentError("Objects of type $T do not support metadata deletion")) end # module diff --git a/test/runtests.jl b/test/runtests.jl index 2a550d9..d260f18 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -38,7 +38,7 @@ function DataAPI.metadata!(x::TestMeta, key::AbstractString, value; style) end DataAPI.deletemetadata!(x::TestMeta, key::AbstractString) = delete!(x.table, key) -DataAPI.deletemetadata!(x::TestMeta) = empty!(x.table) +DataAPI.emptymetadata!(x::TestMeta) = empty!(x.table) function DataAPI.colmetadata(x::TestMeta, col::Symbol, key::AbstractString; style::Bool=false) return style ? x.col[col][key] : x.col[col][key][1] @@ -72,7 +72,7 @@ function DataAPI.deletecolmetadata!(x::TestMeta, col::Symbol, key::AbstractStrin return x end -function DataAPI.deletecolmetadata!(x::TestMeta, col::Symbol) +function DataAPI.emptycolmetadata!(x::TestMeta, col::Symbol) if haskey(x.col, col) delete!(x.col, col) else @@ -81,7 +81,7 @@ function DataAPI.deletecolmetadata!(x::TestMeta, col::Symbol) return x end -DataAPI.deletecolmetadata!(x::TestMeta) = empty!(x.col) +DataAPI.emptycolmetadata!(x::TestMeta) = empty!(x.col) @testset "DataAPI" begin @@ -249,17 +249,17 @@ end @testset "metadata" begin @test_throws ArgumentError DataAPI.metadata!(1, "a", 10, style=:none) @test_throws ArgumentError DataAPI.deletemetadata!(1, "a") - @test_throws ArgumentError DataAPI.deletemetadata!(1) + @test_throws ArgumentError DataAPI.emptymetadata!(1) @test_throws ArgumentError DataAPI.metadata(1, "a") @test_throws ArgumentError DataAPI.metadata(1, "a", style=true) @test DataAPI.metadatakeys(1) == () @test_throws ArgumentError DataAPI.colmetadata!(1, :col, "a", 10, style=:none) @test_throws ArgumentError DataAPI.deletecolmetadata!(1, :col, "a") - @test_throws ArgumentError DataAPI.deletecolmetadata!(1, :col) + @test_throws ArgumentError DataAPI.emptycolmetadata!(1, :col) @test_throws ArgumentError DataAPI.deletecolmetadata!(1, 1, "a") - @test_throws ArgumentError DataAPI.deletecolmetadata!(1, 1) - @test_throws ArgumentError DataAPI.deletecolmetadata!(1) + @test_throws ArgumentError DataAPI.emptycolmetadata!(1, 1) + @test_throws ArgumentError DataAPI.emptycolmetadata!(1) @test_throws ArgumentError DataAPI.colmetadata(1, :col, "a") @test_throws ArgumentError DataAPI.colmetadata(1, :col, "a", style=true) @test_throws ArgumentError DataAPI.colmetadata!(1, 1, "a", 10, style=:none) @@ -280,7 +280,7 @@ end DataAPI.deletemetadata!(tm, "a") @test isempty(DataAPI.metadatakeys(tm)) @test DataAPI.metadata!(tm, "a", "100", style=:note) == tm - DataAPI.deletemetadata!(tm) + DataAPI.emptymetadata!(tm) @test isempty(DataAPI.metadatakeys(tm)) @test DataAPI.colmetadatakeys(tm) == () @@ -297,10 +297,10 @@ end DataAPI.deletecolmetadata!(tm, :col, "a") @test isempty(DataAPI.colmetadatakeys(tm, :col)) @test DataAPI.colmetadata!(tm, :col, "a", "100", style=:note) == tm - DataAPI.deletecolmetadata!(tm, :col) + DataAPI.emptycolmetadata!(tm, :col) @test isempty(DataAPI.colmetadatakeys(tm, :col)) @test DataAPI.colmetadata!(tm, :col, "a", "100", style=:note) == tm - DataAPI.deletecolmetadata!(tm) + DataAPI.emptycolmetadata!(tm) @test isempty(DataAPI.colmetadatakeys(tm)) end From 3b61e3298d9079bbe766c54c99791f61531a66a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bogumi=C5=82=20Kami=C5=84ski?= Date: Sat, 6 Aug 2022 17:35:05 +0200 Subject: [PATCH 41/44] Update src/DataAPI.jl --- src/DataAPI.jl | 1 - 1 file changed, 1 deletion(-) diff --git a/src/DataAPI.jl b/src/DataAPI.jl index c0352bc..fd1e4bb 100644 --- a/src/DataAPI.jl +++ b/src/DataAPI.jl @@ -342,7 +342,6 @@ metadata!(::T, ::AbstractString, ::Any; style) where {T} = Delete metadata for object `x` for key `key` and return `x` (if metadata for `key` is not present do not perform any action). -If `key` is not passed delete all metadata for object `x`. If `x` does not support metadata deletion throw `ArgumentError`. """ deletemetadata!(::T, ::AbstractString) where {T} = From edfd35091ffd856d093d65ce6fb12e3c391bec9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bogumi=C5=82=20Kami=C5=84ski?= Date: Sun, 7 Aug 2022 10:19:15 +0200 Subject: [PATCH 42/44] Update src/DataAPI.jl --- src/DataAPI.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/DataAPI.jl b/src/DataAPI.jl index fd1e4bb..c27ccf9 100644 --- a/src/DataAPI.jl +++ b/src/DataAPI.jl @@ -391,8 +391,8 @@ preferred behavior if it is possible) or returns `()` (this duality is allowed as some Tables.jl tables do not have a schema). If `col` is not passed return an iterator of `col => colmetadatakeys(x, col)` -pairs for all columns that have metadata. If `x` does not support column -metadata return `()`. +pairs for all columns that have metadata, where `col` are `Symbol`. +If `x` does not support column metadata return `()`. """ colmetadatakeys(::Any, ::Int) = () colmetadatakeys(::Any, ::Symbol) = () From b33b62eb012cb1bbdfbf5825735790f656c2f222 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bogumi=C5=82=20Kami=C5=84ski?= Date: Tue, 30 Aug 2022 19:46:32 +0200 Subject: [PATCH 43/44] make :none style more precise --- src/DataAPI.jl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/DataAPI.jl b/src/DataAPI.jl index c27ccf9..da542f1 100644 --- a/src/DataAPI.jl +++ b/src/DataAPI.jl @@ -291,7 +291,8 @@ const STYLE_INFO = """ One of the uses of the metadata `style` is decision how the metadata should be propagated when `x` is transformed. This interface defines the `:none` style that indicates that metadata should not be propagated -under transformations. All types supporting metadata allow at least this style. +under any operations (it is only preserved when a copy of the source table is +performed). All types supporting metadata allow at least this style. """ const COL_INFO = """ From c5f699ee8d38ebf5e34624418b8260260b21668c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bogumi=C5=82=20Kami=C5=84ski?= Date: Sat, 17 Sep 2022 23:01:26 +0200 Subject: [PATCH 44/44] change :none to :default --- src/DataAPI.jl | 2 +- test/runtests.jl | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/DataAPI.jl b/src/DataAPI.jl index da542f1..2697413 100644 --- a/src/DataAPI.jl +++ b/src/DataAPI.jl @@ -290,7 +290,7 @@ function allcombinations end const STYLE_INFO = """ One of the uses of the metadata `style` is decision how the metadata should be propagated when `x` is transformed. This interface -defines the `:none` style that indicates that metadata should not be propagated +defines the `:default` style that indicates that metadata should not be propagated under any operations (it is only preserved when a copy of the source table is performed). All types supporting metadata allow at least this style. """ diff --git a/test/runtests.jl b/test/runtests.jl index d260f18..c8384de 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -247,14 +247,14 @@ end end @testset "metadata" begin - @test_throws ArgumentError DataAPI.metadata!(1, "a", 10, style=:none) + @test_throws ArgumentError DataAPI.metadata!(1, "a", 10, style=:default) @test_throws ArgumentError DataAPI.deletemetadata!(1, "a") @test_throws ArgumentError DataAPI.emptymetadata!(1) @test_throws ArgumentError DataAPI.metadata(1, "a") @test_throws ArgumentError DataAPI.metadata(1, "a", style=true) @test DataAPI.metadatakeys(1) == () - @test_throws ArgumentError DataAPI.colmetadata!(1, :col, "a", 10, style=:none) + @test_throws ArgumentError DataAPI.colmetadata!(1, :col, "a", 10, style=:default) @test_throws ArgumentError DataAPI.deletecolmetadata!(1, :col, "a") @test_throws ArgumentError DataAPI.emptycolmetadata!(1, :col) @test_throws ArgumentError DataAPI.deletecolmetadata!(1, 1, "a") @@ -262,7 +262,7 @@ end @test_throws ArgumentError DataAPI.emptycolmetadata!(1) @test_throws ArgumentError DataAPI.colmetadata(1, :col, "a") @test_throws ArgumentError DataAPI.colmetadata(1, :col, "a", style=true) - @test_throws ArgumentError DataAPI.colmetadata!(1, 1, "a", 10, style=:none) + @test_throws ArgumentError DataAPI.colmetadata!(1, 1, "a", 10, style=:default) @test_throws ArgumentError DataAPI.colmetadata(1, 1, "a") @test_throws ArgumentError DataAPI.colmetadata(1, 1, "a", style=true) @test DataAPI.colmetadatakeys(1, :col) == ()