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,201 @@
|
|
|
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
|
|
14
|
+
|
|
15
|
+
import asyncio
|
|
16
|
+
import random
|
|
17
|
+
import threading
|
|
18
|
+
|
|
19
|
+
from random import sample
|
|
20
|
+
from string import ascii_letters
|
|
21
|
+
from threading import Thread
|
|
22
|
+
from time import sleep
|
|
23
|
+
|
|
24
|
+
class TestServer(object):
|
|
25
|
+
def test_sync_updates_with_loop_callback_are_sync(self):
|
|
26
|
+
def feed(table):
|
|
27
|
+
y = 1000
|
|
28
|
+
while y > 0:
|
|
29
|
+
y -= 1
|
|
30
|
+
table.update([{"a": random.randint(0, 10), "index": y}])
|
|
31
|
+
|
|
32
|
+
perspective_server = Server()
|
|
33
|
+
loop = asyncio.new_event_loop()
|
|
34
|
+
thread = threading.Thread(target=loop.run_forever)
|
|
35
|
+
thread.start()
|
|
36
|
+
|
|
37
|
+
client = perspective_server.new_local_client()
|
|
38
|
+
table = client.table(
|
|
39
|
+
{"a": "integer", "index": "integer"}, index="index", name="test"
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
view = table.view()
|
|
43
|
+
global count
|
|
44
|
+
count = 0
|
|
45
|
+
|
|
46
|
+
def update(x):
|
|
47
|
+
global count
|
|
48
|
+
count += 1
|
|
49
|
+
|
|
50
|
+
view.on_update(update)
|
|
51
|
+
feed(table)
|
|
52
|
+
assert table.size() == 1000
|
|
53
|
+
assert count == 1000
|
|
54
|
+
loop.call_soon_threadsafe(loop.stop)
|
|
55
|
+
thread.join()
|
|
56
|
+
loop.close()
|
|
57
|
+
|
|
58
|
+
def test_concurrent_updates(self):
|
|
59
|
+
async def feed(table, loop):
|
|
60
|
+
y = 1000
|
|
61
|
+
while y > 0:
|
|
62
|
+
y -= 1
|
|
63
|
+
table.update([{"a": random.randint(0, 10), "index": y}])
|
|
64
|
+
await asyncio.sleep(0.001)
|
|
65
|
+
|
|
66
|
+
perspective_server = Server()
|
|
67
|
+
loop = asyncio.new_event_loop()
|
|
68
|
+
thread = threading.Thread(target=loop.run_forever)
|
|
69
|
+
thread.start()
|
|
70
|
+
|
|
71
|
+
client = perspective_server.new_local_client()
|
|
72
|
+
table = client.table(
|
|
73
|
+
{"a": "integer", "index": "integer"}, index="index", name="test"
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
view = table.view()
|
|
77
|
+
global count
|
|
78
|
+
count = 0
|
|
79
|
+
|
|
80
|
+
def update(x):
|
|
81
|
+
global count
|
|
82
|
+
count += 1
|
|
83
|
+
|
|
84
|
+
view.on_update(update)
|
|
85
|
+
asyncio.run_coroutine_threadsafe(feed(table, loop), loop).result()
|
|
86
|
+
assert table.size() == 1000
|
|
87
|
+
assert count == 1000
|
|
88
|
+
loop.call_soon_threadsafe(loop.stop)
|
|
89
|
+
thread.join()
|
|
90
|
+
loop.close()
|
|
91
|
+
|
|
92
|
+
def test_concurrent_updates_with_limit_tables_are_threadsafe(self):
|
|
93
|
+
TEST_ITERATIONS = 100
|
|
94
|
+
global running
|
|
95
|
+
perspective_server = Server()
|
|
96
|
+
client = perspective_server.new_local_client()
|
|
97
|
+
table = client.table(
|
|
98
|
+
{"col{}".format(i): "integer" for i in range(100)}, limit=100
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
running = True
|
|
102
|
+
|
|
103
|
+
# Create an updating thread that overlaps the index alot
|
|
104
|
+
def feed(table):
|
|
105
|
+
row = {"col{}".format(i): random.randint(0, 100) for i in range(100)}
|
|
106
|
+
while running:
|
|
107
|
+
table.update([row for _ in range(100)])
|
|
108
|
+
|
|
109
|
+
thread = threading.Thread(target=feed, args=(table,))
|
|
110
|
+
thread.start()
|
|
111
|
+
|
|
112
|
+
results = []
|
|
113
|
+
|
|
114
|
+
# Create a thread that serialized the table alot, checking for nulls
|
|
115
|
+
def feed2(table):
|
|
116
|
+
global running
|
|
117
|
+
view = table.view()
|
|
118
|
+
while len(results) < TEST_ITERATIONS:
|
|
119
|
+
arr = view.to_arrow()
|
|
120
|
+
table2 = client.table(arr)
|
|
121
|
+
view2 = table2.view()
|
|
122
|
+
json = view2.to_json(end_row=1)
|
|
123
|
+
view2.delete()
|
|
124
|
+
table2.delete()
|
|
125
|
+
results.append(json)
|
|
126
|
+
|
|
127
|
+
view.delete()
|
|
128
|
+
running = False
|
|
129
|
+
|
|
130
|
+
thread2 = threading.Thread(target=feed2, args=(table,))
|
|
131
|
+
thread2.start()
|
|
132
|
+
|
|
133
|
+
thread.join()
|
|
134
|
+
thread2.join()
|
|
135
|
+
|
|
136
|
+
assert table.size() == 100
|
|
137
|
+
for result in results:
|
|
138
|
+
for row in result:
|
|
139
|
+
for col, val in row.items():
|
|
140
|
+
assert val is not None
|
|
141
|
+
|
|
142
|
+
table.delete()
|
|
143
|
+
|
|
144
|
+
def test_concurrent_view_creation_on_separate_servers_are_threadsafe(self):
|
|
145
|
+
def run_perspective():
|
|
146
|
+
x = 1000
|
|
147
|
+
s = Server()
|
|
148
|
+
c = s.new_local_client()
|
|
149
|
+
t = c.table({"a": "string", "b": int})
|
|
150
|
+
t.view(expressions=["//tmp\nfalse"])
|
|
151
|
+
while x > 0:
|
|
152
|
+
t.update([{"a": "foo", "b": 42}])
|
|
153
|
+
x -= 1
|
|
154
|
+
|
|
155
|
+
thread1 = threading.Thread(target=run_perspective, daemon=True)
|
|
156
|
+
thread2 = threading.Thread(target=run_perspective, daemon=True)
|
|
157
|
+
thread1.start()
|
|
158
|
+
thread2.start()
|
|
159
|
+
thread1.join()
|
|
160
|
+
thread2.join()
|
|
161
|
+
|
|
162
|
+
def test_concurrent_view_creation_with_updates_are_threadsafe(self):
|
|
163
|
+
global running
|
|
164
|
+
s = Server()
|
|
165
|
+
schema = {
|
|
166
|
+
"a": "string",
|
|
167
|
+
"b": "string",
|
|
168
|
+
"c": "string",
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
group_bys = ["a", "b", "c"]
|
|
172
|
+
c = s.new_local_client()
|
|
173
|
+
t = c.table(schema, limit=10000)
|
|
174
|
+
running = True
|
|
175
|
+
|
|
176
|
+
def gen_views():
|
|
177
|
+
global running
|
|
178
|
+
for _ in range(100):
|
|
179
|
+
t.view(columns=list(schema.keys()), group_by=group_bys)
|
|
180
|
+
sleep(0.01)
|
|
181
|
+
running = False
|
|
182
|
+
|
|
183
|
+
def run_psp():
|
|
184
|
+
global running
|
|
185
|
+
while running:
|
|
186
|
+
t.update(
|
|
187
|
+
[
|
|
188
|
+
{
|
|
189
|
+
"a": "".join(sample(ascii_letters, 4)),
|
|
190
|
+
"b": "".join(sample(ascii_letters, 4)),
|
|
191
|
+
"c": "".join(sample(ascii_letters, 4)),
|
|
192
|
+
}
|
|
193
|
+
]
|
|
194
|
+
)
|
|
195
|
+
|
|
196
|
+
thread1 = Thread(target=run_psp, daemon=True)
|
|
197
|
+
thread2 = Thread(target=gen_views, daemon=True)
|
|
198
|
+
thread1.start()
|
|
199
|
+
thread2.start()
|
|
200
|
+
thread1.join()
|
|
201
|
+
thread2.join()
|
|
@@ -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
|
+
# ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|