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,26 @@
|
|
|
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 TestToPolars(object):
|
|
20
|
+
def test_to_polars(self, superstore):
|
|
21
|
+
original_tbl = Table(superstore.to_dict(orient="records"))
|
|
22
|
+
df = original_tbl.view().to_polars()
|
|
23
|
+
tbl = Table(df)
|
|
24
|
+
assert tbl.size() == original_tbl.size()
|
|
25
|
+
df2 = tbl.view().to_polars()
|
|
26
|
+
assert df.equals(df2)
|
|
@@ -0,0 +1,545 @@
|
|
|
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 numpy as np
|
|
14
|
+
import pyarrow as pa
|
|
15
|
+
import pandas as pd
|
|
16
|
+
from datetime import date, datetime
|
|
17
|
+
from pytest import mark
|
|
18
|
+
import perspective as psp
|
|
19
|
+
|
|
20
|
+
client = psp.Server().new_local_client()
|
|
21
|
+
Table = client.table
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class TestUpdate(object):
|
|
25
|
+
@mark.skip(reason="Fix for null values update yet to be implemented")
|
|
26
|
+
def test_update_with_missing_or_null_values(self):
|
|
27
|
+
tbl = Table([{"a": "1", "b": "2"}, {"a": "3", "b": "4"}], index="a")
|
|
28
|
+
tbl.update([{"a": "1", "b": None}])
|
|
29
|
+
assert tbl.view().to_records() == [{"a": "1", "b": None}, {"a": "3", "b": "4"}]
|
|
30
|
+
|
|
31
|
+
data = pd.DataFrame({"a": ["1"], "b": [None]})
|
|
32
|
+
|
|
33
|
+
arrow_table = pa.Table.from_pandas(data, preserve_index=False)
|
|
34
|
+
|
|
35
|
+
# write arrow to stream
|
|
36
|
+
stream = pa.BufferOutputStream()
|
|
37
|
+
writer = pa.RecordBatchStreamWriter(
|
|
38
|
+
stream, arrow_table.schema
|
|
39
|
+
)
|
|
40
|
+
writer.write_table(arrow_table)
|
|
41
|
+
writer.close()
|
|
42
|
+
arrow = stream.getvalue().to_pybytes()
|
|
43
|
+
|
|
44
|
+
tbl.update(arrow)
|
|
45
|
+
assert tbl.size() == 2
|
|
46
|
+
assert tbl.view().to_records() == [{"a": "1", "b": ""}, {"a": "3", "b": "4"}]
|
|
47
|
+
|
|
48
|
+
def test_update_from_schema(self):
|
|
49
|
+
tbl = Table({"a": "string", "b": "integer"})
|
|
50
|
+
tbl.update([{"a": "abc", "b": 123}])
|
|
51
|
+
assert tbl.view().to_records() == [{"a": "abc", "b": 123}]
|
|
52
|
+
|
|
53
|
+
def test_update_columnar_from_schema(self):
|
|
54
|
+
tbl = Table({"a": "string", "b": "integer"})
|
|
55
|
+
tbl.update({"a": ["abc"], "b": [123]})
|
|
56
|
+
assert tbl.view().to_records() == [{"a": "abc", "b": 123}]
|
|
57
|
+
|
|
58
|
+
def test_update_csv(self):
|
|
59
|
+
tbl = Table({"a": "string", "b": "integer"})
|
|
60
|
+
|
|
61
|
+
view = tbl.view()
|
|
62
|
+
tbl.update("a,b\nxyz,123\ndef,100000000")
|
|
63
|
+
|
|
64
|
+
assert view.to_columns() == {"a": ["xyz", "def"], "b": [123, 100000000]}
|
|
65
|
+
|
|
66
|
+
def test_update_csv_indexed(self):
|
|
67
|
+
tbl = Table({"a": "string", "b": "float"}, index="a")
|
|
68
|
+
|
|
69
|
+
view = tbl.view()
|
|
70
|
+
tbl.update("a,b\nxyz,1.23456718\ndef,100000000.1")
|
|
71
|
+
|
|
72
|
+
assert view.to_columns() == {
|
|
73
|
+
"a": ["def", "xyz"],
|
|
74
|
+
"b": [100000000.1, 1.23456718],
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
tbl.update("a,b\nxyz,0.00000001\ndef,1234.5678\nefg,100.2")
|
|
78
|
+
|
|
79
|
+
assert view.to_columns() == {
|
|
80
|
+
"a": ["def", "efg", "xyz"],
|
|
81
|
+
"b": [1234.5678, 100.2, 0.00000001],
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
def test_update_append(self):
|
|
85
|
+
tbl = Table([{"a": "abc", "b": 123}])
|
|
86
|
+
tbl.update([{"a": "def", "b": 456}])
|
|
87
|
+
assert tbl.view().to_records() == [
|
|
88
|
+
{"a": "abc", "b": 123},
|
|
89
|
+
{"a": "def", "b": 456},
|
|
90
|
+
]
|
|
91
|
+
|
|
92
|
+
def test_update_partial(self):
|
|
93
|
+
tbl = Table([{"a": "abc", "b": 123}], index="a")
|
|
94
|
+
tbl.update([{"a": "abc", "b": 456}])
|
|
95
|
+
assert tbl.view().to_records() == [{"a": "abc", "b": 456}]
|
|
96
|
+
|
|
97
|
+
def test_update_partial_add_row(self):
|
|
98
|
+
tbl = Table([{"a": "abc", "b": 123}], index="a")
|
|
99
|
+
tbl.update([{"a": "abc", "b": 456}, {"a": "def"}])
|
|
100
|
+
assert tbl.view().to_records() == [
|
|
101
|
+
{"a": "abc", "b": 456},
|
|
102
|
+
{"a": "def", "b": None},
|
|
103
|
+
]
|
|
104
|
+
|
|
105
|
+
def test_update_partial_noop(self):
|
|
106
|
+
tbl = Table([{"a": "abc", "b": 1, "c": 2}], index="a")
|
|
107
|
+
tbl.update([{"a": "abc", "b": 456}])
|
|
108
|
+
assert tbl.view().to_records() == [{"a": "abc", "b": 456, "c": 2}]
|
|
109
|
+
|
|
110
|
+
def test_update_partial_unset(self):
|
|
111
|
+
tbl = Table(
|
|
112
|
+
[{"a": "abc", "b": 1, "c": 2}, {"a": "def", "b": 3, "c": 4}], index="a"
|
|
113
|
+
)
|
|
114
|
+
tbl.update([{"a": "abc"}, {"a": "def", "c": None}])
|
|
115
|
+
assert tbl.view().to_records() == [
|
|
116
|
+
{"a": "abc", "b": 1, "c": 2},
|
|
117
|
+
{"a": "def", "b": 3, "c": None},
|
|
118
|
+
]
|
|
119
|
+
|
|
120
|
+
def test_update_columnar_partial_add_row(self):
|
|
121
|
+
tbl = Table([{"a": "abc", "b": 123}], index="a")
|
|
122
|
+
|
|
123
|
+
tbl.update({"a": ["abc", "def"], "b": [456, None]})
|
|
124
|
+
|
|
125
|
+
assert tbl.view().to_records() == [
|
|
126
|
+
{"a": "abc", "b": 456},
|
|
127
|
+
{"a": "def", "b": None},
|
|
128
|
+
]
|
|
129
|
+
|
|
130
|
+
def test_update_columnar_partial_noop(self):
|
|
131
|
+
tbl = Table([{"a": "abc", "b": 1, "c": 2}], index="a")
|
|
132
|
+
|
|
133
|
+
# no-op because "c" is not in the update dataset
|
|
134
|
+
tbl.update({"a": ["abc"], "b": [456]})
|
|
135
|
+
|
|
136
|
+
assert tbl.view().to_records() == [{"a": "abc", "b": 456, "c": 2}]
|
|
137
|
+
|
|
138
|
+
def test_update_columnar_partial_unset(self):
|
|
139
|
+
tbl = Table(
|
|
140
|
+
[{"a": "abc", "b": 1, "c": 2}, {"a": "def", "b": 3, "c": 4}], index="a"
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
tbl.update({"a": ["abc"], "b": [None]})
|
|
144
|
+
|
|
145
|
+
assert tbl.view().to_records() == [
|
|
146
|
+
{"a": "abc", "b": None, "c": 2},
|
|
147
|
+
{"a": "def", "b": 3, "c": 4},
|
|
148
|
+
]
|
|
149
|
+
|
|
150
|
+
def test_update_partial_subcolumn(self):
|
|
151
|
+
tbl = Table([{"a": "abc", "b": 123, "c": 456}], index="a")
|
|
152
|
+
tbl.update([{"a": "abc", "c": 1234}])
|
|
153
|
+
assert tbl.view().to_records() == [{"a": "abc", "b": 123, "c": 1234}]
|
|
154
|
+
|
|
155
|
+
def test_update_partial_subcolumn_dict(self):
|
|
156
|
+
tbl = Table([{"a": "abc", "b": 123, "c": 456}], index="a")
|
|
157
|
+
tbl.update({"a": ["abc"], "c": [1234]})
|
|
158
|
+
assert tbl.view().to_records() == [{"a": "abc", "b": 123, "c": 1234}]
|
|
159
|
+
|
|
160
|
+
def test_update_partial_cols_more_columns_than_table(self):
|
|
161
|
+
tbl = Table([{"a": "abc", "b": 123}], index="a")
|
|
162
|
+
tbl.update([{"a": "abc", "b": 456, "c": 789}])
|
|
163
|
+
assert tbl.view().to_records() == [{"a": "abc", "b": 456}]
|
|
164
|
+
|
|
165
|
+
def test_update_columnar_append(self):
|
|
166
|
+
tbl = Table({"a": ["abc"], "b": [123]})
|
|
167
|
+
tbl.update({"a": ["def"], "b": [456]})
|
|
168
|
+
assert tbl.view().to_records() == [
|
|
169
|
+
{"a": "abc", "b": 123},
|
|
170
|
+
{"a": "def", "b": 456},
|
|
171
|
+
]
|
|
172
|
+
|
|
173
|
+
def test_update_columnar_partial(self):
|
|
174
|
+
tbl = Table({"a": ["abc"], "b": [123]}, index="a")
|
|
175
|
+
tbl.update({"a": ["abc"], "b": [456]})
|
|
176
|
+
assert tbl.view().to_records() == [{"a": "abc", "b": 456}]
|
|
177
|
+
|
|
178
|
+
# make sure already created views are notified properly
|
|
179
|
+
def test_update_from_schema_notify(self):
|
|
180
|
+
tbl = Table({"a": "string", "b": "integer"})
|
|
181
|
+
view = tbl.view()
|
|
182
|
+
assert view.num_rows() == 0
|
|
183
|
+
tbl.update([{"a": "abc", "b": 123}])
|
|
184
|
+
assert view.to_records() == [{"a": "abc", "b": 123}]
|
|
185
|
+
|
|
186
|
+
def test_update_columnar_from_schema_notify(self):
|
|
187
|
+
tbl = Table({"a": "string", "b": "integer"})
|
|
188
|
+
view = tbl.view()
|
|
189
|
+
assert view.num_rows() == 0
|
|
190
|
+
tbl.update({"a": ["abc"], "b": [123]})
|
|
191
|
+
assert view.to_records() == [{"a": "abc", "b": 123}]
|
|
192
|
+
|
|
193
|
+
def test_update_append_notify(self):
|
|
194
|
+
tbl = Table([{"a": "abc", "b": 123}])
|
|
195
|
+
view = tbl.view()
|
|
196
|
+
assert view.num_rows() == 1
|
|
197
|
+
tbl.update([{"a": "def", "b": 456}])
|
|
198
|
+
assert view.to_records() == [{"a": "abc", "b": 123}, {"a": "def", "b": 456}]
|
|
199
|
+
|
|
200
|
+
def test_update_partial_notify(self):
|
|
201
|
+
tbl = Table([{"a": "abc", "b": 123}], index="a")
|
|
202
|
+
view = tbl.view()
|
|
203
|
+
assert view.num_rows() == 1
|
|
204
|
+
tbl.update([{"a": "abc", "b": 456}])
|
|
205
|
+
assert view.to_records() == [{"a": "abc", "b": 456}]
|
|
206
|
+
|
|
207
|
+
def test_update_partial_cols_not_in_schema_notify(self):
|
|
208
|
+
tbl = Table([{"a": "abc", "b": 123}], index="a")
|
|
209
|
+
view = tbl.view()
|
|
210
|
+
assert view.num_rows() == 1
|
|
211
|
+
tbl.update([{"a": "abc", "b": 456, "c": 789}])
|
|
212
|
+
assert view.to_records() == [{"a": "abc", "b": 456}]
|
|
213
|
+
|
|
214
|
+
def test_update_columnar_append_notify(self):
|
|
215
|
+
tbl = Table({"a": ["abc"], "b": [123]})
|
|
216
|
+
view = tbl.view()
|
|
217
|
+
assert view.num_rows() == 1
|
|
218
|
+
tbl.update({"a": ["def"], "b": [456]})
|
|
219
|
+
assert view.to_records() == [{"a": "abc", "b": 123}, {"a": "def", "b": 456}]
|
|
220
|
+
|
|
221
|
+
def test_update_columnar_partial_notify(self):
|
|
222
|
+
tbl = Table({"a": ["abc"], "b": [123]}, index="a")
|
|
223
|
+
view = tbl.view()
|
|
224
|
+
assert view.num_rows() == 1
|
|
225
|
+
tbl.update({"a": ["abc"], "b": [456]})
|
|
226
|
+
assert view.to_records() == [{"a": "abc", "b": 456}]
|
|
227
|
+
|
|
228
|
+
# bool
|
|
229
|
+
|
|
230
|
+
def test_update_bool_from_schema(self):
|
|
231
|
+
bool_data = [{"a": True, "b": False}, {"a": True, "b": True}]
|
|
232
|
+
tbl = Table({"a": "boolean", "b": "boolean"})
|
|
233
|
+
tbl.update(bool_data)
|
|
234
|
+
assert tbl.size() == 2
|
|
235
|
+
assert tbl.view().to_records() == bool_data
|
|
236
|
+
|
|
237
|
+
def test_update_bool_str_from_schema(self):
|
|
238
|
+
bool_data = [{"a": "True", "b": "False"}, {"a": "True", "b": "True"}]
|
|
239
|
+
tbl = Table({"a": "boolean", "b": "boolean"})
|
|
240
|
+
tbl.update(bool_data)
|
|
241
|
+
assert tbl.size() == 2
|
|
242
|
+
assert tbl.view().to_records() == [
|
|
243
|
+
{"a": True, "b": False},
|
|
244
|
+
{"a": True, "b": True},
|
|
245
|
+
]
|
|
246
|
+
|
|
247
|
+
@mark.skip(reason="We may not want to support this")
|
|
248
|
+
def test_update_bool_str_all_formats_from_schema(self):
|
|
249
|
+
bool_data = [
|
|
250
|
+
{"a": "True", "b": "False"},
|
|
251
|
+
{"a": "t", "b": "f"},
|
|
252
|
+
{"a": "true", "b": "false"},
|
|
253
|
+
{"a": 1, "b": 0},
|
|
254
|
+
{"a": "on", "b": "off"},
|
|
255
|
+
]
|
|
256
|
+
tbl = Table({"a": "boolean", "b": "boolean"})
|
|
257
|
+
tbl.update(bool_data)
|
|
258
|
+
assert tbl.size() == 5
|
|
259
|
+
assert tbl.view().to_columns() == {
|
|
260
|
+
"a": [True, True, True, True, True],
|
|
261
|
+
"b": [False, False, False, False, False],
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
def test_update_bool_int_from_schema(self):
|
|
265
|
+
bool_data = [{"a": 1, "b": 0}, {"a": 1, "b": 0}]
|
|
266
|
+
tbl = Table({"a": "boolean", "b": "boolean"})
|
|
267
|
+
tbl.update(bool_data)
|
|
268
|
+
assert tbl.size() == 2
|
|
269
|
+
assert tbl.view().to_columns() == {"a": [True, True], "b": [False, False]}
|
|
270
|
+
|
|
271
|
+
# dates and datetimes
|
|
272
|
+
def test_update_date(self, util):
|
|
273
|
+
tbl = Table({"a": [date(2019, 7, 11)]})
|
|
274
|
+
tbl.update([{"a": date(2019, 7, 12)}])
|
|
275
|
+
assert tbl.view().to_records() == [
|
|
276
|
+
{"a": util.to_timestamp(datetime(2019, 7, 11))},
|
|
277
|
+
{"a": util.to_timestamp(datetime(2019, 7, 12))},
|
|
278
|
+
]
|
|
279
|
+
|
|
280
|
+
@mark.skip # We do not support numpy.
|
|
281
|
+
def test_update_date_np(self, util):
|
|
282
|
+
tbl = Table({"a": [date(2019, 7, 11)]})
|
|
283
|
+
tbl.update([{"a": np.datetime64(date(2019, 7, 12))}])
|
|
284
|
+
assert tbl.view().to_records() == [
|
|
285
|
+
{"a": util.to_timestamp(datetime(2019, 7, 11))},
|
|
286
|
+
{"a": util.to_timestamp(datetime(2019, 7, 12))},
|
|
287
|
+
]
|
|
288
|
+
|
|
289
|
+
def test_update_datetime(self, util):
|
|
290
|
+
tbl = Table({"a": [datetime(2019, 7, 11, 11, 0)]})
|
|
291
|
+
tbl.update([{"a": datetime(2019, 7, 12, 11, 0)}])
|
|
292
|
+
assert tbl.view().to_records() == [
|
|
293
|
+
{"a": util.to_timestamp(datetime(2019, 7, 11, 11, 0))},
|
|
294
|
+
{"a": util.to_timestamp(datetime(2019, 7, 12, 11, 0))},
|
|
295
|
+
]
|
|
296
|
+
|
|
297
|
+
@mark.skip # We do not support numpy.
|
|
298
|
+
def test_update_datetime_np(self, util):
|
|
299
|
+
tbl = Table({"a": [datetime(2019, 7, 11, 11, 0)]})
|
|
300
|
+
tbl.update([{"a": np.datetime64(datetime(2019, 7, 12, 11, 0))}])
|
|
301
|
+
assert tbl.view().to_records() == [
|
|
302
|
+
{"a": util.to_timestamp(datetime(2019, 7, 11, 11, 0))},
|
|
303
|
+
{"a": util.to_timestamp(datetime(2019, 7, 12, 11, 0))},
|
|
304
|
+
]
|
|
305
|
+
|
|
306
|
+
@mark.skip # We do not support numpy.
|
|
307
|
+
def test_update_datetime_np_ts(self, util):
|
|
308
|
+
tbl = Table({"a": [datetime(2019, 7, 11, 11, 0)]})
|
|
309
|
+
tbl.update([{"a": np.datetime64("2019-07-12T11:00")}])
|
|
310
|
+
assert tbl.view().to_records() == [
|
|
311
|
+
{"a": util.to_timestamp(datetime(2019, 7, 11, 11, 0))},
|
|
312
|
+
{"a": util.to_timestamp(datetime(2019, 7, 12, 11, 0))},
|
|
313
|
+
]
|
|
314
|
+
|
|
315
|
+
def test_update_datetime_timestamp_seconds(self, util):
|
|
316
|
+
ts = util.to_timestamp(datetime(2019, 7, 12, 11, 0, 0))
|
|
317
|
+
tbl = Table({"a": [datetime(2019, 7, 11, 11, 0)]})
|
|
318
|
+
tbl.update([{"a": ts}])
|
|
319
|
+
assert tbl.view().to_records() == [
|
|
320
|
+
{"a": util.to_timestamp(datetime(2019, 7, 11, 11, 0))},
|
|
321
|
+
{"a": util.to_timestamp(datetime(2019, 7, 12, 11, 0))},
|
|
322
|
+
]
|
|
323
|
+
|
|
324
|
+
def test_update_datetime_timestamp_ms(self, util):
|
|
325
|
+
ts = util.to_timestamp(datetime(2019, 7, 12, 11, 0, 0))
|
|
326
|
+
tbl = Table({"a": [datetime(2019, 7, 11, 11, 0)]})
|
|
327
|
+
tbl.update([{"a": ts}])
|
|
328
|
+
assert tbl.view().to_records() == [
|
|
329
|
+
{"a": util.to_timestamp(datetime(2019, 7, 11, 11, 0))},
|
|
330
|
+
{"a": util.to_timestamp(datetime(2019, 7, 12, 11, 0))},
|
|
331
|
+
]
|
|
332
|
+
|
|
333
|
+
# partial date & datetime updates
|
|
334
|
+
|
|
335
|
+
def test_update_date_partial(self, util):
|
|
336
|
+
tbl = Table({"a": [date(2019, 7, 11)], "b": [1]}, index="b")
|
|
337
|
+
tbl.update([{"a": date(2019, 7, 12), "b": 1}])
|
|
338
|
+
assert tbl.view().to_records() == [
|
|
339
|
+
{"a": util.to_timestamp(datetime(2019, 7, 12)), "b": 1}
|
|
340
|
+
]
|
|
341
|
+
|
|
342
|
+
@mark.skip # We do not support numpy anymore.
|
|
343
|
+
def test_update_date_np_partial(self, util):
|
|
344
|
+
tbl = Table({"a": [date(2019, 7, 11)], "b": [1]}, index="b")
|
|
345
|
+
tbl.update([{"a": np.datetime64(date(2019, 7, 12)), "b": 1}])
|
|
346
|
+
assert tbl.view().to_records() == [
|
|
347
|
+
{"a": util.to_timestamp(datetime(2019, 7, 12)), "b": 1}
|
|
348
|
+
]
|
|
349
|
+
|
|
350
|
+
def test_update_datetime_partial(self, util):
|
|
351
|
+
tbl = Table({"a": [datetime(2019, 7, 11, 11, 0)], "b": [1]}, index="b")
|
|
352
|
+
tbl.update([{"a": datetime(2019, 7, 12, 11, 0), "b": 1}])
|
|
353
|
+
assert tbl.view().to_records() == [
|
|
354
|
+
{"a": util.to_timestamp(datetime(2019, 7, 12, 11, 0)), "b": 1}
|
|
355
|
+
]
|
|
356
|
+
|
|
357
|
+
@mark.skip # We do not support numpy anymore.
|
|
358
|
+
def test_update_datetime_np_partial(self, util):
|
|
359
|
+
tbl = Table({"a": [datetime(2019, 7, 11, 11, 0)], "b": [1]}, index="b")
|
|
360
|
+
tbl.update([{"a": np.datetime64(datetime(2019, 7, 12, 11, 0)), "b": 1}])
|
|
361
|
+
assert tbl.view().to_records() == [
|
|
362
|
+
{"a": util.to_timestamp(datetime(2019, 7, 12, 11, 0)), "b": 1}
|
|
363
|
+
]
|
|
364
|
+
|
|
365
|
+
@mark.skip # We do not support numpy anymore.
|
|
366
|
+
def test_update_datetime_np_ts_partial(self, util):
|
|
367
|
+
tbl = Table({"a": [datetime(2019, 7, 11, 11, 0)], "b": [1]}, index="b")
|
|
368
|
+
tbl.update([{"a": np.datetime64("2019-07-12T11:00"), "b": 1}])
|
|
369
|
+
assert tbl.view().to_records() == [
|
|
370
|
+
{"a": util.to_timestamp(datetime(2019, 7, 12, 11, 0)), "b": 1}
|
|
371
|
+
]
|
|
372
|
+
|
|
373
|
+
def test_update_datetime_timestamp_seconds_partial(self, util):
|
|
374
|
+
ts = util.to_timestamp(datetime(2019, 7, 12, 11, 0, 0))
|
|
375
|
+
tbl = Table({"a": [datetime(2019, 7, 11, 11, 0)], "idx": [1]}, index="idx")
|
|
376
|
+
tbl.update([{"a": ts, "idx": 1}])
|
|
377
|
+
assert tbl.view().to_records() == [
|
|
378
|
+
{"a": util.to_timestamp(datetime(2019, 7, 12, 11, 0)), "idx": 1}
|
|
379
|
+
]
|
|
380
|
+
|
|
381
|
+
def test_update_datetime_timestamp_ms_partial(self, util):
|
|
382
|
+
ts = util.to_timestamp(datetime(2019, 7, 12, 11, 0, 0))
|
|
383
|
+
tbl = Table({"a": [datetime(2019, 7, 11, 11, 0)], "idx": [1]}, index="idx")
|
|
384
|
+
tbl.update([{"a": ts, "idx": 1}])
|
|
385
|
+
assert tbl.view().to_records() == [
|
|
386
|
+
{"a": util.to_timestamp(datetime(2019, 7, 12, 11, 0)), "idx": 1}
|
|
387
|
+
]
|
|
388
|
+
|
|
389
|
+
# updating dates using implicit index
|
|
390
|
+
|
|
391
|
+
def test_update_date_partial_implicit(self, util):
|
|
392
|
+
tbl = Table({"a": [date(2019, 7, 11)]})
|
|
393
|
+
tbl.update([{"a": date(2019, 7, 12), "__INDEX__": 0}])
|
|
394
|
+
assert tbl.view().to_records() == [
|
|
395
|
+
{"a": util.to_timestamp(datetime(2019, 7, 12))}
|
|
396
|
+
]
|
|
397
|
+
|
|
398
|
+
@mark.skip # We do not support numpy anymore.
|
|
399
|
+
def test_update_date_np_partial_implicit(self, util):
|
|
400
|
+
tbl = Table({"a": [date(2019, 7, 11)]})
|
|
401
|
+
tbl.update([{"a": np.datetime64(date(2019, 7, 12)), "__INDEX__": 0}])
|
|
402
|
+
assert tbl.view().to_records() == [
|
|
403
|
+
{"a": util.to_timestamp(datetime(2019, 7, 12))}
|
|
404
|
+
]
|
|
405
|
+
|
|
406
|
+
def test_update_datetime_partial_implicit(self, util):
|
|
407
|
+
tbl = Table({"a": [datetime(2019, 7, 11, 11, 0)]})
|
|
408
|
+
tbl.update([{"a": datetime(2019, 7, 12, 11, 0), "__INDEX__": 0}])
|
|
409
|
+
assert tbl.view().to_records() == [
|
|
410
|
+
{"a": util.to_timestamp(datetime(2019, 7, 12, 11, 0))}
|
|
411
|
+
]
|
|
412
|
+
|
|
413
|
+
@mark.skip # We do not support numpy anymore.
|
|
414
|
+
def test_update_datetime_np_partial_implicit(self, util):
|
|
415
|
+
tbl = Table({"a": [datetime(2019, 7, 11, 11, 0)]})
|
|
416
|
+
tbl.update([{"a": np.datetime64(datetime(2019, 7, 12, 11, 0)), "__INDEX__": 0}])
|
|
417
|
+
assert tbl.view().to_records() == [
|
|
418
|
+
{"a": util.to_timestamp(datetime(2019, 7, 12, 11, 0))}
|
|
419
|
+
]
|
|
420
|
+
|
|
421
|
+
@mark.skip # We do not support numpy anymore.
|
|
422
|
+
def test_update_datetime_np_ts_partial_implicit(self, util):
|
|
423
|
+
tbl = Table({"a": [datetime(2019, 7, 11, 11, 0)]})
|
|
424
|
+
tbl.update([{"a": np.datetime64("2019-07-12T11:00"), "__INDEX__": 0}])
|
|
425
|
+
assert tbl.view().to_records() == [
|
|
426
|
+
{"a": util.to_timestamp(datetime(2019, 7, 12, 11, 0))}
|
|
427
|
+
]
|
|
428
|
+
|
|
429
|
+
# implicit index
|
|
430
|
+
|
|
431
|
+
def test_update_implicit_index(self):
|
|
432
|
+
data = [{"a": 1, "b": 2}, {"a": 2, "b": 3}]
|
|
433
|
+
tbl = Table(data)
|
|
434
|
+
view = tbl.view()
|
|
435
|
+
tbl.update([{"__INDEX__": 0, "a": 3, "b": 15}])
|
|
436
|
+
assert view.to_records() == [{"a": 3, "b": 15}, {"a": 2, "b": 3}]
|
|
437
|
+
|
|
438
|
+
def test_update_implicit_index_dict_noop(self):
|
|
439
|
+
data = [{"a": 1, "b": 2}, {"a": 2, "b": 3}]
|
|
440
|
+
tbl = Table(data)
|
|
441
|
+
view = tbl.view()
|
|
442
|
+
|
|
443
|
+
# "b" does not exist in dataset, so no-op
|
|
444
|
+
tbl.update(
|
|
445
|
+
{
|
|
446
|
+
"__INDEX__": [0],
|
|
447
|
+
"a": [3],
|
|
448
|
+
}
|
|
449
|
+
)
|
|
450
|
+
assert view.to_records() == [{"a": 3, "b": 2}, {"a": 2, "b": 3}]
|
|
451
|
+
|
|
452
|
+
def test_update_implicit_index_dict_unset_with_null(self):
|
|
453
|
+
data = [{"a": 1, "b": 2}, {"a": 2, "b": 3}]
|
|
454
|
+
tbl = Table(data)
|
|
455
|
+
view = tbl.view()
|
|
456
|
+
|
|
457
|
+
# unset because "b" is null
|
|
458
|
+
tbl.update({"__INDEX__": [0], "a": [3], "b": [None]})
|
|
459
|
+
assert view.to_records() == [{"a": 3, "b": None}, {"a": 2, "b": 3}]
|
|
460
|
+
|
|
461
|
+
def test_update_implicit_index_multi(self):
|
|
462
|
+
data = [{"a": 1, "b": 2}, {"a": 2, "b": 3}, {"a": 4, "b": 5}]
|
|
463
|
+
tbl = Table(data)
|
|
464
|
+
view = tbl.view()
|
|
465
|
+
tbl.update(
|
|
466
|
+
[
|
|
467
|
+
{
|
|
468
|
+
"__INDEX__": 0,
|
|
469
|
+
"a": 3,
|
|
470
|
+
},
|
|
471
|
+
{"__INDEX__": 2, "a": 5},
|
|
472
|
+
]
|
|
473
|
+
)
|
|
474
|
+
assert view.to_records() == [
|
|
475
|
+
{"a": 3, "b": 2},
|
|
476
|
+
{"a": 2, "b": 3},
|
|
477
|
+
{"a": 5, "b": 5},
|
|
478
|
+
]
|
|
479
|
+
|
|
480
|
+
def test_update_implicit_index_symmetric(self):
|
|
481
|
+
data = [{"a": 1, "b": 2}, {"a": 2, "b": 3}]
|
|
482
|
+
tbl = Table(data)
|
|
483
|
+
view = tbl.view()
|
|
484
|
+
records = view.to_records(index=True)
|
|
485
|
+
idx = records[0]["__INDEX__"][0] # XXX: How should we grab this?
|
|
486
|
+
tbl.update([{"__INDEX__": idx, "a": 3}])
|
|
487
|
+
assert view.to_records() == [{"a": 3, "b": 2}, {"a": 2, "b": 3}]
|
|
488
|
+
|
|
489
|
+
def test_update_explicit_index(self):
|
|
490
|
+
data = [{"a": 1, "b": 2}, {"a": 2, "b": 3}]
|
|
491
|
+
tbl = Table(data, index="a")
|
|
492
|
+
view = tbl.view()
|
|
493
|
+
tbl.update([{"a": 1, "b": 3}])
|
|
494
|
+
assert view.to_records() == [{"a": 1, "b": 3}, {"a": 2, "b": 3}]
|
|
495
|
+
|
|
496
|
+
def test_update_explicit_index_multi(self):
|
|
497
|
+
data = [{"a": 1, "b": 2}, {"a": 2, "b": 3}, {"a": 3, "b": 4}]
|
|
498
|
+
tbl = Table(data, index="a")
|
|
499
|
+
view = tbl.view()
|
|
500
|
+
tbl.update([{"a": 1, "b": 3}, {"a": 3, "b": 5}])
|
|
501
|
+
assert view.to_records() == [
|
|
502
|
+
{"a": 1, "b": 3},
|
|
503
|
+
{"a": 2, "b": 3},
|
|
504
|
+
{"a": 3, "b": 5},
|
|
505
|
+
]
|
|
506
|
+
|
|
507
|
+
def test_update_explicit_index_multi_append(self):
|
|
508
|
+
data = [{"a": 1, "b": 2}, {"a": 2, "b": 3}, {"a": 3, "b": 4}]
|
|
509
|
+
tbl = Table(data, index="a")
|
|
510
|
+
view = tbl.view()
|
|
511
|
+
tbl.update([{"a": 1, "b": 3}, {"a": 12, "b": 5}])
|
|
512
|
+
assert view.to_records() == [
|
|
513
|
+
{"a": 1, "b": 3},
|
|
514
|
+
{"a": 2, "b": 3},
|
|
515
|
+
{"a": 3, "b": 4},
|
|
516
|
+
{"a": 12, "b": 5},
|
|
517
|
+
]
|
|
518
|
+
|
|
519
|
+
def test_update_explicit_index_multi_append_noindex(self):
|
|
520
|
+
data = [{"a": 1, "b": 2}, {"a": 2, "b": 3}, {"a": 3, "b": 4}]
|
|
521
|
+
tbl = Table(data, index="a")
|
|
522
|
+
view = tbl.view()
|
|
523
|
+
tbl.update([{"a": 1, "b": 3}, {"b": 5}])
|
|
524
|
+
assert view.to_records() == [
|
|
525
|
+
{"a": None, "b": 5},
|
|
526
|
+
{"a": 1, "b": 3},
|
|
527
|
+
{"a": 2, "b": 3},
|
|
528
|
+
{"a": 3, "b": 4},
|
|
529
|
+
]
|
|
530
|
+
|
|
531
|
+
def test_update_implicit_index_with_explicit_unset(self):
|
|
532
|
+
data = [{"a": 1, "b": 2}, {"a": 2, "b": 3}]
|
|
533
|
+
tbl = Table(data, index="a")
|
|
534
|
+
view = tbl.view()
|
|
535
|
+
tbl.update([{"__INDEX__": 1, "b": 3}])
|
|
536
|
+
assert view.to_records() == [{"a": 1, "b": 3}, {"a": 2, "b": 3}]
|
|
537
|
+
|
|
538
|
+
def test_update_implicit_index_with_explicit_set(self):
|
|
539
|
+
data = [{"a": 1, "b": 2}, {"a": 2, "b": 3}]
|
|
540
|
+
tbl = Table(data, index="a")
|
|
541
|
+
view = tbl.view()
|
|
542
|
+
tbl.update(
|
|
543
|
+
[{"__INDEX__": 1, "a": 1, "b": 3}]
|
|
544
|
+
) # should ignore re-specification of pkey
|
|
545
|
+
assert view.to_records() == [{"a": 1, "b": 3}, {"a": 2, "b": 3}]
|