642 lines
21 KiB
Python
642 lines
21 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). ┃
|
|
# ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
|
|
|
from datetime import date, datetime
|
|
import perspective
|
|
from pytest import mark, raises
|
|
import pytest
|
|
import perspective as psp
|
|
|
|
client = psp.Server().new_local_client()
|
|
Table = client.table
|
|
|
|
|
|
class TestTable:
|
|
# table constructors
|
|
|
|
@mark.skip
|
|
def test_empty_table(self):
|
|
tbl = Table([])
|
|
assert tbl.size() == 0
|
|
|
|
def test_table_not_iterable(self):
|
|
data = {"a": 1}
|
|
with raises(TypeError):
|
|
Table(data)
|
|
|
|
# def test_table_synchronous_process(self):
|
|
# tbl = Table({"a": [1, 2, 3]})
|
|
# assert _PerspectiveStateManager.TO_PROCESS == {}
|
|
# tbl.update({"a": [4, 5, 6]})
|
|
# assert _PerspectiveStateManager.TO_PROCESS == {}
|
|
|
|
def test_table_csv(self):
|
|
data = "x,y,z\n1,a,true\n2,b,false\n3,c,true\n4,d,false"
|
|
tbl = Table(data)
|
|
assert tbl.schema() == {"x": "integer", "y": "string", "z": "boolean"}
|
|
view = tbl.view()
|
|
assert view.to_columns() == {
|
|
"x": [1, 2, 3, 4],
|
|
"y": ["a", "b", "c", "d"],
|
|
"z": [True, False, True, False],
|
|
}
|
|
|
|
def test_table_csv_with_nulls(self):
|
|
tbl = Table("x,y\n1,")
|
|
assert tbl.schema() == {"x": "integer", "y": "string"}
|
|
view = tbl.view()
|
|
assert view.to_columns() == {"x": [1], "y": [None]}
|
|
|
|
def test_table_csv_with_nulls_updated(self):
|
|
tbl = Table("x,y\n1,", index="x")
|
|
assert tbl.schema() == {"x": "integer", "y": "string"}
|
|
view = tbl.view()
|
|
assert view.to_columns() == {"x": [1], "y": [None]}
|
|
tbl.update("x,y\n1,abc\n2,123")
|
|
assert view.to_columns() == {"x": [1, 2], "y": ["abc", "123"]}
|
|
|
|
def test_table_correct_csv_nan_end(self):
|
|
tbl = Table("string,integer\n,1\n,2\nabc,3")
|
|
assert tbl.schema() == {"string": "string", "integer": "integer"}
|
|
assert tbl.size() == 3
|
|
assert tbl.view().to_columns() == {
|
|
"string": ["", "", "abc"],
|
|
"integer": [1, 2, 3],
|
|
}
|
|
|
|
def test_table_correct_csv_nan_intermittent(self):
|
|
tbl = Table("string,float\nabc,\n,2.5\nghi,")
|
|
assert tbl.schema() == {"string": "string", "float": "float"}
|
|
assert tbl.size() == 3
|
|
assert tbl.view().to_columns() == {
|
|
"string": ["abc", "", "ghi"],
|
|
"float": [None, 2.5, None],
|
|
}
|
|
|
|
def test_table_records_from_string_with_format_override(self):
|
|
data = '{"x": [1,2,3], "y": [4,5,6]}'
|
|
tbl = Table(data, format="columns")
|
|
view = tbl.view()
|
|
assert view.to_columns() == {
|
|
"x": [1, 2, 3],
|
|
"y": [4, 5, 6],
|
|
}
|
|
|
|
def test_table_string_column_with_nulls_update_and_filter(self):
|
|
tbl = Table(
|
|
[
|
|
{"a": "1", "b": 2, "c": "3"},
|
|
{"a": "2", "b": 3, "c": "4"},
|
|
{"a": "3", "b": 3, "c": None},
|
|
],
|
|
index="a",
|
|
)
|
|
view = tbl.view(filter=[["c", "==", "4"]])
|
|
records = view.to_records()
|
|
tbl.update([{"a": "4", "b": 10}])
|
|
assert records == view.to_records()
|
|
|
|
def test_table_int(self):
|
|
data = [{"a": 1, "b": 2}, {"a": 3, "b": 4}]
|
|
tbl = Table(data)
|
|
assert tbl.size() == 2
|
|
assert tbl.schema() == {"a": "integer", "b": "integer"}
|
|
|
|
def test_table_int_column_names(self):
|
|
data = {"a": [1, 2, 3], 0: [4, 5, 6]}
|
|
Table(data)
|
|
|
|
def test_table_nones(self):
|
|
none_data = [{"a": 1, "b": None}, {"a": None, "b": 2}]
|
|
tbl = Table(none_data)
|
|
assert tbl.size() == 2
|
|
assert tbl.schema() == {"a": "integer", "b": "integer"}
|
|
|
|
def test_table_bool(self):
|
|
bool_data = [{"a": True, "b": False}, {"a": True, "b": True}]
|
|
tbl = Table(bool_data)
|
|
assert tbl.size() == 2
|
|
assert tbl.schema() == {"a": "boolean", "b": "boolean"}
|
|
|
|
def test_table_bool_str(self):
|
|
bool_data = [{"a": "True", "b": "False"}, {"a": "True", "b": "True"}]
|
|
tbl = Table(bool_data)
|
|
assert tbl.size() == 2
|
|
assert tbl.schema() == {"a": "boolean", "b": "boolean"}
|
|
assert tbl.view().to_columns() == {"a": [True, True], "b": [False, True]}
|
|
|
|
def test_table_float(self):
|
|
float_data = [{"a": 1.5, "b": 2.5}, {"a": 3.2, "b": 3.1}]
|
|
tbl = Table(float_data)
|
|
assert tbl.size() == 2
|
|
assert tbl.schema() == {"a": "float", "b": "float"}
|
|
|
|
def test_table_str(self):
|
|
str_data = [{"a": "b", "b": "b"}, {"a": "3", "b": "3"}]
|
|
tbl = Table(str_data)
|
|
assert tbl.size() == 2
|
|
assert tbl.schema() == {"a": "string", "b": "string"}
|
|
|
|
def test_table_str_with_escape(self):
|
|
str_data = [
|
|
{"a": 'abc"def"', "b": 'abc"def"'},
|
|
{"a": "abc'def'", "b": "abc'def'"},
|
|
]
|
|
tbl = Table(str_data)
|
|
assert tbl.size() == 2
|
|
assert tbl.schema() == {"a": "string", "b": "string"}
|
|
assert tbl.view().to_records() == str_data
|
|
|
|
def test_table_str_unicode(self):
|
|
str_data = [{"a": "ȀȁȀȃȀȁȀȃȀȁȀȃȀȁȀȃ", "b": "ЖДфйЖДфйЖДфйЖДфй"}]
|
|
tbl = Table(str_data)
|
|
assert tbl.size() == 1
|
|
assert tbl.schema() == {"a": "string", "b": "string"}
|
|
assert tbl.view().to_records() == str_data
|
|
|
|
def test_table_date(self):
|
|
str_data = [{"a": date.today(), "b": date.today()}]
|
|
tbl = Table(str_data)
|
|
assert tbl.size() == 1
|
|
assert tbl.schema() == {"a": "date", "b": "date"}
|
|
|
|
def test_table_datetime(self):
|
|
str_data = [{"a": datetime.now(), "b": datetime.now()}]
|
|
tbl = Table(str_data)
|
|
assert tbl.size() == 1
|
|
assert tbl.schema() == {"a": "datetime", "b": "datetime"}
|
|
|
|
def test_table_columnar(self):
|
|
data = {"a": [1, 2, 3], "b": [4, 5, 6]}
|
|
tbl = Table(data)
|
|
assert tbl.columns() == ["a", "b"]
|
|
assert tbl.size() == 3
|
|
assert tbl.schema() == {"a": "integer", "b": "integer"}
|
|
|
|
def test_table_columnar_mixed_length(self):
|
|
data = [{"a": 1.5, "b": 2.5}, {"a": 3.2}]
|
|
tbl = Table(data)
|
|
assert tbl.size() == 2
|
|
assert tbl.schema() == {"a": "float", "b": "float"}
|
|
assert tbl.view().to_records() == [{"a": 1.5, "b": 2.5}, {"a": 3.2, "b": None}]
|
|
|
|
# schema
|
|
|
|
def test_table_schema(self):
|
|
data = {
|
|
"a": "integer",
|
|
"b": "float",
|
|
"c": "string",
|
|
"d": "boolean",
|
|
"e": "date",
|
|
"f": "datetime",
|
|
}
|
|
|
|
tbl = Table(data)
|
|
|
|
assert tbl.schema() == {
|
|
"a": "integer",
|
|
"b": "float",
|
|
"c": "string",
|
|
"d": "boolean",
|
|
"e": "date",
|
|
"f": "datetime",
|
|
}
|
|
|
|
def test_table_readable_string_schema(self):
|
|
data = {
|
|
"a": "integer",
|
|
"b": "float",
|
|
"c": "string",
|
|
"d": "boolean",
|
|
"e": "date",
|
|
"f": "datetime",
|
|
}
|
|
|
|
tbl = Table(data)
|
|
|
|
assert tbl.schema() == {
|
|
"a": "integer",
|
|
"b": "float",
|
|
"c": "string",
|
|
"d": "boolean",
|
|
"e": "date",
|
|
"f": "datetime",
|
|
}
|
|
|
|
def test_table_output_readable_schema(self):
|
|
data = {
|
|
"a": "integer",
|
|
"b": "float",
|
|
"c": "string",
|
|
"d": "boolean",
|
|
"e": "date",
|
|
"f": "datetime",
|
|
}
|
|
|
|
tbl = Table(data)
|
|
|
|
assert tbl.schema() == {
|
|
"a": "integer",
|
|
"b": "float",
|
|
"c": "string",
|
|
"d": "boolean",
|
|
"e": "date",
|
|
"f": "datetime",
|
|
}
|
|
|
|
def test_table_mixed_schema(self):
|
|
data = {
|
|
"a": "integer",
|
|
"b": "float",
|
|
"c": "string",
|
|
"d": "boolean",
|
|
"e": "date",
|
|
"f": "datetime",
|
|
}
|
|
|
|
tbl = Table(data)
|
|
|
|
assert tbl.schema() == {
|
|
"a": "integer",
|
|
"b": "float",
|
|
"c": "string",
|
|
"d": "boolean",
|
|
"e": "date",
|
|
"f": "datetime",
|
|
}
|
|
|
|
def test_table_output_string_schema(self):
|
|
data = {
|
|
"a": "integer",
|
|
"b": "float",
|
|
"c": "string",
|
|
"d": "boolean",
|
|
"e": "date",
|
|
"f": "datetime",
|
|
}
|
|
|
|
tbl = Table(data)
|
|
|
|
assert tbl.schema() == {
|
|
"a": "integer",
|
|
"b": "float",
|
|
"c": "string",
|
|
"d": "boolean",
|
|
"e": "date",
|
|
"f": "datetime",
|
|
}
|
|
|
|
def test_table_symmetric_schema(self):
|
|
data = {
|
|
"a": [1, 2, 3],
|
|
"b": [1.5, 2.5, 3.5],
|
|
"c": ["a", "b", "c"],
|
|
"d": [True, False, True],
|
|
"e": [date.today(), date.today(), date.today()],
|
|
"f": [datetime.now(), datetime.now(), datetime.now()],
|
|
}
|
|
|
|
tbl = Table(data)
|
|
schema = tbl.schema()
|
|
|
|
assert schema == {
|
|
"a": "integer",
|
|
"b": "float",
|
|
"c": "string",
|
|
"d": "boolean",
|
|
"e": "date",
|
|
"f": "datetime",
|
|
}
|
|
|
|
tbl2 = Table(schema)
|
|
|
|
assert tbl2.schema() == schema
|
|
|
|
def test_table_symmetric_string_schema(self):
|
|
data = {
|
|
"a": [1, 2, 3],
|
|
"b": [1.5, 2.5, 3.5],
|
|
"c": ["a", "b", "c"],
|
|
"d": [True, False, True],
|
|
"e": [date.today(), date.today(), date.today()],
|
|
"f": [datetime.now(), datetime.now(), datetime.now()],
|
|
}
|
|
|
|
tbl = Table(data)
|
|
schema = tbl.schema()
|
|
|
|
assert schema == {
|
|
"a": "integer",
|
|
"b": "float",
|
|
"c": "string",
|
|
"d": "boolean",
|
|
"e": "date",
|
|
"f": "datetime",
|
|
}
|
|
|
|
tbl2 = Table(schema)
|
|
|
|
assert tbl2.schema() == schema
|
|
|
|
def test_table_python_schema(self):
|
|
data = {
|
|
"a": int,
|
|
"b": float,
|
|
"c": str,
|
|
"d": bool,
|
|
"e": date,
|
|
"f": datetime,
|
|
}
|
|
|
|
tbl = Table(data)
|
|
assert tbl.schema() == {
|
|
"a": "integer",
|
|
"b": "float",
|
|
"c": "string",
|
|
"d": "boolean",
|
|
"e": "date",
|
|
"f": "datetime",
|
|
}
|
|
|
|
# is_valid_filter
|
|
|
|
# def test_table_is_valid_filter_str(self):
|
|
# filter = ["a", "<", 1]
|
|
# data = [{"a": 1, "b": 2}, {"a": 3, "b": 4}]
|
|
# tbl = Table(data)
|
|
# assert tbl.is_valid_filter(filter) is True
|
|
|
|
# def test_table_not_is_valid_filter_str(self):
|
|
# filter = ["a", "<", None]
|
|
# data = [{"a": 1, "b": 2}, {"a": 3, "b": 4}]
|
|
# tbl = Table(data)
|
|
# assert tbl.is_valid_filter(filter) is False
|
|
|
|
# def test_table_is_valid_filter_filter_op(self):
|
|
# filter = ["a", t_filter_op.FILTER_OP_IS_NULL]
|
|
# data = [{"a": 1, "b": 2}, {"a": 3, "b": 4}]
|
|
# tbl = Table(data)
|
|
# assert tbl.is_valid_filter(filter) is True
|
|
|
|
# def test_table_not_is_valid_filter_filter_op(self):
|
|
# filter = ["a", t_filter_op.FILTER_OP_GT, None]
|
|
# data = [{"a": 1, "b": 2}, {"a": 3, "b": 4}]
|
|
# tbl = Table(data)
|
|
# assert tbl.is_valid_filter(filter) is False
|
|
|
|
# def test_table_is_valid_filter_date(self):
|
|
# filter = ["a", t_filter_op.FILTER_OP_GT, date.today()]
|
|
# tbl = Table({"a": "date"})
|
|
# assert tbl.is_valid_filter(filter) is True
|
|
|
|
# def test_table_not_is_valid_filter_date(self):
|
|
# filter = ["a", t_filter_op.FILTER_OP_GT, None]
|
|
# tbl = Table({"a": "date"})
|
|
# assert tbl.is_valid_filter(filter) is False
|
|
|
|
# def test_table_is_valid_filter_datetime(self):
|
|
# filter = ["a", t_filter_op.FILTER_OP_GT, datetime.now()]
|
|
# tbl = Table({"a": "datetime"})
|
|
# assert tbl.is_valid_filter(filter) is True
|
|
|
|
# def test_table_not_is_valid_filter_datetime(self):
|
|
# filter = ["a", t_filter_op.FILTER_OP_GT, None]
|
|
# tbl = Table({"a": "datetime"})
|
|
# assert tbl.is_valid_filter(filter) is False
|
|
|
|
# def test_table_is_valid_filter_datetime_str(self):
|
|
# filter = ["a", t_filter_op.FILTER_OP_GT, "7/11/2019 5:30PM"]
|
|
# tbl = Table({"a": "datetime"})
|
|
# assert tbl.is_valid_filter(filter) is True
|
|
|
|
# def test_table_not_is_valid_filter_datetime_str(self):
|
|
# filter = ["a", t_filter_op.FILTER_OP_GT, None]
|
|
# tbl = Table({"a": "datetime"})
|
|
# assert tbl.is_valid_filter(filter) is False
|
|
|
|
# def test_table_is_valid_filter_ignores_not_in_schema(self):
|
|
# filter = ["not in schema", "<", 1]
|
|
# data = [{"a": 1, "b": 2}, {"a": 3, "b": 4}]
|
|
# tbl = Table(data)
|
|
# assert tbl.is_valid_filter(filter) is True
|
|
|
|
# index
|
|
|
|
def test_table_index(self):
|
|
data = [{"a": 1, "b": 2}, {"a": 1, "b": 4}]
|
|
tbl = Table(data, index="a")
|
|
assert tbl.size() == 1
|
|
assert tbl.view().to_records() == [{"a": 1, "b": 4}]
|
|
|
|
def test_table_index_from_schema(self):
|
|
data = [{"a": 1, "b": 2}, {"a": 1, "b": 4}]
|
|
tbl = Table({"a": "integer", "b": "integer"}, index="a")
|
|
assert tbl.size() == 0
|
|
tbl.update(data)
|
|
assert tbl.view().to_records() == [{"a": 1, "b": 4}]
|
|
|
|
# index with None in column
|
|
|
|
def test_table_index_int_with_none(self):
|
|
tbl = Table({"a": [0, 1, 2, None, None], "b": [4, 3, 2, 1, 0]}, index="a")
|
|
assert tbl.view().to_columns() == {
|
|
"a": [None, 0, 1, 2],
|
|
"b": [0, 4, 3, 2],
|
|
} # second `None` replaces first
|
|
|
|
def test_table_index_float_with_none(self):
|
|
tbl = Table({"a": [0.0, 1.5, 2.5, None, None], "b": [4, 3, 2, 1, 0]}, index="a")
|
|
assert tbl.view().to_columns() == {
|
|
"a": [None, 0, 1.5, 2.5],
|
|
"b": [0, 4, 3, 2],
|
|
} # second `None` replaces first
|
|
|
|
def test_table_index_bool_with_none(self):
|
|
# bools cannot be used as primary key columns
|
|
with raises(perspective.PerspectiveError):
|
|
Table({"a": [True, False, None, True], "b": [4, 3, 2, 1]}, index="a")
|
|
|
|
def test_table_index_date_with_none(self):
|
|
tbl = Table(
|
|
{
|
|
"a": [date(2019, 7, 11), None, date(2019, 3, 12), date(2011, 3, 10)],
|
|
"b": [4, 3, 2, 1],
|
|
},
|
|
index="a",
|
|
)
|
|
|
|
def ts(x):
|
|
return int(datetime.timestamp(x) * 1000)
|
|
|
|
assert tbl.view().to_columns() == {
|
|
"a": [
|
|
None,
|
|
ts(datetime(2011, 3, 10)),
|
|
ts(datetime(2019, 3, 12)),
|
|
ts(datetime(2019, 7, 11)),
|
|
],
|
|
"b": [3, 1, 2, 4],
|
|
}
|
|
|
|
def test_table_index_datetime_with_none(self, util):
|
|
tbl = Table(
|
|
{
|
|
"a": [
|
|
datetime(2019, 7, 11, 15, 30),
|
|
None,
|
|
datetime(2019, 7, 11, 12, 10),
|
|
datetime(2019, 7, 11, 5, 0),
|
|
],
|
|
"b": [4, 3, 2, 1],
|
|
},
|
|
index="a",
|
|
)
|
|
assert tbl.view().to_columns() == {
|
|
"a": [
|
|
None,
|
|
util.to_timestamp(datetime(2019, 7, 11, 5, 0)),
|
|
util.to_timestamp(datetime(2019, 7, 11, 12, 10)),
|
|
util.to_timestamp(datetime(2019, 7, 11, 15, 30)),
|
|
],
|
|
"b": [3, 1, 2, 4],
|
|
}
|
|
|
|
def test_table_index_str_with_none(self):
|
|
tbl = Table({"a": ["", "a", None, "b"], "b": [4, 3, 2, 1]}, index="a")
|
|
assert tbl.view().to_columns() == {"a": [None, "", "a", "b"], "b": [2, 4, 3, 1]}
|
|
|
|
def test_table_get_index(self):
|
|
tbl = Table({"a": ["", "a", None, "b"], "b": [4, 3, 2, 1]}, index="a")
|
|
assert tbl.get_index() == "a"
|
|
|
|
def test_table_get_index_none(self):
|
|
tbl = Table({"a": ["", "a", None, "b"], "b": [4, 3, 2, 1]})
|
|
assert tbl.get_index() is None
|
|
|
|
# limit
|
|
|
|
def test_table_limit(self):
|
|
data = [{"a": 1, "b": 2}, {"a": 3, "b": 4}]
|
|
tbl = Table(data, limit=1)
|
|
assert tbl.size() == 1
|
|
assert tbl.view().to_records() == [{"a": 3, "b": 4}]
|
|
|
|
def test_table_get_limit(self):
|
|
data = [{"a": 1, "b": 2}, {"a": 3, "b": 4}]
|
|
tbl = Table(data, limit=1)
|
|
assert tbl.get_limit() == 1
|
|
|
|
def test_table_get_limit_none(self):
|
|
data = [{"a": 1, "b": 2}, {"a": 3, "b": 4}]
|
|
tbl = Table(data)
|
|
assert tbl.get_limit() is None
|
|
|
|
# num_views
|
|
|
|
@pytest.mark.skip
|
|
def test_table_get_num_views(self):
|
|
data = [{"a": 1, "b": 2}, {"a": 3, "b": 4}]
|
|
tbl = Table(data)
|
|
assert tbl.get_num_views() == 0
|
|
v1 = tbl.view()
|
|
v2 = tbl.view()
|
|
v3 = tbl.view()
|
|
assert tbl.get_num_views() == 3
|
|
|
|
v1.delete()
|
|
v2.delete()
|
|
assert tbl.get_num_views() == 1
|
|
failed = False
|
|
try:
|
|
tbl.delete()
|
|
except perspective.PerspectiveError:
|
|
failed = True
|
|
assert failed
|
|
v3.delete()
|
|
assert tbl.get_num_views() == 0
|
|
tbl.delete()
|
|
|
|
# clear
|
|
|
|
def test_table_clear(self):
|
|
data = [{"a": 1, "b": 2}, {"a": 3, "b": 4}]
|
|
tbl = Table(data)
|
|
tbl.clear()
|
|
view = tbl.view()
|
|
assert view.to_records() == []
|
|
|
|
# replace
|
|
|
|
def test_table_replace(self):
|
|
data = [{"a": 1, "b": 2}, {"a": 3, "b": 4}]
|
|
data2 = [{"a": 3, "b": 4}, {"a": 1, "b": 2}]
|
|
tbl = Table(data)
|
|
tbl.replace(data2)
|
|
assert tbl.view().to_records() == data2
|
|
|
|
def test_table_replace_views_should_preserve(self):
|
|
data = [{"a": 1, "b": 2}, {"a": 3, "b": 4}]
|
|
data2 = [{"a": 3, "b": 4}, {"a": 1, "b": 2}]
|
|
tbl = Table(data)
|
|
view = tbl.view(group_by=["a"], split_by=["b"])
|
|
first = view.to_records()
|
|
tbl.replace(data2)
|
|
assert view.to_records() == first
|
|
|
|
def test_table_replace_should_fire_on_update(self, sentinel):
|
|
data = [{"a": 1, "b": 2}, {"a": 3, "b": 4}]
|
|
data2 = [{"a": 3, "b": 4}, {"a": 1, "b": 2}]
|
|
tbl = Table(data)
|
|
view = tbl.view()
|
|
|
|
s = sentinel(False)
|
|
|
|
def updater(port_id):
|
|
s.set(True)
|
|
|
|
view.on_update(updater)
|
|
tbl.replace(data2)
|
|
tbl.size()
|
|
assert s.get()
|
|
|
|
def test_table_replace_should_fire_on_update_with_delta(self, sentinel):
|
|
data = [{"a": 1, "b": 2}, {"a": 3, "b": 4}]
|
|
data2 = [{"a": 3, "b": 4}, {"a": 1, "b": 2}]
|
|
tbl = Table(data)
|
|
view = tbl.view()
|
|
|
|
s = sentinel(False)
|
|
|
|
def updater(port_id, delta):
|
|
# assert port_id == 0
|
|
table2 = Table(delta)
|
|
assert table2.view().to_records() == data2
|
|
s.set(True)
|
|
|
|
view.on_update(updater, mode="row")
|
|
tbl.replace(data2)
|
|
tbl.size()
|
|
assert s.get() is True
|
|
|
|
def test_float32_table_construction(self):
|
|
float_data = [{"a": 1.5, "b": 2.5}, {"a": 3.2, "b": 3.1}]
|
|
tbl = Table(float_data, index="a")
|
|
assert tbl.size() == 2
|
|
assert tbl.schema() == {"a": "float", "b": "float"}
|
|
|
|
|
|
if __name__ == "__main__":
|
|
import pytest
|
|
|
|
pytest.main(["-vv", "-s", __file__])
|