perspective-python 4.2.0__cp311-abi3-win_amd64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- perspective/__init__.py +396 -0
- perspective/extension/finos-perspective-nbextension.json +5 -0
- perspective/handlers/__init__.py +11 -0
- perspective/handlers/aiohttp.py +61 -0
- perspective/handlers/starlette.py +55 -0
- perspective/handlers/tornado.py +184 -0
- perspective/perspective.pyd +0 -0
- perspective/templates/exported_widget.html.template +35 -0
- perspective/tests/__init__.py +11 -0
- perspective/tests/async/test_async_client.py +83 -0
- perspective/tests/async/test_websocket_client.py +124 -0
- perspective/tests/conftest.py +272 -0
- perspective/tests/core/__init__.py +11 -0
- perspective/tests/core/test_async.py +351 -0
- perspective/tests/multi_threaded/__init__.py +11 -0
- perspective/tests/multi_threaded/test_multi_threaded.py +201 -0
- perspective/tests/server/__init__.py +11 -0
- perspective/tests/server/test_server.py +1016 -0
- perspective/tests/server/test_session.py +110 -0
- perspective/tests/table/__init__.py +11 -0
- perspective/tests/table/arrow/date32.arrow +0 -0
- perspective/tests/table/arrow/date64.arrow +0 -0
- perspective/tests/table/arrow/dict.arrow +0 -0
- perspective/tests/table/arrow/dict_update.arrow +0 -0
- perspective/tests/table/arrow/int_float_str.arrow +0 -0
- perspective/tests/table/arrow/int_float_str_file.arrow +0 -0
- perspective/tests/table/arrow/int_float_str_update.arrow +0 -0
- perspective/tests/table/object_sequence.py +402 -0
- perspective/tests/table/test_column_paths.py +89 -0
- perspective/tests/table/test_delete.py +124 -0
- perspective/tests/table/test_exception.py +65 -0
- perspective/tests/table/test_leaks.py +54 -0
- perspective/tests/table/test_ports.py +178 -0
- perspective/tests/table/test_remove.py +102 -0
- perspective/tests/table/test_table.py +641 -0
- perspective/tests/table/test_table_arrow.py +503 -0
- perspective/tests/table/test_table_datetime.py +2409 -0
- perspective/tests/table/test_table_infer.py +201 -0
- perspective/tests/table/test_table_limit.py +45 -0
- perspective/tests/table/test_table_numpy.py +1022 -0
- perspective/tests/table/test_table_pandas.py +1018 -0
- perspective/tests/table/test_table_polars.py +251 -0
- perspective/tests/table/test_table_view_table.py +130 -0
- perspective/tests/table/test_to_arrow.py +417 -0
- perspective/tests/table/test_to_arrow_lz4.py +32 -0
- perspective/tests/table/test_to_format.py +1024 -0
- perspective/tests/table/test_to_polars.py +26 -0
- perspective/tests/table/test_update.py +545 -0
- perspective/tests/table/test_update_arrow.py +980 -0
- perspective/tests/table/test_update_pandas.py +211 -0
- perspective/tests/table/test_view.py +2261 -0
- perspective/tests/table/test_view_expression.py +1940 -0
- perspective/tests/test_dependencies.py +53 -0
- perspective/tests/viewer/__init__.py +11 -0
- perspective/tests/viewer/test_viewer.py +246 -0
- perspective/tests/widget/__init__.py +11 -0
- perspective/tests/widget/test_widget.py +278 -0
- perspective/tests/widget/test_widget_pandas.py +453 -0
- perspective/virtual_servers/__init__.py +134 -0
- perspective/virtual_servers/clickhouse.py +245 -0
- perspective/virtual_servers/duckdb.py +236 -0
- perspective/widget/__init__.py +349 -0
- perspective/widget/viewer/__init__.py +15 -0
- perspective/widget/viewer/validate.py +22 -0
- perspective/widget/viewer/viewer.py +343 -0
- perspective/widget/viewer/viewer_traitlets.py +101 -0
- perspective_python-4.2.0.data/data/share/jupyter/labextensions/@perspective-dev/jupyterlab/install.json +5 -0
- perspective_python-4.2.0.data/data/share/jupyter/labextensions/@perspective-dev/jupyterlab/package.json +71 -0
- perspective_python-4.2.0.data/data/share/jupyter/labextensions/@perspective-dev/jupyterlab/static/253.5f5c9e80605aa4106a28.js +2 -0
- perspective_python-4.2.0.data/data/share/jupyter/labextensions/@perspective-dev/jupyterlab/static/253.5f5c9e80605aa4106a28.js.LICENSE.txt +25 -0
- perspective_python-4.2.0.data/data/share/jupyter/labextensions/@perspective-dev/jupyterlab/static/523.c030af5d3c4f67ff83f6.js +1 -0
- perspective_python-4.2.0.data/data/share/jupyter/labextensions/@perspective-dev/jupyterlab/static/remoteEntry.95a8ea1b44d96032833f.js +1 -0
- perspective_python-4.2.0.data/data/share/jupyter/labextensions/@perspective-dev/jupyterlab/static/style.js +4 -0
- perspective_python-4.2.0.data/data/share/jupyter/labextensions/@perspective-dev/jupyterlab/static/third-party-licenses.json +16 -0
- perspective_python-4.2.0.dist-info/METADATA +27 -0
- perspective_python-4.2.0.dist-info/RECORD +79 -0
- perspective_python-4.2.0.dist-info/WHEEL +4 -0
- perspective_python-4.2.0.dist-info/licenses/LICENSE.md +193 -0
- perspective_python-4.2.0.dist-info/licenses/LICENSE_THIRDPARTY_cargo.yml +17395 -0
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
|
|
2
|
+
# ┃ ██████ ██████ ██████ █ █ █ █ █ █▄ ▀███ █ ┃
|
|
3
|
+
# ┃ ▄▄▄▄▄█ █▄▄▄▄▄ ▄▄▄▄▄█ ▀▀▀▀▀█▀▀▀▀▀ █ ▀▀▀▀▀█ ████████▌▐███ ███▄ ▀█ █ ▀▀▀▀▀ ┃
|
|
4
|
+
# ┃ █▀▀▀▀▀ █▀▀▀▀▀ █▀██▀▀ ▄▄▄▄▄ █ ▄▄▄▄▄█ ▄▄▄▄▄█ ████████▌▐███ █████▄ █ ▄▄▄▄▄ ┃
|
|
5
|
+
# ┃ █ ██████ █ ▀█▄ █ ██████ █ ███▌▐███ ███████▄ █ ┃
|
|
6
|
+
# ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
|
|
7
|
+
# ┃ Copyright (c) 2017, the Perspective Authors. ┃
|
|
8
|
+
# ┃ ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ ┃
|
|
9
|
+
# ┃ This file is part of the Perspective library, distributed under the terms ┃
|
|
10
|
+
# ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
|
|
11
|
+
# ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
|
12
|
+
|
|
13
|
+
from perspective import Server, Client, ProxySession, AsyncClient
|
|
14
|
+
import pytest
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
client = Server().new_local_client()
|
|
18
|
+
Table = client.table
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
data = {"a": [1, 2, 3], "b": ["a", "b", "c"]}
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class TestProxySession(object):
|
|
25
|
+
def test_proxy_client(self):
|
|
26
|
+
server = Server()
|
|
27
|
+
client = server.new_local_client()
|
|
28
|
+
|
|
29
|
+
def handle_request(bytes):
|
|
30
|
+
sub_session.handle_request(bytes)
|
|
31
|
+
|
|
32
|
+
def handle_response(bytes):
|
|
33
|
+
sub_client.handle_response(bytes)
|
|
34
|
+
|
|
35
|
+
sub_session = ProxySession(client, handle_response)
|
|
36
|
+
sub_client = Client(handle_request, sub_session.close)
|
|
37
|
+
table = sub_client.table(data, name="table1")
|
|
38
|
+
assert table.schema() == {"a": "integer", "b": "string"}
|
|
39
|
+
|
|
40
|
+
def test_proxy_and_local_client_can_share_handles(self):
|
|
41
|
+
server = Server()
|
|
42
|
+
client = server.new_local_client()
|
|
43
|
+
|
|
44
|
+
def handle_request(bytes):
|
|
45
|
+
sub_session.handle_request(bytes)
|
|
46
|
+
|
|
47
|
+
def handle_response(bytes):
|
|
48
|
+
sub_client.handle_response(bytes)
|
|
49
|
+
|
|
50
|
+
sub_session = ProxySession(client, handle_response)
|
|
51
|
+
sub_client = Client(handle_request, sub_session.close)
|
|
52
|
+
table = sub_client.table(data, name="table1")
|
|
53
|
+
table2 = client.open_table("table1")
|
|
54
|
+
assert table.size() == 3
|
|
55
|
+
table2.update([{"a": 4, "d": 5}])
|
|
56
|
+
assert table.size() == 4
|
|
57
|
+
|
|
58
|
+
@pytest.mark.asyncio
|
|
59
|
+
async def test_handle_request_async(self):
|
|
60
|
+
"""tests use of ProxySession.handle_request_async() in an AsyncClient callback"""
|
|
61
|
+
server = Server()
|
|
62
|
+
client = server.new_local_client()
|
|
63
|
+
|
|
64
|
+
def handle_response(bytes):
|
|
65
|
+
import asyncio
|
|
66
|
+
|
|
67
|
+
asyncio.create_task(sub_client.handle_response(bytes))
|
|
68
|
+
|
|
69
|
+
sub_session = ProxySession(client, handle_response)
|
|
70
|
+
sub_client = AsyncClient(sub_session.handle_request_async, sub_session.close)
|
|
71
|
+
table = await sub_client.table(data, name="table1")
|
|
72
|
+
table2 = client.open_table("table1")
|
|
73
|
+
assert (await table.size()) == 3
|
|
74
|
+
table2.update([{"a": 4, "d": 5}])
|
|
75
|
+
assert (await table.size()) == 4
|
|
76
|
+
|
|
77
|
+
@pytest.mark.asyncio
|
|
78
|
+
async def test_dismabiguate_message_ids_in_proxy_session(self):
|
|
79
|
+
"""tests concurrent calls from clients on Session + ProxySession"""
|
|
80
|
+
server = Server()
|
|
81
|
+
client = server.new_local_client()
|
|
82
|
+
|
|
83
|
+
def send_response(bytes):
|
|
84
|
+
import asyncio
|
|
85
|
+
|
|
86
|
+
asyncio.create_task(sub_client.handle_response(bytes))
|
|
87
|
+
|
|
88
|
+
async def send_request(bytes):
|
|
89
|
+
await sub_session.handle_request_async(bytes)
|
|
90
|
+
|
|
91
|
+
sub_session = ProxySession(client, send_response)
|
|
92
|
+
sub_client = AsyncClient(send_request, sub_session.close)
|
|
93
|
+
|
|
94
|
+
table = client.table("x\n1", name="test_table")
|
|
95
|
+
table2 = await sub_client.open_table("test_table")
|
|
96
|
+
view = table.view()
|
|
97
|
+
view2 = await table2.view()
|
|
98
|
+
|
|
99
|
+
sentinel = []
|
|
100
|
+
|
|
101
|
+
def callback1(*args):
|
|
102
|
+
sentinel.append("Callback 1")
|
|
103
|
+
|
|
104
|
+
def callback2(*args):
|
|
105
|
+
sentinel.append("Callback 2")
|
|
106
|
+
|
|
107
|
+
view.on_update(callback1)
|
|
108
|
+
await view2.on_update(callback2)
|
|
109
|
+
await table2.update("x\n2")
|
|
110
|
+
assert sentinel == ["Callback 1", "Callback 2"]
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
|
|
2
|
+
# ┃ ██████ ██████ ██████ █ █ █ █ █ █▄ ▀███ █ ┃
|
|
3
|
+
# ┃ ▄▄▄▄▄█ █▄▄▄▄▄ ▄▄▄▄▄█ ▀▀▀▀▀█▀▀▀▀▀ █ ▀▀▀▀▀█ ████████▌▐███ ███▄ ▀█ █ ▀▀▀▀▀ ┃
|
|
4
|
+
# ┃ █▀▀▀▀▀ █▀▀▀▀▀ █▀██▀▀ ▄▄▄▄▄ █ ▄▄▄▄▄█ ▄▄▄▄▄█ ████████▌▐███ █████▄ █ ▄▄▄▄▄ ┃
|
|
5
|
+
# ┃ █ ██████ █ ▀█▄ █ ██████ █ ███▌▐███ ███████▄ █ ┃
|
|
6
|
+
# ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
|
|
7
|
+
# ┃ Copyright (c) 2017, the Perspective Authors. ┃
|
|
8
|
+
# ┃ ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ ┃
|
|
9
|
+
# ┃ This file is part of the Perspective library, distributed under the terms ┃
|
|
10
|
+
# ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
|
|
11
|
+
# ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,402 @@
|
|
|
1
|
+
# ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
|
|
2
|
+
# ┃ ██████ ██████ ██████ █ █ █ █ █ █▄ ▀███ █ ┃
|
|
3
|
+
# ┃ ▄▄▄▄▄█ █▄▄▄▄▄ ▄▄▄▄▄█ ▀▀▀▀▀█▀▀▀▀▀ █ ▀▀▀▀▀█ ████████▌▐███ ███▄ ▀█ █ ▀▀▀▀▀ ┃
|
|
4
|
+
# ┃ █▀▀▀▀▀ █▀▀▀▀▀ █▀██▀▀ ▄▄▄▄▄ █ ▄▄▄▄▄█ ▄▄▄▄▄█ ████████▌▐███ █████▄ █ ▄▄▄▄▄ ┃
|
|
5
|
+
# ┃ █ ██████ █ ▀█▄ █ ██████ █ ███▌▐███ ███████▄ █ ┃
|
|
6
|
+
# ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
|
|
7
|
+
# ┃ Copyright (c) 2017, the Perspective Authors. ┃
|
|
8
|
+
# ┃ ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ ┃
|
|
9
|
+
# ┃ This file is part of the Perspective library, distributed under the terms ┃
|
|
10
|
+
# ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
|
|
11
|
+
# ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
|
12
|
+
|
|
13
|
+
import sys
|
|
14
|
+
from random import randint, choice
|
|
15
|
+
import perspective as psp
|
|
16
|
+
|
|
17
|
+
client = psp.Server().new_local_client()
|
|
18
|
+
Table = client.table
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class CustomObjectStore(object):
|
|
22
|
+
def __init__(self, value):
|
|
23
|
+
self._value = value
|
|
24
|
+
|
|
25
|
+
def _psp_dtype_(self):
|
|
26
|
+
return "object"
|
|
27
|
+
|
|
28
|
+
def __int__(self):
|
|
29
|
+
return int(self._value)
|
|
30
|
+
|
|
31
|
+
def __repr__(self):
|
|
32
|
+
return "test" if self._value == 1 else "test{}".format(self._value)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def run():
|
|
36
|
+
t = CustomObjectStore(1)
|
|
37
|
+
t2 = CustomObjectStore(2)
|
|
38
|
+
|
|
39
|
+
assert sys.getrefcount(t) == 2
|
|
40
|
+
assert sys.getrefcount(t2) == 2
|
|
41
|
+
|
|
42
|
+
data = {"a": [0], "b": [t]}
|
|
43
|
+
assert sys.getrefcount(t) == 3
|
|
44
|
+
|
|
45
|
+
tbl = Table(data, index="a")
|
|
46
|
+
assert sys.getrefcount(t) == 4
|
|
47
|
+
|
|
48
|
+
assert tbl.schema() == {"a": int, "b": object}
|
|
49
|
+
assert tbl.size() == 1
|
|
50
|
+
assert tbl.view().to_columns() == {"a": [0], "b": [t]}
|
|
51
|
+
|
|
52
|
+
# Count references
|
|
53
|
+
# 1 for `t`, 1 for `data`, 1 for argument to sys.getrefcount, and 1 for the table
|
|
54
|
+
print(sys.getrefcount(t), "should be", 4)
|
|
55
|
+
print("t:", id(t))
|
|
56
|
+
assert sys.getrefcount(t) == 4
|
|
57
|
+
|
|
58
|
+
print(sys.getrefcount(t2), "should be", 2)
|
|
59
|
+
print("t2:", id(t2))
|
|
60
|
+
assert sys.getrefcount(t2) == 2
|
|
61
|
+
|
|
62
|
+
tbl.update([{"a": i, "b": None} for i in range(1, 6)])
|
|
63
|
+
|
|
64
|
+
assert tbl.size() == 6
|
|
65
|
+
# 1 for `t`, 1 for `data`, 1 for argument to sys.getrefcount, and 1 for the table
|
|
66
|
+
print(sys.getrefcount(t), "should be", 4)
|
|
67
|
+
assert sys.getrefcount(t) == 4
|
|
68
|
+
|
|
69
|
+
print()
|
|
70
|
+
tbl.update([data])
|
|
71
|
+
# 1 for `t`, 1 for `data`, 1 for argument to sys.getrefcount, and 1 for the table
|
|
72
|
+
print(sys.getrefcount(t), "should be", 4)
|
|
73
|
+
assert sys.getrefcount(t) == 4
|
|
74
|
+
|
|
75
|
+
print()
|
|
76
|
+
tbl.update([data])
|
|
77
|
+
# 1 for `t`, 1 for `data`, 1 for argument to sys.getrefcount, and 1 for the table
|
|
78
|
+
print(sys.getrefcount(t), "should be", 4)
|
|
79
|
+
assert sys.getrefcount(t) == 4
|
|
80
|
+
|
|
81
|
+
print()
|
|
82
|
+
tbl.update([data])
|
|
83
|
+
# 1 for `t`, 1 for `data`, 1 for argument to sys.getrefcount, and 1 for the table
|
|
84
|
+
print(sys.getrefcount(t), "should be", 4)
|
|
85
|
+
assert sys.getrefcount(t) == 4
|
|
86
|
+
|
|
87
|
+
print()
|
|
88
|
+
tbl.update([{"a": 1, "b": t}])
|
|
89
|
+
# 1 for `t`, 1 for `data`, 1 for argument to sys.getrefcount, and 2 for the table
|
|
90
|
+
print(sys.getrefcount(t), "should be", 5)
|
|
91
|
+
assert sys.getrefcount(t) == 5
|
|
92
|
+
|
|
93
|
+
print()
|
|
94
|
+
tbl.update([{"a": 1, "b": t}])
|
|
95
|
+
# 1 for `t`, 1 for `data`, 1 for argument to sys.getrefcount, and 2 for the table
|
|
96
|
+
print(sys.getrefcount(t), "should be", 5)
|
|
97
|
+
assert sys.getrefcount(t) == 5
|
|
98
|
+
|
|
99
|
+
print()
|
|
100
|
+
tbl.update([{"a": 3, "b": t}])
|
|
101
|
+
# 1 for `t`, 1 for `data`, 1 for argument to sys.getrefcount, and 3 for the table
|
|
102
|
+
print(sys.getrefcount(t), "should be", 6)
|
|
103
|
+
assert sys.getrefcount(t) == 6
|
|
104
|
+
|
|
105
|
+
print()
|
|
106
|
+
tbl.update([{"a": 3, "b": t}])
|
|
107
|
+
# 1 for `t`, 1 for `data`, 1 for argument to sys.getrefcount, and 3 for the table
|
|
108
|
+
print(sys.getrefcount(t), "should be", 6)
|
|
109
|
+
assert sys.getrefcount(t) == 6
|
|
110
|
+
|
|
111
|
+
print()
|
|
112
|
+
tbl.update([{"a": 5, "b": t}])
|
|
113
|
+
# 1 for `t`, 1 for `data`, 1 for argument to sys.getrefcount, and 4for the table
|
|
114
|
+
print(sys.getrefcount(t), "should be", 7)
|
|
115
|
+
# assert sys.getrefcount(t) == 7
|
|
116
|
+
print(tbl.view().to_columns()["b"])
|
|
117
|
+
assert list(_ is not None for _ in tbl.view().to_columns()["b"]) == [
|
|
118
|
+
True,
|
|
119
|
+
True,
|
|
120
|
+
False,
|
|
121
|
+
True,
|
|
122
|
+
False,
|
|
123
|
+
True,
|
|
124
|
+
]
|
|
125
|
+
|
|
126
|
+
print()
|
|
127
|
+
# clear some, overwrite some with same
|
|
128
|
+
tbl.update([{"a": 0, "b": t}])
|
|
129
|
+
# 1 for `t`, 1 for `data`, 1 for argument to sys.getrefcount, and 4 for the table
|
|
130
|
+
print(sys.getrefcount(t), "should be", 7)
|
|
131
|
+
assert list(_ is not None for _ in tbl.view().to_columns()["b"]) == [
|
|
132
|
+
True,
|
|
133
|
+
True,
|
|
134
|
+
False,
|
|
135
|
+
True,
|
|
136
|
+
False,
|
|
137
|
+
True,
|
|
138
|
+
]
|
|
139
|
+
|
|
140
|
+
print()
|
|
141
|
+
tbl.update([{"a": 1, "b": t2}])
|
|
142
|
+
# 1 for `t`, 1 for `data`, 1 for argument to sys.getrefcount, and 3 for the table
|
|
143
|
+
print(sys.getrefcount(t), "should be", 6)
|
|
144
|
+
# 1 for `t2`, 1 for argument to sys.getrefcount, and 1 for the table
|
|
145
|
+
print(sys.getrefcount(t2), "should be", 3)
|
|
146
|
+
print(tbl.view().to_columns()["b"])
|
|
147
|
+
assert list(_ is not None for _ in tbl.view().to_columns()["b"]) == [
|
|
148
|
+
True,
|
|
149
|
+
True,
|
|
150
|
+
False,
|
|
151
|
+
True,
|
|
152
|
+
False,
|
|
153
|
+
True,
|
|
154
|
+
]
|
|
155
|
+
|
|
156
|
+
print()
|
|
157
|
+
tbl.update([{"a": 1, "b": t2}])
|
|
158
|
+
# 1 for `t`, 1 for `data`, 1 for argument to sys.getrefcount, and 3 for the table
|
|
159
|
+
print(sys.getrefcount(t), "should be", 6)
|
|
160
|
+
# 1 for `t2`, 1 for argument to sys.getrefcount, and 1 for the table
|
|
161
|
+
print(sys.getrefcount(t2), "should be", 3)
|
|
162
|
+
print(tbl.view().to_columns()["b"])
|
|
163
|
+
assert list(_ is not None for _ in tbl.view().to_columns()["b"]) == [
|
|
164
|
+
True,
|
|
165
|
+
True,
|
|
166
|
+
False,
|
|
167
|
+
True,
|
|
168
|
+
False,
|
|
169
|
+
True,
|
|
170
|
+
]
|
|
171
|
+
|
|
172
|
+
print()
|
|
173
|
+
tbl.update([{"a": 1, "b": t2}])
|
|
174
|
+
# 1 for `t`, 1 for `data`, 1 for argument to sys.getrefcount, and 3 for the table
|
|
175
|
+
print(sys.getrefcount(t), "should be", 6)
|
|
176
|
+
# 1 for `t2`, 1 for argument to sys.getrefcount, and 1 for the table
|
|
177
|
+
print(sys.getrefcount(t2), "should be", 3)
|
|
178
|
+
print(tbl.view().to_columns()["b"])
|
|
179
|
+
assert list(_ is not None for _ in tbl.view().to_columns()["b"]) == [
|
|
180
|
+
True,
|
|
181
|
+
True,
|
|
182
|
+
False,
|
|
183
|
+
True,
|
|
184
|
+
False,
|
|
185
|
+
True,
|
|
186
|
+
]
|
|
187
|
+
|
|
188
|
+
print()
|
|
189
|
+
tbl.update([{"a": 1, "b": t2}])
|
|
190
|
+
# 1 for `t`, 1 for `data`, 1 for argument to sys.getrefcount, and 3 for the table
|
|
191
|
+
print(sys.getrefcount(t), "should be", 6)
|
|
192
|
+
# 1 for `t2`, 1 for argument to sys.getrefcount, and 1 for the table
|
|
193
|
+
print(sys.getrefcount(t2), "should be", 3)
|
|
194
|
+
print(tbl.view().to_columns()["b"])
|
|
195
|
+
assert list(_ is not None for _ in tbl.view().to_columns()["b"]) == [
|
|
196
|
+
True,
|
|
197
|
+
True,
|
|
198
|
+
False,
|
|
199
|
+
True,
|
|
200
|
+
False,
|
|
201
|
+
True,
|
|
202
|
+
]
|
|
203
|
+
|
|
204
|
+
print()
|
|
205
|
+
tbl.update([{"a": 2, "b": t2}])
|
|
206
|
+
# 1 for `t`, 1 for `data`, 1 for argument to sys.getrefcount, and 3 for the table
|
|
207
|
+
print(sys.getrefcount(t), "should be", 6)
|
|
208
|
+
# 1 for `t2`, 1 for argument to sys.getrefcount, and 1 for the table
|
|
209
|
+
print(sys.getrefcount(t2), "should be", 4)
|
|
210
|
+
print(tbl.view().to_columns()["b"])
|
|
211
|
+
assert list(_ is not None for _ in tbl.view().to_columns()["b"]) == [
|
|
212
|
+
True,
|
|
213
|
+
True,
|
|
214
|
+
True,
|
|
215
|
+
True,
|
|
216
|
+
False,
|
|
217
|
+
True,
|
|
218
|
+
]
|
|
219
|
+
|
|
220
|
+
print()
|
|
221
|
+
tbl.update([{"a": 2, "b": None}])
|
|
222
|
+
# 1 for `t`, 1 for `data`, 1 for argument to sys.getrefcount, and 3 for the table
|
|
223
|
+
print(sys.getrefcount(t), "should be", 6)
|
|
224
|
+
# 1 for `t2`, 1 for argument to sys.getrefcount, and 1 for the table
|
|
225
|
+
print(sys.getrefcount(t2), "should be", 3)
|
|
226
|
+
print(tbl.view().to_columns()["b"])
|
|
227
|
+
assert list(_ is not None for _ in tbl.view().to_columns()["b"]) == [
|
|
228
|
+
True,
|
|
229
|
+
True,
|
|
230
|
+
False,
|
|
231
|
+
True,
|
|
232
|
+
False,
|
|
233
|
+
True,
|
|
234
|
+
]
|
|
235
|
+
|
|
236
|
+
print()
|
|
237
|
+
tbl.update([{"a": 2, "b": t2}])
|
|
238
|
+
# 1 for `t`, 1 for `data`, 1 for argument to sys.getrefcount, and 3 for the table
|
|
239
|
+
print(sys.getrefcount(t), "should be", 6)
|
|
240
|
+
# 1 for `t2`, 1 for argument to sys.getrefcount, and 1 for the table
|
|
241
|
+
print(sys.getrefcount(t2), "should be", 4)
|
|
242
|
+
print(tbl.view().to_columns()["b"])
|
|
243
|
+
assert list(_ is not None for _ in tbl.view().to_columns()["b"]) == [
|
|
244
|
+
True,
|
|
245
|
+
True,
|
|
246
|
+
True,
|
|
247
|
+
True,
|
|
248
|
+
False,
|
|
249
|
+
True,
|
|
250
|
+
]
|
|
251
|
+
|
|
252
|
+
print()
|
|
253
|
+
tbl.update([{"a": 2, "b": None}])
|
|
254
|
+
# 1 for `t`, 1 for `data`, 1 for argument to sys.getrefcount, and 3 for the table
|
|
255
|
+
print(sys.getrefcount(t), "should be", 6)
|
|
256
|
+
# 1 for `t2`, 1 for argument to sys.getrefcount, and 1 for the table
|
|
257
|
+
print(sys.getrefcount(t2), "should be", 3)
|
|
258
|
+
print(tbl.view().to_columns()["b"])
|
|
259
|
+
assert list(_ is not None for _ in tbl.view().to_columns()["b"]) == [
|
|
260
|
+
True,
|
|
261
|
+
True,
|
|
262
|
+
False,
|
|
263
|
+
True,
|
|
264
|
+
False,
|
|
265
|
+
True,
|
|
266
|
+
]
|
|
267
|
+
|
|
268
|
+
print()
|
|
269
|
+
tbl.update([{"a": 3, "b": None}])
|
|
270
|
+
# 1 for `t`, 1 for `data`, 1 for argument to sys.getrefcount, and 2 for the table
|
|
271
|
+
print(sys.getrefcount(t), "should be", 5)
|
|
272
|
+
# 1 for `t2`, 1 for argument to sys.getrefcount, and 1 for the table
|
|
273
|
+
print(sys.getrefcount(t2), "should be", 3)
|
|
274
|
+
print(tbl.view().to_columns()["b"])
|
|
275
|
+
assert list(_ is not None for _ in tbl.view().to_columns()["b"]) == [
|
|
276
|
+
True,
|
|
277
|
+
True,
|
|
278
|
+
False,
|
|
279
|
+
False,
|
|
280
|
+
False,
|
|
281
|
+
True,
|
|
282
|
+
]
|
|
283
|
+
|
|
284
|
+
print()
|
|
285
|
+
tbl.update([{"a": 3, "b": None}])
|
|
286
|
+
# 1 for `t`, 1 for `data`, 1 for argument to sys.getrefcount, and 2 for the table
|
|
287
|
+
print(sys.getrefcount(t), "should be", 5)
|
|
288
|
+
# 1 for `t2`, 1 for argument to sys.getrefcount, and 1 for the table
|
|
289
|
+
print(sys.getrefcount(t2), "should be", 3)
|
|
290
|
+
print(tbl.view().to_columns()["b"])
|
|
291
|
+
assert list(_ is not None for _ in tbl.view().to_columns()["b"]) == [
|
|
292
|
+
True,
|
|
293
|
+
True,
|
|
294
|
+
False,
|
|
295
|
+
False,
|
|
296
|
+
False,
|
|
297
|
+
True,
|
|
298
|
+
]
|
|
299
|
+
|
|
300
|
+
print()
|
|
301
|
+
tbl.update([{"a": 5, "b": None}])
|
|
302
|
+
# 1 for `t`, 1 for `data`, 1 for argument to sys.getrefcount, and 1 for the table
|
|
303
|
+
print(sys.getrefcount(t), "should be", 4)
|
|
304
|
+
# 1 for `t2`, 1 for argument to sys.getrefcount, and 1 for the table
|
|
305
|
+
print(sys.getrefcount(t2), "should be", 3)
|
|
306
|
+
print(tbl.view().to_columns()["b"])
|
|
307
|
+
assert list(_ is not None for _ in tbl.view().to_columns()["b"]) == [
|
|
308
|
+
True,
|
|
309
|
+
True,
|
|
310
|
+
False,
|
|
311
|
+
False,
|
|
312
|
+
False,
|
|
313
|
+
False,
|
|
314
|
+
]
|
|
315
|
+
|
|
316
|
+
print()
|
|
317
|
+
tbl.update([{"a": 5, "b": None}])
|
|
318
|
+
# 1 for `t`, 1 for `data`, 1 for argument to sys.getrefcount, and 1 for the table
|
|
319
|
+
print(sys.getrefcount(t), "should be", 4)
|
|
320
|
+
# 1 for `t2`, 1 for argument to sys.getrefcount, and 1 for the table
|
|
321
|
+
print(sys.getrefcount(t2), "should be", 3)
|
|
322
|
+
print(tbl.view().to_columns()["b"])
|
|
323
|
+
assert list(_ is not None for _ in tbl.view().to_columns()["b"]) == [
|
|
324
|
+
True,
|
|
325
|
+
True,
|
|
326
|
+
False,
|
|
327
|
+
False,
|
|
328
|
+
False,
|
|
329
|
+
False,
|
|
330
|
+
]
|
|
331
|
+
|
|
332
|
+
print()
|
|
333
|
+
tbl.clear()
|
|
334
|
+
assert tbl.size() == 0
|
|
335
|
+
assert tbl.view().to_columns() == {}
|
|
336
|
+
# 1 for `t`, one for `data`, one for argument to sys.getrefcount
|
|
337
|
+
print(sys.getrefcount(t), "should be", 3)
|
|
338
|
+
assert sys.getrefcount(t) == 3
|
|
339
|
+
|
|
340
|
+
|
|
341
|
+
def run2():
|
|
342
|
+
t = CustomObjectStore(1)
|
|
343
|
+
t_ref_count = 2
|
|
344
|
+
assert sys.getrefcount(t) == t_ref_count
|
|
345
|
+
|
|
346
|
+
indexes = set([0])
|
|
347
|
+
|
|
348
|
+
tbl = Table({"a": [0], "b": [t]}, index="a")
|
|
349
|
+
assert sys.getrefcount(t) == 3
|
|
350
|
+
t_ref_count += 1
|
|
351
|
+
|
|
352
|
+
assert tbl.schema() == {"a": int, "b": object}
|
|
353
|
+
assert tbl.size() == 1
|
|
354
|
+
assert tbl.view().to_columns() == {"a": [0], "b": [t]}
|
|
355
|
+
|
|
356
|
+
# seed a few to check
|
|
357
|
+
tbl.remove([1])
|
|
358
|
+
tbl.remove([1])
|
|
359
|
+
tbl.remove([1])
|
|
360
|
+
|
|
361
|
+
for _ in range(10):
|
|
362
|
+
pick = randint(1, 2) if indexes else 1
|
|
363
|
+
if pick == 1:
|
|
364
|
+
ind = randint(1, 10)
|
|
365
|
+
while ind in indexes:
|
|
366
|
+
ind = randint(1, 100)
|
|
367
|
+
|
|
368
|
+
print(
|
|
369
|
+
"adding", ind, "refcount", t_ref_count, "should be", sys.getrefcount(t)
|
|
370
|
+
)
|
|
371
|
+
tbl.update({"a": [ind], "b": [t]})
|
|
372
|
+
t_ref_count += 1
|
|
373
|
+
indexes.add(ind)
|
|
374
|
+
assert sys.getrefcount(t) == t_ref_count
|
|
375
|
+
|
|
376
|
+
else:
|
|
377
|
+
ind = choice(list(indexes))
|
|
378
|
+
indexes.remove(ind)
|
|
379
|
+
tbl.remove([ind])
|
|
380
|
+
t_ref_count -= 1
|
|
381
|
+
print(
|
|
382
|
+
"removing",
|
|
383
|
+
ind,
|
|
384
|
+
"refcount",
|
|
385
|
+
t_ref_count,
|
|
386
|
+
"should be",
|
|
387
|
+
sys.getrefcount(t),
|
|
388
|
+
)
|
|
389
|
+
assert sys.getrefcount(t) == t_ref_count
|
|
390
|
+
|
|
391
|
+
print(t_ref_count)
|
|
392
|
+
print(tbl.view().to_columns())
|
|
393
|
+
|
|
394
|
+
assert sys.getrefcount(t) == t_ref_count
|
|
395
|
+
|
|
396
|
+
print()
|
|
397
|
+
tbl.clear()
|
|
398
|
+
assert tbl.size() == 0
|
|
399
|
+
assert tbl.view().to_columns() == {}
|
|
400
|
+
# 1 for `t`, one for `data`, one for argument to sys.getrefcount
|
|
401
|
+
print(sys.getrefcount(t), "should be", 2)
|
|
402
|
+
assert sys.getrefcount(t) == 2
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
|
|
2
|
+
# ┃ ██████ ██████ ██████ █ █ █ █ █ █▄ ▀███ █ ┃
|
|
3
|
+
# ┃ ▄▄▄▄▄█ █▄▄▄▄▄ ▄▄▄▄▄█ ▀▀▀▀▀█▀▀▀▀▀ █ ▀▀▀▀▀█ ████████▌▐███ ███▄ ▀█ █ ▀▀▀▀▀ ┃
|
|
4
|
+
# ┃ █▀▀▀▀▀ █▀▀▀▀▀ █▀██▀▀ ▄▄▄▄▄ █ ▄▄▄▄▄█ ▄▄▄▄▄█ ████████▌▐███ █████▄ █ ▄▄▄▄▄ ┃
|
|
5
|
+
# ┃ █ ██████ █ ▀█▄ █ ██████ █ ███▌▐███ ███████▄ █ ┃
|
|
6
|
+
# ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
|
|
7
|
+
# ┃ Copyright (c) 2017, the Perspective Authors. ┃
|
|
8
|
+
# ┃ ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ ┃
|
|
9
|
+
# ┃ This file is part of the Perspective library, distributed under the terms ┃
|
|
10
|
+
# ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
|
|
11
|
+
# ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
|
12
|
+
|
|
13
|
+
import perspective as psp
|
|
14
|
+
|
|
15
|
+
client = psp.Server().new_local_client()
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class TestViewColumnPaths(object):
|
|
19
|
+
def test_column_paths(self, superstore):
|
|
20
|
+
tbl = client.table(superstore)
|
|
21
|
+
view = tbl.view()
|
|
22
|
+
paths = view.column_paths()
|
|
23
|
+
assert paths == [
|
|
24
|
+
"index",
|
|
25
|
+
"Row ID",
|
|
26
|
+
"Order ID",
|
|
27
|
+
"Order Date",
|
|
28
|
+
"Ship Date",
|
|
29
|
+
"Ship Mode",
|
|
30
|
+
"Customer ID",
|
|
31
|
+
"Segment",
|
|
32
|
+
"Country",
|
|
33
|
+
"City",
|
|
34
|
+
"State",
|
|
35
|
+
"Postal Code",
|
|
36
|
+
"Region",
|
|
37
|
+
"Product ID",
|
|
38
|
+
"Category",
|
|
39
|
+
"Sub-Category",
|
|
40
|
+
"Sales",
|
|
41
|
+
"Quantity",
|
|
42
|
+
"Discount",
|
|
43
|
+
"Profit",
|
|
44
|
+
]
|
|
45
|
+
|
|
46
|
+
view.delete()
|
|
47
|
+
tbl.delete()
|
|
48
|
+
|
|
49
|
+
def test_column_paths_split_by(self, superstore):
|
|
50
|
+
tbl = client.table(superstore)
|
|
51
|
+
view = tbl.view(group_by=["State"], columns=["Sales"], split_by=["Ship Mode"])
|
|
52
|
+
paths = view.column_paths()
|
|
53
|
+
assert paths == [
|
|
54
|
+
"First Class|Sales",
|
|
55
|
+
"Second Class|Sales",
|
|
56
|
+
"Standard Class|Sales",
|
|
57
|
+
]
|
|
58
|
+
|
|
59
|
+
view.delete()
|
|
60
|
+
tbl.delete()
|
|
61
|
+
|
|
62
|
+
def test_column_paths_split_by_range(self, superstore):
|
|
63
|
+
tbl = client.table(superstore)
|
|
64
|
+
view = tbl.view(group_by=["State"], columns=["Sales"], split_by=["Ship Mode"])
|
|
65
|
+
paths = view.column_paths(start_col=1)
|
|
66
|
+
assert paths == [
|
|
67
|
+
"Second Class|Sales",
|
|
68
|
+
"Standard Class|Sales",
|
|
69
|
+
]
|
|
70
|
+
|
|
71
|
+
view.delete()
|
|
72
|
+
view = tbl.view(group_by=["State"], columns=["Sales"], split_by=["Ship Mode"])
|
|
73
|
+
paths = view.column_paths(start_col=1, end_col=2)
|
|
74
|
+
assert paths == [
|
|
75
|
+
"Second Class|Sales",
|
|
76
|
+
"Standard Class|Sales",
|
|
77
|
+
]
|
|
78
|
+
|
|
79
|
+
view.delete()
|
|
80
|
+
tbl = client.table(superstore)
|
|
81
|
+
view = tbl.view(group_by=["State"], columns=["Sales"], split_by=["Ship Mode"])
|
|
82
|
+
paths = view.column_paths(end_col=1)
|
|
83
|
+
assert paths == [
|
|
84
|
+
"First Class|Sales",
|
|
85
|
+
"Second Class|Sales",
|
|
86
|
+
]
|
|
87
|
+
|
|
88
|
+
view.delete()
|
|
89
|
+
tbl.delete()
|