perspective-python 3.0.0rc1__cp39-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 +78 -0
- perspective/extension/finos-perspective-nbextension.json +5 -0
- perspective/handlers/__init__.py +26 -0
- perspective/handlers/aiohttp.py +54 -0
- perspective/handlers/starlette.py +51 -0
- perspective/handlers/tornado.py +61 -0
- perspective/perspective.pyd +0 -0
- perspective/templates/exported_widget.html.jinja +35 -0
- perspective/tests/__init__.py +11 -0
- perspective/tests/conftest.py +268 -0
- perspective/tests/core/__init__.py +11 -0
- perspective/tests/core/test_async.py +436 -0
- perspective/tests/core/test_threadpool.py +48 -0
- perspective/tests/server/__init__.py +11 -0
- perspective/tests/server/test_server.py +1062 -0
- perspective/tests/server/test_session.py +55 -0
- perspective/tests/single_threaded/test_single_threaded.py +61 -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_delete.py +124 -0
- perspective/tests/table/test_exception.py +53 -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 +610 -0
- perspective/tests/table/test_table_arrow.py +452 -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 +43 -0
- perspective/tests/table/test_table_numpy.py +1022 -0
- perspective/tests/table/test_table_pandas.py +1018 -0
- perspective/tests/table/test_to_arrow.py +414 -0
- perspective/tests/table/test_to_arrow_lz4.py +33 -0
- perspective/tests/table/test_to_format.py +1024 -0
- perspective/tests/table/test_update.py +545 -0
- perspective/tests/table/test_update_arrow.py +980 -0
- perspective/tests/table/test_update_numpy.py +252 -0
- perspective/tests/table/test_update_pandas.py +211 -0
- perspective/tests/table/test_view.py +2235 -0
- perspective/tests/table/test_view_expression.py +1940 -0
- perspective/tests/viewer/__init__.py +11 -0
- perspective/tests/viewer/test_validate.py +70 -0
- perspective/tests/viewer/test_viewer.py +245 -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/viewer/__init__.py +15 -0
- perspective/viewer/validate.py +22 -0
- perspective/viewer/viewer.py +331 -0
- perspective/viewer/viewer_traitlets.py +101 -0
- perspective/widget/__init__.py +16 -0
- perspective/widget/widget.py +269 -0
- perspective.data/data/share/jupyter/labextensions/@finos/perspective-jupyterlab/install.json +5 -0
- perspective.data/data/share/jupyter/labextensions/@finos/perspective-jupyterlab/package.json +81 -0
- perspective.data/data/share/jupyter/labextensions/@finos/perspective-jupyterlab/static/253.6f17b87bb4eb1e656365.js +18 -0
- perspective.data/data/share/jupyter/labextensions/@finos/perspective-jupyterlab/static/253.6f17b87bb4eb1e656365.js.LICENSE.txt +59 -0
- perspective.data/data/share/jupyter/labextensions/@finos/perspective-jupyterlab/static/905.d3bbc3d5954582d507bb.js +1 -0
- perspective.data/data/share/jupyter/labextensions/@finos/perspective-jupyterlab/static/remoteEntry.7044010cbbf2a7208035.js +1 -0
- perspective.data/data/share/jupyter/labextensions/@finos/perspective-jupyterlab/static/style.js +4 -0
- perspective.data/data/share/jupyter/labextensions/@finos/perspective-jupyterlab/static/third-party-licenses.json +16 -0
- perspective_python-3.0.0rc1.dist-info/METADATA +13 -0
- perspective_python-3.0.0rc1.dist-info/RECORD +70 -0
- perspective_python-3.0.0rc1.dist-info/WHEEL +4 -0
|
@@ -0,0 +1,55 @@
|
|
|
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
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
client = Server().new_local_client()
|
|
17
|
+
Table = client.table
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
data = {"a": [1, 2, 3], "b": ["a", "b", "c"]}
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class TestProxySession(object):
|
|
24
|
+
def test_proxy_client(self):
|
|
25
|
+
server = Server()
|
|
26
|
+
client = server.new_local_client()
|
|
27
|
+
|
|
28
|
+
def handle_request(bytes):
|
|
29
|
+
sub_session.handle_request(bytes)
|
|
30
|
+
|
|
31
|
+
def handle_response(bytes):
|
|
32
|
+
sub_client.handle_response(bytes)
|
|
33
|
+
|
|
34
|
+
sub_session = ProxySession(client, handle_response)
|
|
35
|
+
sub_client = Client(handle_request)
|
|
36
|
+
table = sub_client.table(data, name="table1")
|
|
37
|
+
assert table.schema() == {"a": "integer", "b": "string"}
|
|
38
|
+
|
|
39
|
+
def test_proxy_and_local_client_can_share_handles(self):
|
|
40
|
+
server = Server()
|
|
41
|
+
client = server.new_local_client()
|
|
42
|
+
|
|
43
|
+
def handle_request(bytes):
|
|
44
|
+
sub_session.handle_request(bytes)
|
|
45
|
+
|
|
46
|
+
def handle_response(bytes):
|
|
47
|
+
sub_client.handle_response(bytes)
|
|
48
|
+
|
|
49
|
+
sub_session = ProxySession(client, handle_response)
|
|
50
|
+
sub_client = Client(handle_request)
|
|
51
|
+
table = sub_client.table(data, name="table1")
|
|
52
|
+
table2 = client.open_table("table1")
|
|
53
|
+
assert table.size() == 3
|
|
54
|
+
table2.update([{"a": 4, "d": 5}])
|
|
55
|
+
assert table.size() == 4
|
|
@@ -0,0 +1,61 @@
|
|
|
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
|
+
|
|
14
|
+
import perspective as psp
|
|
15
|
+
|
|
16
|
+
server = psp.Server()
|
|
17
|
+
server.set_threadpool_size(1)
|
|
18
|
+
client = server.new_local_client()
|
|
19
|
+
Table = client.table
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class TestThreadPoolOne:
|
|
23
|
+
def test_threadpool_one_does_not_block_view(self):
|
|
24
|
+
t = Table(
|
|
25
|
+
{
|
|
26
|
+
"id": "integer",
|
|
27
|
+
"symbol": "string",
|
|
28
|
+
"valid": "boolean",
|
|
29
|
+
"value": "integer",
|
|
30
|
+
"value2": "integer",
|
|
31
|
+
},
|
|
32
|
+
index="id",
|
|
33
|
+
)
|
|
34
|
+
t.update(
|
|
35
|
+
[
|
|
36
|
+
{"id": 1, "symbol": "A", "valid": False, "value": 5, "value2": 15},
|
|
37
|
+
{"id": 2, "symbol": "A", "valid": True, "value": 10, "value2": 20},
|
|
38
|
+
]
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
v = t.view(
|
|
42
|
+
columns=["symbol", "value", "value3"],
|
|
43
|
+
expressions={"value3": """"value" + "value2\""""},
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
v_agg = t.view(
|
|
47
|
+
columns=["symbol", "value", "value3"],
|
|
48
|
+
expressions={"value3": """"value" + "value2\""""},
|
|
49
|
+
group_by=["symbol"],
|
|
50
|
+
aggregates={"symbol": "first", "value": "sum", "value2": "sum"},
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
assert v.to_json() == [
|
|
54
|
+
{"symbol": "A", "value": 5, "value3": 20.0},
|
|
55
|
+
{"symbol": "A", "value": 10, "value3": 30.0},
|
|
56
|
+
]
|
|
57
|
+
|
|
58
|
+
assert v_agg.to_json() == [
|
|
59
|
+
{"__ROW_PATH__": [], "symbol": "A", "value": 15, "value3": 50.0},
|
|
60
|
+
{"__ROW_PATH__": ["A"], "symbol": "A", "value": 15, "value3": 50.0},
|
|
61
|
+
]
|
|
@@ -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,124 @@
|
|
|
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
|
+
Table = client.table
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class TestDelete(object):
|
|
20
|
+
# delete
|
|
21
|
+
|
|
22
|
+
def test_table_delete(self):
|
|
23
|
+
data = [{"a": 1, "b": 2}, {"a": 3, "b": 4}]
|
|
24
|
+
tbl = Table(data)
|
|
25
|
+
tbl.delete()
|
|
26
|
+
# don't segfault
|
|
27
|
+
|
|
28
|
+
def test_table_delete_callback(self, sentinel):
|
|
29
|
+
s = sentinel(False)
|
|
30
|
+
|
|
31
|
+
def callback():
|
|
32
|
+
s.set(True)
|
|
33
|
+
|
|
34
|
+
data = [{"a": 1, "b": 2}, {"a": 3, "b": 4}]
|
|
35
|
+
tbl = Table(data)
|
|
36
|
+
tbl.on_delete(callback)
|
|
37
|
+
tbl.delete()
|
|
38
|
+
assert s.get() is True
|
|
39
|
+
|
|
40
|
+
def test_table_delete_with_view(self, sentinel):
|
|
41
|
+
s = sentinel(False)
|
|
42
|
+
|
|
43
|
+
def callback():
|
|
44
|
+
s.set(True)
|
|
45
|
+
|
|
46
|
+
data = [{"a": 1, "b": 2}, {"a": 3, "b": 4}]
|
|
47
|
+
tbl = Table(data)
|
|
48
|
+
tbl.on_delete(callback)
|
|
49
|
+
view = tbl.view()
|
|
50
|
+
view.delete()
|
|
51
|
+
tbl.delete()
|
|
52
|
+
assert s.get() is True
|
|
53
|
+
|
|
54
|
+
def test_table_delete_multiple_callback(self, sentinel):
|
|
55
|
+
s1 = sentinel(False)
|
|
56
|
+
s2 = sentinel(False)
|
|
57
|
+
|
|
58
|
+
def callback1():
|
|
59
|
+
s1.set(True)
|
|
60
|
+
|
|
61
|
+
def callback2():
|
|
62
|
+
s2.set(True)
|
|
63
|
+
|
|
64
|
+
tbl = Table([{"a": 1}])
|
|
65
|
+
tbl.on_delete(callback1)
|
|
66
|
+
tbl.on_delete(callback2)
|
|
67
|
+
|
|
68
|
+
tbl.delete()
|
|
69
|
+
|
|
70
|
+
assert s1.get() is True
|
|
71
|
+
assert s2.get() is True
|
|
72
|
+
|
|
73
|
+
def test_table_remove_delete_callback(self, sentinel):
|
|
74
|
+
s = sentinel(False)
|
|
75
|
+
|
|
76
|
+
def callback():
|
|
77
|
+
s.set(True)
|
|
78
|
+
|
|
79
|
+
tbl = Table([{"a": 1}])
|
|
80
|
+
callback_id = tbl.on_delete(callback)
|
|
81
|
+
tbl.remove_delete(callback_id)
|
|
82
|
+
|
|
83
|
+
tbl.delete()
|
|
84
|
+
|
|
85
|
+
assert s.get() is False
|
|
86
|
+
|
|
87
|
+
def test_view_delete_multiple_callback(self, sentinel):
|
|
88
|
+
s1 = sentinel(False)
|
|
89
|
+
s2 = sentinel(False)
|
|
90
|
+
|
|
91
|
+
def callback1():
|
|
92
|
+
s1.set(True)
|
|
93
|
+
|
|
94
|
+
def callback2():
|
|
95
|
+
s2.set(True)
|
|
96
|
+
|
|
97
|
+
tbl = Table([{"a": 1}])
|
|
98
|
+
view = tbl.view()
|
|
99
|
+
|
|
100
|
+
view.on_delete(callback1)
|
|
101
|
+
view.on_delete(callback2)
|
|
102
|
+
|
|
103
|
+
view.delete()
|
|
104
|
+
tbl.delete()
|
|
105
|
+
|
|
106
|
+
assert s1.get() is True
|
|
107
|
+
assert s2.get() is True
|
|
108
|
+
|
|
109
|
+
def test_view_remove_delete_callback(self, sentinel):
|
|
110
|
+
s = sentinel(False)
|
|
111
|
+
|
|
112
|
+
def callback():
|
|
113
|
+
s.set(True)
|
|
114
|
+
|
|
115
|
+
tbl = Table([{"a": 1}])
|
|
116
|
+
view = tbl.view()
|
|
117
|
+
|
|
118
|
+
callback_id = view.on_delete(callback)
|
|
119
|
+
view.remove_delete(callback_id)
|
|
120
|
+
|
|
121
|
+
view.delete()
|
|
122
|
+
tbl.delete()
|
|
123
|
+
|
|
124
|
+
assert s.get() is False
|