Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ strip = true
# These are only respected when `cargo` is invoked from the project root
[patch.crates-io]
# simd-adler32 = { git = "https://github.com/mcountryman/simd-adler32.git", rev = "b279034d9eb554c3e5e0af523db044f08d8297ba" }
protobuf-src = { rev = "1aba500e469f8bdc384a0fe9e69c189fda72e059", git = "https://github.com/MaterializeInc/rust-protobuf-native" }
perspective-client = { path = "rust/perspective-client" }
perspective-server = { path = "rust/perspective-server" }
perspective-js = { path = "rust/perspective-js" }
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
# ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
# ┃ ██████ ██████ ██████ █ █ █ █ █ █▄ ▀███ █ ┃
# ┃ ▄▄▄▄▄█ █▄▄▄▄▄ ▄▄▄▄▄█ ▀▀▀▀▀█▀▀▀▀▀ █ ▀▀▀▀▀█ ████████▌▐███ ███▄ ▀█ █ ▀▀▀▀▀ ┃
# ┃ █▀▀▀▀▀ █▀▀▀▀▀ █▀██▀▀ ▄▄▄▄▄ █ ▄▄▄▄▄█ ▄▄▄▄▄█ ████████▌▐███ █████▄ █ ▄▄▄▄▄ ┃
# ┃ █ ██████ █ ▀█▄ █ ██████ █ ███▌▐███ ███████▄ █ ┃
# ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
# ┃ 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 pandas as pd
import numpy as np
from perspective import PerspectiveError
from datetime import date, datetime
from pytest import approx, mark, raises

import perspective as psp

client = psp.Server().new_local_client()
Table = client.table


def date_timestamp(date):
return int(datetime.combine(date, datetime.min.time()).timestamp()) * 1000


def compare_delta(received, expected):
"""Compare an arrow-serialized row delta by constructing a Table."""
tbl = Table(received)
assert tbl.view().to_columns() == expected


class TestView(object):
def test_view_zero(self):
data = [{"a": 1, "b": 2}, {"a": 3, "b": 4}]
tbl = Table(data)
view = tbl.view()
tbl2 = Table(view)
view2 = tbl2.view()
dimms = view2.dimensions()
assert dimms["num_view_rows"] == 2
assert dimms["num_view_columns"] == 2
assert view2.schema() == {"a": "integer", "b": "integer"}
assert view2.to_records() == data

def test_view_one(self):
data = [{"a": 1, "b": 2}, {"a": 3, "b": 4}]
tbl = Table(data)
view = tbl.view(group_by=["a"])
tbl2 = Table(view)
view2 = tbl2.view()

dimms = view2.dimensions()
assert dimms["num_view_rows"] == 3
assert dimms["num_view_columns"] == 3
assert view2.schema() == {
"a (Group by 1)": "integer",
"a": "integer",
"b": "integer",
}

assert view2.to_records() == [
{"a (Group by 1)": None, "a": 4, "b": 6},
{"a (Group by 1)": 1, "a": 1, "b": 2},
{"a (Group by 1)": 3, "a": 3, "b": 4},
]

def test_view_two(self):
data = [{"a": 1, "b": 2}, {"a": 3, "b": 4}]
tbl = Table(data)
view = tbl.view(group_by=["a"], split_by=["b"])
tbl2 = Table(view)
view2 = tbl2.view()
dimms = view2.dimensions()
assert dimms["num_view_rows"] == 3
assert dimms["num_view_columns"] == 5
assert view2.schema() == {
"a (Group by 1)": "integer",
"2|a": "integer",
"2|b": "integer",
"4|a": "integer",
"4|b": "integer",
}

assert view2.to_records() == [
{
"a (Group by 1)": None,
"2|a": 1,
"2|b": 2,
"4|a": 3,
"4|b": 4,
},
{
"a (Group by 1)": 1,
"2|a": 1,
"2|b": 2,
"4|a": None,
"4|b": None,
},
{
"a (Group by 1)": 3,
"2|a": None,
"2|b": None,
"4|a": 3,
"4|b": 4,
},
]

def test_view_two_column_only(self):
data = [{"a": 1, "b": 2}, {"a": 3, "b": 4}]
tbl = Table(data)
view = tbl.view(split_by=["b"])
tbl2 = Table(view)
view2 = tbl2.view()
dimms = view2.dimensions()
assert dimms["num_view_rows"] == 2
assert dimms["num_view_columns"] == 4
assert view2.schema() == {
"2|a": "integer",
"2|b": "integer",
"4|a": "integer",
"4|b": "integer",
}

assert view2.to_records() == [
{"2|a": 1, "2|b": 2, "4|a": None, "4|b": None},
{"2|a": None, "2|b": None, "4|a": 3, "4|b": 4},
]
2 changes: 1 addition & 1 deletion rust/perspective-python/src/client/client_async.rs
Original file line number Diff line number Diff line change
Expand Up @@ -627,7 +627,7 @@ impl AsyncTable {
#[pyclass]
#[derive(Clone)]
pub struct AsyncView {
view: Arc<View>,
pub(crate) view: Arc<View>,
_client: AsyncClient,
}

Expand Down
2 changes: 1 addition & 1 deletion rust/perspective-python/src/client/client_sync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -469,7 +469,7 @@ impl Table {
/// Perspective conserves memory by relying on a single [`Table`] to power
/// multiple [`View`]s concurrently.
#[pyclass(subclass, name = "View", module = "perspective")]
pub struct View(AsyncView);
pub struct View(pub(crate) AsyncView);

assert_view_api!(View);

Expand Down
6 changes: 5 additions & 1 deletion rust/perspective-python/src/client/table_data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,11 @@ pub impl TableData {
input: Bound<'_, PyAny>,
format: Option<TableReadFormat>,
) -> Result<TableData, PyErr> {
if let Some(update) = UpdateData::from_py_partial(&input, format)? {
if let Ok(view) = input.downcast::<crate::client::client_async::AsyncView>() {
Ok(TableData::View((*view.borrow().view).clone()))
} else if let Ok(view) = input.downcast::<crate::client::client_sync::View>() {
Ok(TableData::View((*view.borrow().0.view).clone()))
} else if let Some(update) = UpdateData::from_py_partial(&input, format)? {
Ok(TableData::Update(update))
} else if let Ok(pylist) = input.downcast::<PyList>() {
let json_module = PyModule::import(input.py(), "json")?;
Expand Down
Loading