418 lines
16 KiB
Python
418 lines
16 KiB
Python
# ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
|
|
# ┃ ██████ ██████ ██████ █ █ █ █ █ █▄ ▀███ █ ┃
|
|
# ┃ ▄▄▄▄▄█ █▄▄▄▄▄ ▄▄▄▄▄█ ▀▀▀▀▀█▀▀▀▀▀ █ ▀▀▀▀▀█ ████████▌▐███ ███▄ ▀█ █ ▀▀▀▀▀ ┃
|
|
# ┃ █▀▀▀▀▀ █▀▀▀▀▀ █▀██▀▀ ▄▄▄▄▄ █ ▄▄▄▄▄█ ▄▄▄▄▄█ ████████▌▐███ █████▄ █ ▄▄▄▄▄ ┃
|
|
# ┃ █ ██████ █ ▀█▄ █ ██████ █ ███▌▐███ ███████▄ █ ┃
|
|
# ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
|
|
# ┃ Copyright (c) 2017, the Perspective Authors. ┃
|
|
# ┃ ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ ┃
|
|
# ┃ This file is part of the Perspective library, distributed under the terms ┃
|
|
# ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
|
|
# ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
|
|
|
import pyarrow as pa
|
|
from datetime import date, datetime
|
|
import perspective as psp
|
|
|
|
client = psp.Server().new_local_client()
|
|
Table = client.table
|
|
|
|
|
|
class TestToArrow(object):
|
|
def test_to_arrow_nones_symmetric(self):
|
|
data = {"a": [None, 1, None, 2, 3], "b": [1.5, 2.5, None, 3.5, None]}
|
|
tbl = Table(data)
|
|
assert tbl.schema() == {"a": "integer", "b": "float"}
|
|
arr = tbl.view().to_arrow()
|
|
tbl2 = Table(arr)
|
|
assert tbl2.view().to_columns() == data
|
|
|
|
def test_to_arrow_big_numbers_symmetric(self):
|
|
data = {
|
|
"a": [1, 2, 3, 4],
|
|
"b": [
|
|
1.7976931348623157e308,
|
|
1.7976931348623157e308,
|
|
1.7976931348623157e308,
|
|
1.7976931348623157e308,
|
|
],
|
|
}
|
|
tbl = Table(data)
|
|
assert tbl.schema() == {"a": "integer", "b": "float"}
|
|
arr = tbl.view().to_arrow()
|
|
tbl2 = Table(arr)
|
|
assert tbl2.view().to_columns() == data
|
|
|
|
def test_to_arrow_boolean_symmetric(self):
|
|
data = {"a": [True, False, None, False, True, None]}
|
|
tbl = Table(data)
|
|
assert tbl.schema() == {"a": "boolean"}
|
|
arr = tbl.view().to_arrow()
|
|
tbl2 = Table(arr)
|
|
assert tbl2.view().to_columns() == data
|
|
|
|
def test_to_arrow_str_symmetric(self):
|
|
data = {"a": ["a", "b", "c", "d", "e", None]}
|
|
tbl = Table(data)
|
|
assert tbl.schema() == {"a": "string"}
|
|
arr = tbl.view().to_arrow()
|
|
tbl2 = Table(arr)
|
|
assert tbl2.view().to_columns() == data
|
|
|
|
def test_to_arrow_str_dict(self):
|
|
data = {
|
|
"a": ["abcdefg", "abcdefg", "h"],
|
|
"b": ["aaa", "bbb", "bbb"],
|
|
"c": ["hello", "world", "world"],
|
|
}
|
|
tbl = Table(data)
|
|
assert tbl.schema() == {"a": "string", "b": "string", "c": "string"}
|
|
arr = tbl.view().to_arrow()
|
|
|
|
# assert that we are actually generating dict arrays
|
|
buf = pa.BufferReader(arr)
|
|
reader = pa.ipc.open_stream(buf)
|
|
arrow_table = reader.read_all()
|
|
arrow_schema = arrow_table.schema
|
|
|
|
for name in ("a", "b", "c"):
|
|
arrow_type = arrow_schema.field(name).type
|
|
assert pa.types.is_dictionary(arrow_type)
|
|
|
|
# assert that data is symmetrical
|
|
tbl2 = Table(arr)
|
|
assert tbl2.view().to_columns() == data
|
|
|
|
def test_to_arrow_date_symmetric(self):
|
|
# data = {"a": [date(2019, 7, 11), date(2016, 2, 29), date(2019, 12, 10)]}
|
|
# tbl = Table(data)
|
|
tbl = Table({"a": "date"})
|
|
# data = {"a": map(lambda x: x.getTime(), [date(2019, 7, 11), date(2016, 2, 29), date(2019, 12, 10)])}
|
|
data = {"a": [date(2019, 7, 11), date(2016, 2, 29), date(2019, 12, 10)]}
|
|
tbl.update(data)
|
|
assert tbl.schema() == {"a": "date"}
|
|
arr = tbl.view().to_arrow()
|
|
tbl2 = Table(arr)
|
|
|
|
def ts(x):
|
|
return int(datetime.timestamp(x) * 1000)
|
|
|
|
assert tbl2.schema() == tbl.schema()
|
|
assert tbl2.view().to_columns() == {
|
|
"a": [
|
|
ts(datetime(2019, 7, 11)),
|
|
ts(datetime(2016, 2, 29)),
|
|
ts(datetime(2019, 12, 10)),
|
|
]
|
|
}
|
|
|
|
def test_to_arrow_date_symmetric_january(self, util):
|
|
data = {"a": [date(2019, 1, 1), date(2016, 1, 1), date(2019, 1, 1)]}
|
|
tbl = Table(data)
|
|
assert tbl.schema() == {"a": "date"}
|
|
arr = tbl.view().to_arrow()
|
|
tbl2 = Table(arr)
|
|
assert tbl2.schema() == tbl.schema()
|
|
assert tbl2.view().to_columns() == {
|
|
"a": [
|
|
util.to_timestamp(x)
|
|
for x in [
|
|
datetime(2019, 1, 1),
|
|
datetime(2016, 1, 1),
|
|
datetime(2019, 1, 1),
|
|
]
|
|
]
|
|
}
|
|
|
|
def test_to_arrow_datetime_symmetric(self, util):
|
|
data = {
|
|
"a": [
|
|
datetime(2019, 7, 11, 12, 30),
|
|
datetime(2016, 2, 29, 11, 0),
|
|
datetime(2019, 12, 10, 12, 0),
|
|
]
|
|
}
|
|
tbl = Table(data)
|
|
assert tbl.schema() == {"a": "datetime"}
|
|
arr = tbl.view().to_arrow()
|
|
tbl2 = Table(arr)
|
|
assert tbl2.schema() == tbl.schema()
|
|
assert tbl2.view().to_columns() == {
|
|
"a": [
|
|
util.to_timestamp(x)
|
|
for x in [
|
|
datetime(2019, 7, 11, 12, 30),
|
|
datetime(2016, 2, 29, 11, 0),
|
|
datetime(2019, 12, 10, 12, 0),
|
|
]
|
|
]
|
|
}
|
|
|
|
def test_to_arrow_one_symmetric(self):
|
|
data = {
|
|
"a": [1, 2, 3, 4],
|
|
"b": ["a", "b", "c", "d"],
|
|
"c": [
|
|
datetime(2019, 7, 11, 12, 0),
|
|
datetime(2019, 7, 11, 12, 10),
|
|
datetime(2019, 7, 11, 12, 20),
|
|
datetime(2019, 7, 11, 12, 30),
|
|
],
|
|
}
|
|
tbl = Table(data)
|
|
view = tbl.view(group_by=["a"])
|
|
arrow = view.to_arrow()
|
|
tbl2 = Table(arrow)
|
|
assert tbl2.schema() == {
|
|
"a (Group by 1)": "integer",
|
|
"a": "integer",
|
|
"b": "integer",
|
|
"c": "integer",
|
|
}
|
|
d = view.to_columns()
|
|
d["a (Group by 1)"] = [
|
|
x[0] if len(x) > 0 else None for x in d.pop("__ROW_PATH__")
|
|
]
|
|
assert tbl2.view().to_columns() == d
|
|
|
|
def test_to_arrow_two_symmetric(self):
|
|
data = {
|
|
"a": [1, 2, 3, 4],
|
|
"b": ["hello", "world", "hello2", "world2"],
|
|
"c": [datetime(2019, 7, 11, 12, i) for i in range(0, 40, 10)],
|
|
}
|
|
tbl = Table(data)
|
|
view = tbl.view(group_by=["a"], split_by=["b"])
|
|
arrow = view.to_arrow()
|
|
tbl2 = Table(arrow)
|
|
assert tbl2.schema() == {
|
|
"a (Group by 1)": "integer",
|
|
"hello|a": "integer",
|
|
"hello|b": "integer",
|
|
"hello|c": "integer",
|
|
"world|a": "integer",
|
|
"world|b": "integer",
|
|
"world|c": "integer",
|
|
"hello2|a": "integer",
|
|
"hello2|b": "integer",
|
|
"hello2|c": "integer",
|
|
"world2|a": "integer",
|
|
"world2|b": "integer",
|
|
"world2|c": "integer",
|
|
}
|
|
d = view.to_columns()
|
|
d["a (Group by 1)"] = [
|
|
x[0] if len(x) > 0 else None for x in d.pop("__ROW_PATH__")
|
|
]
|
|
assert tbl2.view().to_columns() == d
|
|
|
|
def test_to_arrow_column_only_symmetric(self):
|
|
data = {
|
|
"a": [1, 2, 3, 4],
|
|
"b": ["a", "b", "c", "d"],
|
|
"c": [datetime(2019, 7, 11, 12, i) for i in range(0, 40, 10)],
|
|
}
|
|
tbl = Table(data)
|
|
view = tbl.view(split_by=["a"])
|
|
arrow = view.to_arrow()
|
|
tbl2 = Table(arrow)
|
|
assert tbl2.schema() == {
|
|
"1|a": "integer",
|
|
"1|b": "string",
|
|
"1|c": "datetime",
|
|
"2|a": "integer",
|
|
"2|b": "string",
|
|
"2|c": "datetime",
|
|
"3|a": "integer",
|
|
"3|b": "string",
|
|
"3|c": "datetime",
|
|
"4|a": "integer",
|
|
"4|b": "string",
|
|
"4|c": "datetime",
|
|
}
|
|
d = view.to_columns()
|
|
assert tbl2.view().to_columns() == d
|
|
|
|
# start and end row
|
|
def test_to_arrow_start_row(self):
|
|
data = {"a": [None, 1, None, 2, 3], "b": [1.5, 2.5, None, 3.5, None]}
|
|
tbl = Table(data)
|
|
assert tbl.schema() == {"a": "integer", "b": "float"}
|
|
arr = tbl.view().to_arrow(start_row=3)
|
|
tbl2 = Table(arr)
|
|
assert tbl2.view().to_columns() == {"a": data["a"][3:], "b": data["b"][3:]}
|
|
|
|
def test_to_arrow_end_row(self):
|
|
data = {"a": [None, 1, None, 2, 3], "b": [1.5, 2.5, None, 3.5, None]}
|
|
tbl = Table(data)
|
|
assert tbl.schema() == {"a": "integer", "b": "float"}
|
|
arr = tbl.view().to_arrow(end_row=2)
|
|
tbl2 = Table(arr)
|
|
assert tbl2.view().to_columns() == {"a": data["a"][:2], "b": data["b"][:2]}
|
|
|
|
def test_to_arrow_start_end_row(self):
|
|
data = {"a": [None, 1, None, 2, 3], "b": [1.5, 2.5, None, 3.5, None]}
|
|
tbl = Table(data)
|
|
assert tbl.schema() == {"a": "integer", "b": "float"}
|
|
arr = tbl.view().to_arrow(start_row=2, end_row=3)
|
|
tbl2 = Table(arr)
|
|
assert tbl2.view().to_columns() == {"a": data["a"][2:3], "b": data["b"][2:3]}
|
|
|
|
def test_to_arrow_start_end_row_equiv(self):
|
|
data = {"a": [None, 1, None, 2, 3], "b": [1.5, 2.5, None, 3.5, None]}
|
|
tbl = Table(data)
|
|
assert tbl.schema() == {"a": "integer", "b": "float"}
|
|
arr = tbl.view().to_arrow(start_row=2, end_row=2)
|
|
tbl2 = Table(arr)
|
|
assert tbl2.view().to_columns() == {"a": [], "b": []}
|
|
|
|
def test_to_arrow_start_row_invalid(self):
|
|
data = {"a": [None, 1, None, 2, 3], "b": [1.5, 2.5, None, 3.5, None]}
|
|
tbl = Table(data)
|
|
assert tbl.schema() == {"a": "integer", "b": "float"}
|
|
arr = tbl.view().to_arrow(start_row=-1)
|
|
tbl2 = Table(arr)
|
|
assert tbl2.view().to_columns() == data
|
|
|
|
def test_to_arrow_end_row_invalid(self):
|
|
data = {"a": [None, 1, None, 2, 3], "b": [1.5, 2.5, None, 3.5, None]}
|
|
tbl = Table(data)
|
|
assert tbl.schema() == {"a": "integer", "b": "float"}
|
|
arr = tbl.view().to_arrow(end_row=6)
|
|
tbl2 = Table(arr)
|
|
assert tbl2.view().to_columns() == data
|
|
|
|
def test_to_arrow_start_end_row_invalid(self):
|
|
data = {"a": [None, 1, None, 2, 3], "b": [1.5, 2.5, None, 3.5, None]}
|
|
tbl = Table(data)
|
|
assert tbl.schema() == {"a": "integer", "b": "float"}
|
|
arr = tbl.view().to_arrow(start_row=-1, end_row=6)
|
|
tbl2 = Table(arr)
|
|
assert tbl2.view().to_columns() == data
|
|
|
|
def test_to_arrow_start_col(self):
|
|
data = {"a": [None, 1, None, 2, 3], "b": [1.5, 2.5, None, 3.5, None]}
|
|
tbl = Table(data)
|
|
assert tbl.schema() == {"a": "integer", "b": "float"}
|
|
arr = tbl.view().to_arrow(start_col=1)
|
|
tbl2 = Table(arr)
|
|
assert tbl2.view().to_columns() == {"b": data["b"]}
|
|
|
|
def test_to_arrow_end_col(self):
|
|
data = {"a": [None, 1, None, 2, 3], "b": [1.5, 2.5, None, 3.5, None]}
|
|
tbl = Table(data)
|
|
assert tbl.schema() == {"a": "integer", "b": "float"}
|
|
arr = tbl.view().to_arrow(end_col=1)
|
|
tbl2 = Table(arr)
|
|
assert tbl2.view().to_columns() == {"a": data["a"]}
|
|
|
|
def test_to_arrow_start_end_col(self):
|
|
data = {
|
|
"a": [None, 1, None, 2, 3],
|
|
"b": [1.5, 2.5, None, 3.5, None],
|
|
"c": [None, 1, None, 2, 3],
|
|
"d": [1.5, 2.5, None, 3.5, None],
|
|
}
|
|
tbl = Table(data)
|
|
assert tbl.schema() == {
|
|
"a": "integer",
|
|
"b": "float",
|
|
"c": "integer",
|
|
"d": "float",
|
|
}
|
|
arr = tbl.view().to_arrow(start_col=1, end_col=3)
|
|
tbl2 = Table(arr)
|
|
assert tbl2.view().to_columns() == {"b": data["b"], "c": data["c"]}
|
|
|
|
def test_to_arrow_start_col_invalid(self):
|
|
data = {"a": [None, 1, None, 2, 3], "b": [1.5, 2.5, None, 3.5, None]}
|
|
tbl = Table(data)
|
|
assert tbl.schema() == {"a": "integer", "b": "float"}
|
|
arr = tbl.view().to_arrow(start_col=-1)
|
|
tbl2 = Table(arr)
|
|
assert tbl2.view().to_columns() == data
|
|
|
|
def test_to_arrow_end_col_invalid(self):
|
|
data = {"a": [None, 1, None, 2, 3], "b": [1.5, 2.5, None, 3.5, None]}
|
|
tbl = Table(data)
|
|
assert tbl.schema() == {"a": "integer", "b": "float"}
|
|
arr = tbl.view().to_arrow(end_col=6)
|
|
tbl2 = Table(arr)
|
|
assert tbl2.view().to_columns() == data
|
|
|
|
def test_to_arrow_start_end_col_invalid(self):
|
|
data = {"a": [None, 1, None, 2, 3], "b": [1.5, 2.5, None, 3.5, None]}
|
|
tbl = Table(data)
|
|
assert tbl.schema() == {"a": "integer", "b": "float"}
|
|
arr = tbl.view().to_arrow(start_col=-1, end_col=6)
|
|
tbl2 = Table(arr)
|
|
assert tbl2.view().to_columns() == data
|
|
|
|
def test_to_arrow_start_end_col_equiv_row(self):
|
|
data = {"a": [None, 1, None, 2, 3], "b": [1.5, 2.5, None, 3.5, None]}
|
|
tbl = Table(data)
|
|
assert tbl.schema() == {"a": "integer", "b": "float"}
|
|
arr = tbl.view().to_arrow(start_col=1, end_col=1, start_row=2, end_row=3)
|
|
tbl2 = Table(arr)
|
|
# start/end col is a range - thus start=end provides no columns
|
|
assert tbl2.view().to_columns() == {}
|
|
|
|
def test_to_arrow_start_end_col_equiv(self):
|
|
data = {"a": [None, 1, None, 2, 3], "b": [1.5, 2.5, None, 3.5, None]}
|
|
tbl = Table(data)
|
|
assert tbl.schema() == {"a": "integer", "b": "float"}
|
|
arr = tbl.view().to_arrow(start_col=1, end_col=1)
|
|
tbl2 = Table(arr)
|
|
assert tbl2.view().to_columns() == {}
|
|
|
|
def test_to_arrow_start_end_row_end_col(self):
|
|
data = {"a": [None, 1, None, 2, 3], "b": [1.5, 2.5, None, 3.5, None]}
|
|
tbl = Table(data)
|
|
assert tbl.schema() == {"a": "integer", "b": "float"}
|
|
arr = tbl.view().to_arrow(end_col=1, start_row=2, end_row=3)
|
|
tbl2 = Table(arr)
|
|
assert tbl2.view().to_columns() == tbl.view().to_columns(
|
|
end_col=1, start_row=2, end_row=3
|
|
)
|
|
|
|
def test_to_arrow_start_end_col_start_row(self):
|
|
data = {
|
|
"a": [None, 1, None, 2, 3],
|
|
"b": [1.5, 2.5, None, 3.5, None],
|
|
"c": [1.5, 2.5, None, 4.5, None],
|
|
}
|
|
tbl = Table(data)
|
|
assert tbl.schema() == {"a": "integer", "b": "float", "c": "float"}
|
|
arr = tbl.view().to_arrow(start_col=1, end_col=2, start_row=2)
|
|
tbl2 = Table(arr)
|
|
assert tbl2.view().to_columns() == tbl.view().to_columns(
|
|
start_col=1, end_col=2, start_row=2
|
|
)
|
|
|
|
def test_to_arrow_start_end_col_end_row(self):
|
|
data = {
|
|
"a": [None, 1, None, 2, 3],
|
|
"b": [1.5, 2.5, None, 3.5, None],
|
|
"c": [1.5, 2.5, None, 4.5, None],
|
|
}
|
|
tbl = Table(data)
|
|
assert tbl.schema() == {"a": "integer", "b": "float", "c": "float"}
|
|
arr = tbl.view().to_arrow(start_col=1, end_col=2, end_row=2)
|
|
tbl2 = Table(arr)
|
|
assert tbl2.view().to_columns() == tbl.view().to_columns(
|
|
start_col=1, end_col=2, end_row=2
|
|
)
|
|
|
|
def test_to_arrow_one_mean(self):
|
|
data = {"a": [1, 2, 3, 4], "b": ["a", "a", "b", "b"]}
|
|
|
|
table = Table(data)
|
|
view = table.view(group_by=["b"], columns=["a"], aggregates={"a": "mean"})
|
|
arrow = view.to_arrow()
|
|
|
|
table2 = Table(arrow)
|
|
view2 = table2.view()
|
|
result = view2.to_columns()
|
|
|
|
assert result == {"b (Group by 1)": [None, "a", "b"], "a": [2.5, 1.5, 3.5]}
|