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,1022 @@
|
|
|
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 datetime import date, datetime
|
|
14
|
+
import numpy as np
|
|
15
|
+
import pandas as pd
|
|
16
|
+
from pytest import raises, mark
|
|
17
|
+
import perspective as psp
|
|
18
|
+
|
|
19
|
+
client = psp.Server().new_local_client()
|
|
20
|
+
Table = client.table
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@mark.skip(reason="We do not support numpy types in the Table constructor")
|
|
24
|
+
class TestTableNumpy(object):
|
|
25
|
+
def test_empty_table(self):
|
|
26
|
+
tbl = Table([])
|
|
27
|
+
assert tbl.size() == 0
|
|
28
|
+
|
|
29
|
+
def test_table_int(self):
|
|
30
|
+
data = {"a": np.array([1, 2, 3]), "b": np.array([4, 5, 6])}
|
|
31
|
+
tbl = Table(data)
|
|
32
|
+
assert tbl.size() == 3
|
|
33
|
+
assert tbl.view().to_columns() == {"a": [1, 2, 3], "b": [4, 5, 6]}
|
|
34
|
+
|
|
35
|
+
def test_table_int_lots_of_columns(self):
|
|
36
|
+
data = {
|
|
37
|
+
"a": np.array([1, 2, 3]),
|
|
38
|
+
"b": np.array([4, 5, 6]),
|
|
39
|
+
"c": np.array([4, 5, 6]),
|
|
40
|
+
"d": np.array([4, 5, 6]),
|
|
41
|
+
"e": np.array([4, 5, 6]),
|
|
42
|
+
"f": np.array([4, 5, 6]),
|
|
43
|
+
}
|
|
44
|
+
tbl = Table(data)
|
|
45
|
+
assert tbl.size() == 3
|
|
46
|
+
assert tbl.view().to_columns() == {
|
|
47
|
+
"a": [1, 2, 3],
|
|
48
|
+
"b": [4, 5, 6],
|
|
49
|
+
"c": [4, 5, 6],
|
|
50
|
+
"d": [4, 5, 6],
|
|
51
|
+
"e": [4, 5, 6],
|
|
52
|
+
"f": [4, 5, 6],
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
def test_table_int_with_None(self):
|
|
56
|
+
data = {
|
|
57
|
+
"a": np.array([1, 2, 3, None, None]),
|
|
58
|
+
"b": np.array([4, 5, 6, None, None]),
|
|
59
|
+
}
|
|
60
|
+
tbl = Table(data)
|
|
61
|
+
assert tbl.size() == 5
|
|
62
|
+
assert tbl.view().to_columns() == {
|
|
63
|
+
"a": [1, 2, 3, None, None],
|
|
64
|
+
"b": [4, 5, 6, None, None],
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
def test_table_int8(self):
|
|
68
|
+
data = {
|
|
69
|
+
"a": np.array([1, 2, 3]).astype(np.int8),
|
|
70
|
+
"b": np.array([4, 5, 6]).astype(np.int8),
|
|
71
|
+
}
|
|
72
|
+
tbl = Table(data)
|
|
73
|
+
assert tbl.size() == 3
|
|
74
|
+
assert tbl.view().to_columns() == {"a": [1, 2, 3], "b": [4, 5, 6]}
|
|
75
|
+
|
|
76
|
+
def test_table_int16(self):
|
|
77
|
+
data = {
|
|
78
|
+
"a": np.array([1, 2, 3]).astype(np.int16),
|
|
79
|
+
"b": np.array([4, 5, 6]).astype(np.int16),
|
|
80
|
+
}
|
|
81
|
+
tbl = Table(data)
|
|
82
|
+
assert tbl.size() == 3
|
|
83
|
+
assert tbl.view().to_columns() == {"a": [1, 2, 3], "b": [4, 5, 6]}
|
|
84
|
+
|
|
85
|
+
def test_table_int32(self):
|
|
86
|
+
data = {
|
|
87
|
+
"a": np.array([1, 2, 3]).astype(np.int32),
|
|
88
|
+
"b": np.array([4, 5, 6]).astype(np.int32),
|
|
89
|
+
}
|
|
90
|
+
tbl = Table(data)
|
|
91
|
+
assert tbl.size() == 3
|
|
92
|
+
assert tbl.view().to_columns() == {"a": [1, 2, 3], "b": [4, 5, 6]}
|
|
93
|
+
|
|
94
|
+
def test_table_int64(self):
|
|
95
|
+
data = {
|
|
96
|
+
"a": np.array([1, 2, 3]).astype(np.int64),
|
|
97
|
+
"b": np.array([4, 5, 6]).astype(np.int64),
|
|
98
|
+
}
|
|
99
|
+
tbl = Table(data)
|
|
100
|
+
assert tbl.size() == 3
|
|
101
|
+
assert tbl.view().to_columns() == {"a": [1, 2, 3], "b": [4, 5, 6]}
|
|
102
|
+
|
|
103
|
+
def test_table_float(self):
|
|
104
|
+
data = {"a": np.array([1.1, 2.2]), "b": np.array([3.3, 4.4])}
|
|
105
|
+
tbl = Table(data)
|
|
106
|
+
assert tbl.size() == 2
|
|
107
|
+
assert tbl.view().to_columns() == {"a": [1.1, 2.2], "b": [3.3, 4.4]}
|
|
108
|
+
|
|
109
|
+
def test_table_float32(self):
|
|
110
|
+
data = {
|
|
111
|
+
"a": np.array([1.1, 2.2]).astype(np.float32),
|
|
112
|
+
"b": np.array([3.3, 4.4]).astype(np.float32),
|
|
113
|
+
}
|
|
114
|
+
tbl = Table(data)
|
|
115
|
+
assert tbl.size() == 2
|
|
116
|
+
assert tbl.view().to_columns() == {
|
|
117
|
+
# py::cast automatically upcasts to 64-bit float
|
|
118
|
+
"a": [1.100000023841858, 2.200000047683716],
|
|
119
|
+
"b": [3.299999952316284, 4.400000095367432],
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
def test_table_float64(self):
|
|
123
|
+
data = {
|
|
124
|
+
"a": np.array([1.1, 2.2]).astype(np.float64),
|
|
125
|
+
"b": np.array([3.3, 4.4]).astype(np.float64),
|
|
126
|
+
}
|
|
127
|
+
tbl = Table(data)
|
|
128
|
+
assert tbl.size() == 2
|
|
129
|
+
assert tbl.view().to_columns() == {"a": [1.1, 2.2], "b": [3.3, 4.4]}
|
|
130
|
+
|
|
131
|
+
# booleans
|
|
132
|
+
|
|
133
|
+
def test_table_bool(self):
|
|
134
|
+
data = {"a": np.array([True, False]), "b": np.array([False, True])}
|
|
135
|
+
tbl = Table(data)
|
|
136
|
+
assert tbl.size() == 2
|
|
137
|
+
assert tbl.view().to_columns() == {"a": [True, False], "b": [False, True]}
|
|
138
|
+
|
|
139
|
+
def test_table_bool8(self):
|
|
140
|
+
data = {
|
|
141
|
+
"a": np.array([True, False]).astype(np.bool8),
|
|
142
|
+
"b": np.array([False, True]).astype(np.bool8),
|
|
143
|
+
}
|
|
144
|
+
tbl = Table(data)
|
|
145
|
+
assert tbl.size() == 2
|
|
146
|
+
assert tbl.view().to_columns() == {"a": [True, False], "b": [False, True]}
|
|
147
|
+
|
|
148
|
+
def test_table_bool_with_none(self):
|
|
149
|
+
data = {
|
|
150
|
+
"a": np.array([True, False, None, False]),
|
|
151
|
+
"b": np.array([False, True, None, False]),
|
|
152
|
+
}
|
|
153
|
+
tbl = Table(data)
|
|
154
|
+
assert tbl.size() == 4
|
|
155
|
+
assert tbl.view().to_columns() == {
|
|
156
|
+
"a": [True, False, None, False],
|
|
157
|
+
"b": [False, True, None, False],
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
def test_table_bool_with_dtype(self):
|
|
161
|
+
data = {
|
|
162
|
+
"a": np.array([True, False, False], dtype="?"),
|
|
163
|
+
"b": np.array([False, True, False], dtype="?"),
|
|
164
|
+
}
|
|
165
|
+
tbl = Table(data)
|
|
166
|
+
assert tbl.size() == 3
|
|
167
|
+
assert tbl.view().to_columns() == {
|
|
168
|
+
"a": [True, False, False],
|
|
169
|
+
"b": [False, True, False],
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
def test_table_bool_str(self):
|
|
173
|
+
data = {"a": np.array(["True", "False"]), "b": np.array(["False", "True"])}
|
|
174
|
+
tbl = Table(data)
|
|
175
|
+
assert tbl.size() == 2
|
|
176
|
+
assert tbl.schema() == {"a": bool, "b": "boolean"}
|
|
177
|
+
assert tbl.view().to_columns() == {"a": [True, False], "b": [False, True]}
|
|
178
|
+
|
|
179
|
+
# strings
|
|
180
|
+
|
|
181
|
+
def test_table_str_object(self):
|
|
182
|
+
data = {
|
|
183
|
+
"a": np.array(["abc", "def"], dtype=object),
|
|
184
|
+
"b": np.array(["hij", "klm"], dtype=object),
|
|
185
|
+
}
|
|
186
|
+
tbl = Table(data)
|
|
187
|
+
assert tbl.size() == 2
|
|
188
|
+
assert tbl.view().to_columns() == {"a": ["abc", "def"], "b": ["hij", "klm"]}
|
|
189
|
+
|
|
190
|
+
def test_table_str_dtype(self):
|
|
191
|
+
dtype = "U3"
|
|
192
|
+
data = {
|
|
193
|
+
"a": np.array(["abc", "def"], dtype=dtype),
|
|
194
|
+
"b": np.array(["hij", "klm"], dtype=dtype),
|
|
195
|
+
}
|
|
196
|
+
tbl = Table(data)
|
|
197
|
+
assert tbl.size() == 2
|
|
198
|
+
assert tbl.view().to_columns() == {"a": ["abc", "def"], "b": ["hij", "klm"]}
|
|
199
|
+
|
|
200
|
+
# date and datetime
|
|
201
|
+
|
|
202
|
+
def test_table_date(self):
|
|
203
|
+
data = {"a": np.array([date(2019, 7, 11)]), "b": np.array([date(2019, 7, 12)])}
|
|
204
|
+
tbl = Table(data)
|
|
205
|
+
assert tbl.size() == 1
|
|
206
|
+
assert tbl.schema() == {"a": date, "b": "date"}
|
|
207
|
+
assert tbl.view().to_columns() == {
|
|
208
|
+
"a": [datetime(2019, 7, 11)],
|
|
209
|
+
"b": [datetime(2019, 7, 12)],
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
def test_table_np_datetime(self):
|
|
213
|
+
data = {
|
|
214
|
+
"a": np.array([datetime(2019, 7, 11, 12, 13)], dtype="datetime64[ns]"),
|
|
215
|
+
"b": np.array([datetime(2019, 7, 11, 12, 14)], dtype="datetime64[ns]"),
|
|
216
|
+
}
|
|
217
|
+
tbl = Table(data)
|
|
218
|
+
assert tbl.size() == 1
|
|
219
|
+
assert tbl.schema() == {"a": datetime, "b": "datetime"}
|
|
220
|
+
assert tbl.view().to_numpy() == {
|
|
221
|
+
"a": np.array([datetime(2019, 7, 11, 12, 13)], dtype=object),
|
|
222
|
+
"b": np.array([datetime(2019, 7, 11, 12, 14)], dtype=object),
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
def test_table_np_datetime_mixed_dtype(self):
|
|
226
|
+
data = {
|
|
227
|
+
"a": np.array([datetime(2019, 7, 11, 12, 13)], dtype="datetime64[ns]"),
|
|
228
|
+
"b": np.array([datetime(2019, 7, 11, 12, 14)], dtype=object),
|
|
229
|
+
}
|
|
230
|
+
tbl = Table(data)
|
|
231
|
+
assert tbl.size() == 1
|
|
232
|
+
assert tbl.schema() == {"a": datetime, "b": "datetime"}
|
|
233
|
+
assert tbl.view().to_numpy() == {
|
|
234
|
+
"a": np.array([datetime(2019, 7, 11, 12, 13)], dtype=object),
|
|
235
|
+
"b": np.array([datetime(2019, 7, 11, 12, 14)], dtype=object),
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
def test_table_np_datetime_default(self, util):
|
|
239
|
+
tbl = Table(
|
|
240
|
+
{"a": np.array([datetime(2019, 7, 12, 11, 0)], dtype="datetime64[ns]")}
|
|
241
|
+
)
|
|
242
|
+
|
|
243
|
+
assert tbl.view().to_columns() == {
|
|
244
|
+
"a": [util.to_timestamp(datetime(2019, 7, 12, 11, 0))]
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
def test_table_np_datetime_string_dtype(self):
|
|
248
|
+
data = ["2019/07/11 15:30:05", "2019/07/11 15:30:05"]
|
|
249
|
+
tbl = Table({"a": np.array(data)})
|
|
250
|
+
|
|
251
|
+
assert tbl.view().to_columns() == {
|
|
252
|
+
"a": [datetime(2019, 7, 11, 15, 30, 5), datetime(2019, 7, 11, 15, 30, 5)]
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
def test_table_np_datetime_string_on_schema(self):
|
|
256
|
+
data = ["2019/07/11 15:30:05", "2019/07/11 15:30:05"]
|
|
257
|
+
tbl = Table({"a": "datetime"})
|
|
258
|
+
|
|
259
|
+
tbl.update({"a": data})
|
|
260
|
+
|
|
261
|
+
assert tbl.view().to_columns() == {
|
|
262
|
+
"a": [datetime(2019, 7, 11, 15, 30, 5), datetime(2019, 7, 11, 15, 30, 5)]
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
def test_table_np_datetime_ns(self, util):
|
|
266
|
+
tbl = Table(
|
|
267
|
+
{"a": np.array([datetime(2019, 7, 12, 11, 0)], dtype="datetime64[ns]")}
|
|
268
|
+
)
|
|
269
|
+
|
|
270
|
+
assert tbl.view().to_columns() == {
|
|
271
|
+
"a": [util.to_timestamp(datetime(2019, 7, 12, 11, 0))]
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
def test_table_np_datetime_us(self, util):
|
|
275
|
+
tbl = Table(
|
|
276
|
+
{"a": np.array([datetime(2019, 7, 12, 11, 0)], dtype="datetime64[us]")}
|
|
277
|
+
)
|
|
278
|
+
|
|
279
|
+
assert tbl.view().to_columns() == {
|
|
280
|
+
"a": [util.to_timestamp(datetime(2019, 7, 12, 11, 0))]
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
def test_table_np_datetime_ms(self, util):
|
|
284
|
+
tbl = Table(
|
|
285
|
+
{"a": np.array([datetime(2019, 7, 12, 11, 0)], dtype="datetime64[ms]")}
|
|
286
|
+
)
|
|
287
|
+
|
|
288
|
+
assert tbl.view().to_columns() == {
|
|
289
|
+
"a": [util.to_timestamp(datetime(2019, 7, 12, 11, 0))]
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
def test_table_np_datetime_s(self, util):
|
|
293
|
+
tbl = Table(
|
|
294
|
+
{"a": np.array([datetime(2019, 7, 12, 11, 0)], dtype="datetime64[s]")}
|
|
295
|
+
)
|
|
296
|
+
|
|
297
|
+
assert tbl.view().to_columns() == {
|
|
298
|
+
"a": [util.to_timestamp(datetime(2019, 7, 12, 11, 0))]
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
def test_table_np_datetime_m(self, util):
|
|
302
|
+
tbl = Table(
|
|
303
|
+
{"a": np.array([datetime(2019, 7, 12, 11, 0)], dtype="datetime64[m]")}
|
|
304
|
+
)
|
|
305
|
+
|
|
306
|
+
assert tbl.view().to_columns() == {
|
|
307
|
+
"a": [util.to_timestamp(datetime(2019, 7, 12, 11, 0))]
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
def test_table_np_datetime_h(self, util):
|
|
311
|
+
tbl = Table(
|
|
312
|
+
{"a": np.array([datetime(2019, 7, 12, 11, 0)], dtype="datetime64[h]")}
|
|
313
|
+
)
|
|
314
|
+
|
|
315
|
+
assert tbl.view().to_columns() == {
|
|
316
|
+
"a": [util.to_timestamp(datetime(2019, 7, 12, 11, 0))]
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
def test_table_np_datetime_D(self, util):
|
|
320
|
+
tbl = Table(
|
|
321
|
+
{"a": np.array([datetime(2019, 7, 12, 11, 0)], dtype="datetime64[D]")}
|
|
322
|
+
)
|
|
323
|
+
|
|
324
|
+
assert tbl.schema() == {"a": "date"}
|
|
325
|
+
|
|
326
|
+
assert tbl.view().to_columns() == {
|
|
327
|
+
"a": [util.to_timestamp(datetime(2019, 7, 12, 0, 0))]
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
def test_table_np_datetime_W(self, util):
|
|
331
|
+
tbl = Table(
|
|
332
|
+
{"a": np.array([datetime(2019, 7, 12, 11, 0)], dtype="datetime64[W]")}
|
|
333
|
+
)
|
|
334
|
+
|
|
335
|
+
assert tbl.schema() == {"a": "date"}
|
|
336
|
+
|
|
337
|
+
assert tbl.view().to_columns() == {
|
|
338
|
+
"a": [util.to_timestamp(datetime(2019, 7, 11, 0, 0))]
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
def test_table_np_datetime_M(self):
|
|
342
|
+
tbl = Table(
|
|
343
|
+
{
|
|
344
|
+
"a": np.array(
|
|
345
|
+
[
|
|
346
|
+
datetime(2019, 5, 12, 11, 0),
|
|
347
|
+
datetime(2019, 6, 12, 11, 0),
|
|
348
|
+
datetime(2019, 7, 12, 11, 0),
|
|
349
|
+
],
|
|
350
|
+
dtype="datetime64[M]",
|
|
351
|
+
)
|
|
352
|
+
}
|
|
353
|
+
)
|
|
354
|
+
|
|
355
|
+
assert tbl.schema() == {"a": "date"}
|
|
356
|
+
|
|
357
|
+
assert tbl.view().to_columns() == {
|
|
358
|
+
"a": [
|
|
359
|
+
datetime(2019, 5, 1, 0, 0),
|
|
360
|
+
datetime(2019, 6, 1, 0, 0),
|
|
361
|
+
datetime(2019, 7, 1, 0, 0),
|
|
362
|
+
]
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
def test_table_np_datetime_Y(self):
|
|
366
|
+
tbl = Table(
|
|
367
|
+
{
|
|
368
|
+
"a": np.array(
|
|
369
|
+
[
|
|
370
|
+
datetime(2017, 5, 12, 11, 0),
|
|
371
|
+
datetime(2018, 6, 12, 11, 0),
|
|
372
|
+
datetime(2019, 7, 12, 11, 0),
|
|
373
|
+
],
|
|
374
|
+
dtype="datetime64[Y]",
|
|
375
|
+
)
|
|
376
|
+
}
|
|
377
|
+
)
|
|
378
|
+
|
|
379
|
+
assert tbl.schema() == {"a": "date"}
|
|
380
|
+
|
|
381
|
+
assert tbl.view().to_columns() == {
|
|
382
|
+
"a": [
|
|
383
|
+
datetime(2017, 1, 1, 0, 0),
|
|
384
|
+
datetime(2018, 1, 1, 0, 0),
|
|
385
|
+
datetime(2019, 1, 1, 0, 0),
|
|
386
|
+
]
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
def test_table_np_datetime_ms_nat(self, util):
|
|
390
|
+
tbl = Table(
|
|
391
|
+
{
|
|
392
|
+
"a": np.array(
|
|
393
|
+
[datetime(2019, 7, 12, 11, 0), np.datetime64("nat")],
|
|
394
|
+
dtype="datetime64[ms]",
|
|
395
|
+
)
|
|
396
|
+
}
|
|
397
|
+
)
|
|
398
|
+
|
|
399
|
+
assert tbl.view().to_columns() == {
|
|
400
|
+
"a": [util.to_timestamp(datetime(2019, 7, 12, 11, 0)), None]
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
def test_table_np_datetime_s_nat(self, util):
|
|
404
|
+
tbl = Table(
|
|
405
|
+
{
|
|
406
|
+
"a": np.array(
|
|
407
|
+
[datetime(2019, 7, 12, 11, 0), np.datetime64("nat")],
|
|
408
|
+
dtype="datetime64[s]",
|
|
409
|
+
)
|
|
410
|
+
}
|
|
411
|
+
)
|
|
412
|
+
|
|
413
|
+
assert tbl.view().to_columns() == {
|
|
414
|
+
"a": [util.to_timestamp(datetime(2019, 7, 12, 11, 0)), None]
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
def test_table_np_timedelta(self):
|
|
418
|
+
tbl = Table(
|
|
419
|
+
{
|
|
420
|
+
"a": np.array([datetime(2019, 7, 12, 11, 0)], dtype="datetime64[ns]")
|
|
421
|
+
- np.array([datetime(2019, 7, 1, 11, 0)], dtype="datetime64[ns]")
|
|
422
|
+
}
|
|
423
|
+
)
|
|
424
|
+
|
|
425
|
+
assert tbl.schema() == {"a": "string"}
|
|
426
|
+
|
|
427
|
+
assert tbl.view().to_columns() == {"a": ["950400000000000 nanoseconds"]}
|
|
428
|
+
|
|
429
|
+
def test_table_np_timedelta_us(self):
|
|
430
|
+
tbl = Table(
|
|
431
|
+
{
|
|
432
|
+
"a": np.array([datetime(2019, 7, 12, 11, 0)], dtype="datetime64[us]")
|
|
433
|
+
- np.array([datetime(2019, 7, 1, 11, 0)], dtype="datetime64[us]")
|
|
434
|
+
}
|
|
435
|
+
)
|
|
436
|
+
|
|
437
|
+
assert tbl.schema() == {"a": "string"}
|
|
438
|
+
|
|
439
|
+
assert tbl.view().to_columns() == {"a": ["950400000000 microseconds"]}
|
|
440
|
+
|
|
441
|
+
def test_table_np_timedelta_ms(self):
|
|
442
|
+
tbl = Table(
|
|
443
|
+
{
|
|
444
|
+
"a": np.array([datetime(2019, 7, 12, 11, 0)], dtype="datetime64[ms]")
|
|
445
|
+
- np.array([datetime(2019, 7, 1, 11, 0)], dtype="datetime64[ms]")
|
|
446
|
+
}
|
|
447
|
+
)
|
|
448
|
+
|
|
449
|
+
assert tbl.schema() == {"a": "string"}
|
|
450
|
+
|
|
451
|
+
assert tbl.view().to_columns() == {"a": ["950400000 milliseconds"]}
|
|
452
|
+
|
|
453
|
+
def test_table_np_timedelta_s(self):
|
|
454
|
+
tbl = Table(
|
|
455
|
+
{
|
|
456
|
+
"a": np.array([datetime(2019, 7, 12, 11, 0)], dtype="datetime64[s]")
|
|
457
|
+
- np.array([datetime(2019, 7, 1, 11, 0)], dtype="datetime64[s]")
|
|
458
|
+
}
|
|
459
|
+
)
|
|
460
|
+
|
|
461
|
+
assert tbl.schema() == {"a": "string"}
|
|
462
|
+
|
|
463
|
+
assert tbl.view().to_columns() == {"a": ["950400 seconds"]}
|
|
464
|
+
|
|
465
|
+
def test_table_np_timedelta_m(self):
|
|
466
|
+
tbl = Table(
|
|
467
|
+
{
|
|
468
|
+
"a": np.array([datetime(2019, 7, 12, 11, 0)], dtype="datetime64[m]")
|
|
469
|
+
- np.array([datetime(2019, 7, 1, 11, 0)], dtype="datetime64[m]")
|
|
470
|
+
}
|
|
471
|
+
)
|
|
472
|
+
|
|
473
|
+
assert tbl.schema() == {"a": "string"}
|
|
474
|
+
|
|
475
|
+
assert tbl.view().to_columns() == {"a": ["15840 minutes"]}
|
|
476
|
+
|
|
477
|
+
def test_table_np_timedelta_h(self):
|
|
478
|
+
tbl = Table(
|
|
479
|
+
{
|
|
480
|
+
"a": np.array([datetime(2019, 7, 12, 11, 0)], dtype="datetime64[h]")
|
|
481
|
+
- np.array([datetime(2019, 7, 1, 11, 0)], dtype="datetime64[h]")
|
|
482
|
+
}
|
|
483
|
+
)
|
|
484
|
+
|
|
485
|
+
assert tbl.schema() == {"a": "string"}
|
|
486
|
+
|
|
487
|
+
assert tbl.view().to_columns() == {"a": ["264 hours"]}
|
|
488
|
+
|
|
489
|
+
def test_table_np_timedelta_d(self):
|
|
490
|
+
tbl = Table(
|
|
491
|
+
{
|
|
492
|
+
"a": np.array([datetime(2019, 7, 12, 11, 0)], dtype="datetime64[D]")
|
|
493
|
+
- np.array([datetime(2019, 7, 1, 11, 0)], dtype="datetime64[D]")
|
|
494
|
+
}
|
|
495
|
+
)
|
|
496
|
+
|
|
497
|
+
assert tbl.schema() == {"a": "string"}
|
|
498
|
+
|
|
499
|
+
assert tbl.view().to_columns() == {"a": ["11 days"]}
|
|
500
|
+
|
|
501
|
+
def test_table_np_timedelta_with_none(self):
|
|
502
|
+
tbl = Table(
|
|
503
|
+
{
|
|
504
|
+
"a": np.array(
|
|
505
|
+
[None, datetime(2019, 7, 12, 11, 0)], dtype="datetime64[ns]"
|
|
506
|
+
)
|
|
507
|
+
- np.array([datetime(2019, 7, 1, 11, 0), None], dtype="datetime64[ns]")
|
|
508
|
+
}
|
|
509
|
+
)
|
|
510
|
+
|
|
511
|
+
assert tbl.schema() == {"a": "string"}
|
|
512
|
+
|
|
513
|
+
assert tbl.view().to_columns() == {"a": [None, None]} # two `NaT` values
|
|
514
|
+
|
|
515
|
+
def test_table_np_mixed(self):
|
|
516
|
+
data = {
|
|
517
|
+
"a": np.arange(5),
|
|
518
|
+
"b": np.full(5, np.nan),
|
|
519
|
+
"c": ["a", "b", "c", "d", "e"],
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
# should not be able to parse mixed dicts of numpy array with list
|
|
523
|
+
with raises(psp.PerspectiveError):
|
|
524
|
+
Table(data)
|
|
525
|
+
|
|
526
|
+
def test_table_np_promote(self):
|
|
527
|
+
data = {
|
|
528
|
+
"a": np.arange(5),
|
|
529
|
+
"b": np.full(5, np.nan),
|
|
530
|
+
"c": np.array([1, 2, 3, 2147483648, 5]),
|
|
531
|
+
}
|
|
532
|
+
tbl = Table({"a": "integer", "b": "float", "c": "integer"})
|
|
533
|
+
tbl.update(data)
|
|
534
|
+
assert tbl.size() == 5
|
|
535
|
+
assert tbl.schema() == {"a": "integer", "b": "float", "c": "integer"}
|
|
536
|
+
|
|
537
|
+
assert tbl.view().to_columns() == {
|
|
538
|
+
"a": [0, 1, 2, 3, 4],
|
|
539
|
+
"b": [None, None, None, None, None],
|
|
540
|
+
"c": [1.0, 2.0, 3.0, 2147483648.0, 5.0],
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
def test_table_np_promote_to_string(self):
|
|
544
|
+
data = {
|
|
545
|
+
"a": np.arange(4),
|
|
546
|
+
"b": np.array([1, 2, "abc", "abc"]),
|
|
547
|
+
}
|
|
548
|
+
tbl = Table(data)
|
|
549
|
+
assert tbl.size() == 4
|
|
550
|
+
assert tbl.schema() == {
|
|
551
|
+
"a": "integer",
|
|
552
|
+
"b": "string",
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
assert tbl.view().to_columns() == {
|
|
556
|
+
"a": [0, 1, 2, 3],
|
|
557
|
+
"b": ["1", "2", "abc", "abc"],
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
def test_table_np_implicit_index(self):
|
|
561
|
+
data = {
|
|
562
|
+
"a": np.array(["a", "b", "c", "d", "e"]),
|
|
563
|
+
"b": np.array([1, 2, 3, 4, 5]),
|
|
564
|
+
}
|
|
565
|
+
tbl = Table(data)
|
|
566
|
+
assert tbl.size() == 5
|
|
567
|
+
assert tbl.schema() == {"a": "string", "b": "integer"}
|
|
568
|
+
tbl.update(
|
|
569
|
+
{
|
|
570
|
+
"__INDEX__": np.array([1, 2, 3, 4]),
|
|
571
|
+
"a": np.array(["bb", "cc", "dd", "ee"]),
|
|
572
|
+
}
|
|
573
|
+
)
|
|
574
|
+
|
|
575
|
+
assert tbl.view().to_columns() == {
|
|
576
|
+
"a": ["a", "bb", "cc", "dd", "ee"],
|
|
577
|
+
"b": [1, 2, 3, 4, 5],
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
# from schema
|
|
581
|
+
|
|
582
|
+
def test_table_numpy_from_schema_int(self):
|
|
583
|
+
df = {"a": np.array([1, None, 2, None, 3, 4])}
|
|
584
|
+
table = Table({"a": "integer"})
|
|
585
|
+
table.update(df)
|
|
586
|
+
assert table.view().to_columns()["a"] == [1, None, 2, None, 3, 4]
|
|
587
|
+
|
|
588
|
+
def test_table_numpy_from_schema_bool(self):
|
|
589
|
+
data = [True, False, True, False]
|
|
590
|
+
df = {"a": data}
|
|
591
|
+
table = Table({"a": "boolean"})
|
|
592
|
+
table.update(df)
|
|
593
|
+
assert table.view().to_columns()["a"] == data
|
|
594
|
+
|
|
595
|
+
def test_table_numpy_from_schema_float(self):
|
|
596
|
+
data = [1.5, None, 2.5, None, 3.5, 4.5]
|
|
597
|
+
df = {"a": np.array(data)}
|
|
598
|
+
table = Table({"a": "float"})
|
|
599
|
+
table.update(df)
|
|
600
|
+
assert table.view().to_columns()["a"] == data
|
|
601
|
+
|
|
602
|
+
def test_table_numpy_from_schema_float_all_nan(self):
|
|
603
|
+
data = [np.nan, np.nan, np.nan, np.nan]
|
|
604
|
+
df = {"a": np.array(data)}
|
|
605
|
+
table = Table({"a": "float"})
|
|
606
|
+
table.update(df)
|
|
607
|
+
assert table.view().to_columns()["a"] == [None, None, None, None]
|
|
608
|
+
|
|
609
|
+
def test_table_numpy_from_schema_float_to_int(self):
|
|
610
|
+
data = [None, 1.5, None, 2.5, None, 3.5, 4.5]
|
|
611
|
+
df = {"a": np.array(data)}
|
|
612
|
+
table = Table({"a": "integer"})
|
|
613
|
+
table.update(df)
|
|
614
|
+
# truncates decimal
|
|
615
|
+
assert table.view().to_columns()["a"] == [None, 1, None, 2, None, 3, 4]
|
|
616
|
+
|
|
617
|
+
def test_table_numpy_from_schema_float_to_int_with_nan(self):
|
|
618
|
+
df = {"a": np.array([np.nan, 1.5, np.nan, 2.5, np.nan, 3.5, 4.5])}
|
|
619
|
+
table = Table({"a": "integer"})
|
|
620
|
+
table.update(df)
|
|
621
|
+
# truncates decimal
|
|
622
|
+
assert table.view().to_columns()["a"] == [None, 1, None, 2, None, 3, 4]
|
|
623
|
+
|
|
624
|
+
def test_table_numpy_from_schema_float_to_int_with_nan_partial(self):
|
|
625
|
+
df = {"a": np.array([np.nan, 1.5, np.nan, 2.5, np.nan, 3.5, 4.5])}
|
|
626
|
+
table = Table({"a": "integer", "b": "integer"})
|
|
627
|
+
table.update(df)
|
|
628
|
+
assert table.size() == 7
|
|
629
|
+
# truncates decimal
|
|
630
|
+
assert table.view().to_columns() == {
|
|
631
|
+
"a": [None, 1, None, 2, None, 3, 4],
|
|
632
|
+
"b": [None, None, None, None, None, None, None],
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
def test_table_numpy_from_schema_float_to_int_with_nan_partial_indexed(self):
|
|
636
|
+
"""Assert that the null masking works even when primary keys
|
|
637
|
+
are being reordered."""
|
|
638
|
+
df = {
|
|
639
|
+
"a": np.array([np.nan, 1.5, np.nan, 2.5, np.nan, 3.5, 4.5]),
|
|
640
|
+
"b": np.array([1.5, 2.5, 3.5, 4.5, 5.5, 6.5, 7.5]),
|
|
641
|
+
}
|
|
642
|
+
table = Table({"a": "integer", "b": "integer"}, index="b")
|
|
643
|
+
table.update(df)
|
|
644
|
+
|
|
645
|
+
# truncates decimal
|
|
646
|
+
assert table.view().to_columns() == {
|
|
647
|
+
"a": [None, 1, None, 2, None, 3, 4],
|
|
648
|
+
"b": [1, 2, 3, 4, 5, 6, 7],
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
table.update(pd.DataFrame({"a": [10, 9, 8], "b": [2, 3, 5]}))
|
|
652
|
+
|
|
653
|
+
assert table.view().to_columns() == {
|
|
654
|
+
"a": [None, 10, 9, 2, 8, 3, 4],
|
|
655
|
+
"b": [1, 2, 3, 4, 5, 6, 7],
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
table.update(
|
|
659
|
+
{
|
|
660
|
+
"a": np.array([100, np.nan], dtype=np.float64),
|
|
661
|
+
"b": np.array([-1, 6], dtype=np.float64),
|
|
662
|
+
}
|
|
663
|
+
)
|
|
664
|
+
|
|
665
|
+
assert table.view().to_columns() == {
|
|
666
|
+
"a": [100, None, 10, 9, 2, 8, None, 4],
|
|
667
|
+
"b": [-1, 1, 2, 3, 4, 5, 6, 7],
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
table.update(
|
|
671
|
+
{
|
|
672
|
+
"a": np.array([100, 1000, np.nan], dtype=np.float64),
|
|
673
|
+
"b": np.array([100, 6, 97], dtype=np.float64),
|
|
674
|
+
}
|
|
675
|
+
)
|
|
676
|
+
|
|
677
|
+
assert table.view().to_columns() == {
|
|
678
|
+
"a": [100, None, 10, 9, 2, 8, 1000, 4, None, 100],
|
|
679
|
+
"b": [-1, 1, 2, 3, 4, 5, 6, 7, 97, 100],
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
def test_table_numpy_from_schema_int_to_float(self):
|
|
683
|
+
data = [None, 1, None, 2, None, 3, 4]
|
|
684
|
+
df = {"a": np.array(data)}
|
|
685
|
+
table = Table({"a": "float"})
|
|
686
|
+
table.update(df)
|
|
687
|
+
assert table.view().to_columns()["a"] == [None, 1.0, None, 2.0, None, 3.0, 4.0]
|
|
688
|
+
|
|
689
|
+
def test_table_numpy_from_schema_date(self):
|
|
690
|
+
data = [date(2019, 8, 15), None, date(2019, 8, 16)]
|
|
691
|
+
df = {"a": np.array(data)}
|
|
692
|
+
table = Table({"a": "date"})
|
|
693
|
+
table.update(df)
|
|
694
|
+
assert table.view().to_columns()["a"] == [
|
|
695
|
+
datetime(2019, 8, 15),
|
|
696
|
+
None,
|
|
697
|
+
datetime(2019, 8, 16),
|
|
698
|
+
]
|
|
699
|
+
|
|
700
|
+
def test_table_numpy_from_schema_datetime(self):
|
|
701
|
+
data = [
|
|
702
|
+
datetime(2019, 7, 11, 12, 30, 5),
|
|
703
|
+
None,
|
|
704
|
+
datetime(2019, 7, 11, 13, 30, 5),
|
|
705
|
+
None,
|
|
706
|
+
]
|
|
707
|
+
df = {"a": np.array(data)}
|
|
708
|
+
table = Table({"a": "datetime"})
|
|
709
|
+
table.update(df)
|
|
710
|
+
assert table.view().to_columns()["a"] == data
|
|
711
|
+
|
|
712
|
+
def test_table_numpy_from_schema_datetime_timestamp_s(self, util):
|
|
713
|
+
data = [
|
|
714
|
+
util.to_timestamp(datetime(2019, 7, 11, 12, 30, 5)),
|
|
715
|
+
np.nan,
|
|
716
|
+
util.to_timestamp(datetime(2019, 7, 11, 13, 30, 5)),
|
|
717
|
+
np.nan,
|
|
718
|
+
]
|
|
719
|
+
df = {"a": np.array(data)}
|
|
720
|
+
table = Table({"a": "datetime"})
|
|
721
|
+
table.update(df)
|
|
722
|
+
assert table.view().to_columns()["a"] == [
|
|
723
|
+
datetime(2019, 7, 11, 12, 30, 5),
|
|
724
|
+
None,
|
|
725
|
+
datetime(2019, 7, 11, 13, 30, 5),
|
|
726
|
+
None,
|
|
727
|
+
]
|
|
728
|
+
|
|
729
|
+
def test_table_numpy_from_schema_datetime_timestamp_ms(self, util):
|
|
730
|
+
data = [
|
|
731
|
+
util.to_timestamp(datetime(2019, 7, 11, 12, 30, 5)) * 1000,
|
|
732
|
+
np.nan,
|
|
733
|
+
util.to_timestamp(datetime(2019, 7, 11, 13, 30, 5)) * 1000,
|
|
734
|
+
np.nan,
|
|
735
|
+
]
|
|
736
|
+
|
|
737
|
+
df = {"a": np.array(data)}
|
|
738
|
+
table = Table({"a": "datetime"})
|
|
739
|
+
table.update(df)
|
|
740
|
+
assert table.view().to_columns()["a"] == [
|
|
741
|
+
datetime(2019, 7, 11, 12, 30, 5),
|
|
742
|
+
None,
|
|
743
|
+
datetime(2019, 7, 11, 13, 30, 5),
|
|
744
|
+
None,
|
|
745
|
+
]
|
|
746
|
+
|
|
747
|
+
def test_table_numpy_from_schema_str(self):
|
|
748
|
+
data = ["a", None, "b", None, "c"]
|
|
749
|
+
df = {"a": np.array(data)}
|
|
750
|
+
table = Table({"a": "string"})
|
|
751
|
+
table.update(df)
|
|
752
|
+
assert table.view().to_columns()["a"] == data
|
|
753
|
+
|
|
754
|
+
# partial update
|
|
755
|
+
|
|
756
|
+
def test_table_numpy_partial_update(self):
|
|
757
|
+
data = ["a", None, "b", None, "c"]
|
|
758
|
+
df = {"a": np.array([1, 2, 3, 4, 5]), "b": np.array(data), "c": np.array(data)}
|
|
759
|
+
table = Table(df, index="a")
|
|
760
|
+
table.update({"a": np.array([2, 4, 5]), "b": np.array(["x", "y", "z"])})
|
|
761
|
+
assert table.view().to_columns() == {
|
|
762
|
+
"a": [1, 2, 3, 4, 5],
|
|
763
|
+
"b": ["a", "x", "b", "y", "z"],
|
|
764
|
+
"c": ["a", None, "b", None, "c"],
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
def test_table_numpy_partial_update_implicit(self):
|
|
768
|
+
data = ["a", None, "b", None, "c"]
|
|
769
|
+
df = {"a": np.array([1, 2, 3, 4, 5]), "b": np.array(data), "c": np.array(data)}
|
|
770
|
+
table = Table(df)
|
|
771
|
+
table.update({"__INDEX__": np.array([1, 3, 4]), "b": np.array(["x", "y", "z"])})
|
|
772
|
+
assert table.view().to_columns() == {
|
|
773
|
+
"a": [1, 2, 3, 4, 5],
|
|
774
|
+
"b": ["a", "x", "b", "y", "z"],
|
|
775
|
+
"c": ["a", None, "b", None, "c"],
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
# structured array
|
|
779
|
+
|
|
780
|
+
def test_table_structured_array(self):
|
|
781
|
+
d = np.array([(1.0, 2), (3.0, 4)], dtype=[("x", "<f8"), ("y", "<i8")])
|
|
782
|
+
table = Table(d)
|
|
783
|
+
assert table.schema() == {"x": "float", "y": "integer"}
|
|
784
|
+
assert table.view().to_columns() == {"x": [1.0, 3.0], "y": [2, 4]}
|
|
785
|
+
|
|
786
|
+
# recarray
|
|
787
|
+
|
|
788
|
+
def test_table_recarray(self):
|
|
789
|
+
d = np.array([(1.0, 2), (3.0, 4)], dtype=[("x", "<f8"), ("y", "<i8")]).view(
|
|
790
|
+
np.recarray
|
|
791
|
+
)
|
|
792
|
+
table = Table(d)
|
|
793
|
+
assert table.schema() == {"x": "float", "y": "integer"}
|
|
794
|
+
assert table.view().to_columns() == {"x": [1.0, 3.0], "y": [2, 4]}
|
|
795
|
+
|
|
796
|
+
def test_table_recarray_datetime_ns(self):
|
|
797
|
+
d = np.array(
|
|
798
|
+
[
|
|
799
|
+
(datetime(2019, 7, 11, 8, 30, 29), 2),
|
|
800
|
+
(datetime(2019, 7, 11, 8, 30, 29), 4),
|
|
801
|
+
],
|
|
802
|
+
dtype=[("x", "datetime64[ns]"), ("y", "<i8")],
|
|
803
|
+
).view(np.recarray)
|
|
804
|
+
table = Table(d)
|
|
805
|
+
assert table.schema() == {"x": "datetime", "y": "integer"}
|
|
806
|
+
assert table.view().to_columns() == {
|
|
807
|
+
"x": [datetime(2019, 7, 11, 8, 30, 29), datetime(2019, 7, 11, 8, 30, 29)],
|
|
808
|
+
"y": [2, 4],
|
|
809
|
+
}
|
|
810
|
+
|
|
811
|
+
def test_table_recarray_datetime_us(self):
|
|
812
|
+
d = np.array(
|
|
813
|
+
[
|
|
814
|
+
(datetime(2019, 7, 11, 8, 30, 29), 2),
|
|
815
|
+
(datetime(2019, 7, 11, 8, 30, 29), 4),
|
|
816
|
+
],
|
|
817
|
+
dtype=[("x", "datetime64[us]"), ("y", "<i8")],
|
|
818
|
+
).view(np.recarray)
|
|
819
|
+
table = Table(d)
|
|
820
|
+
assert table.schema() == {"x": "datetime", "y": "integer"}
|
|
821
|
+
assert table.view().to_columns() == {
|
|
822
|
+
"x": [datetime(2019, 7, 11, 8, 30, 29), datetime(2019, 7, 11, 8, 30, 29)],
|
|
823
|
+
"y": [2, 4],
|
|
824
|
+
}
|
|
825
|
+
|
|
826
|
+
def test_table_recarray_datetime_ms(self):
|
|
827
|
+
d = np.array(
|
|
828
|
+
[
|
|
829
|
+
(datetime(2019, 7, 11, 8, 30, 29), 2),
|
|
830
|
+
(datetime(2019, 7, 11, 8, 30, 29), 4),
|
|
831
|
+
],
|
|
832
|
+
dtype=[("x", "datetime64[ms]"), ("y", "<i8")],
|
|
833
|
+
).view(np.recarray)
|
|
834
|
+
table = Table(d)
|
|
835
|
+
assert table.schema() == {"x": "datetime", "y": "integer"}
|
|
836
|
+
assert table.view().to_columns() == {
|
|
837
|
+
"x": [datetime(2019, 7, 11, 8, 30, 29), datetime(2019, 7, 11, 8, 30, 29)],
|
|
838
|
+
"y": [2, 4],
|
|
839
|
+
}
|
|
840
|
+
|
|
841
|
+
def test_table_recarray_datetime_s(self):
|
|
842
|
+
d = np.array(
|
|
843
|
+
[
|
|
844
|
+
(datetime(2019, 7, 11, 8, 30, 29), 2),
|
|
845
|
+
(datetime(2019, 7, 11, 8, 30, 29), 4),
|
|
846
|
+
],
|
|
847
|
+
dtype=[("x", "datetime64[s]"), ("y", "<i8")],
|
|
848
|
+
).view(np.recarray)
|
|
849
|
+
table = Table(d)
|
|
850
|
+
assert table.schema() == {"x": "datetime", "y": "integer"}
|
|
851
|
+
assert table.view().to_columns() == {
|
|
852
|
+
"x": [datetime(2019, 7, 11, 8, 30, 29), datetime(2019, 7, 11, 8, 30, 29)],
|
|
853
|
+
"y": [2, 4],
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
def test_table_recarray_datetime_m(self):
|
|
857
|
+
d = np.array(
|
|
858
|
+
[
|
|
859
|
+
(datetime(2019, 7, 11, 8, 30, 29), 2),
|
|
860
|
+
(datetime(2019, 7, 11, 8, 31, 29), 4),
|
|
861
|
+
],
|
|
862
|
+
dtype=[("x", "datetime64[m]"), ("y", "<i8")],
|
|
863
|
+
).view(np.recarray)
|
|
864
|
+
table = Table(d)
|
|
865
|
+
assert table.schema() == {"x": "datetime", "y": "integer"}
|
|
866
|
+
assert table.view().to_columns() == {
|
|
867
|
+
"x": [datetime(2019, 7, 11, 8, 30, 0), datetime(2019, 7, 11, 8, 31, 0)],
|
|
868
|
+
"y": [2, 4],
|
|
869
|
+
}
|
|
870
|
+
|
|
871
|
+
def test_table_recarray_datetime_h(self):
|
|
872
|
+
d = np.array(
|
|
873
|
+
[
|
|
874
|
+
(datetime(2019, 7, 11, 8, 30, 29), 2),
|
|
875
|
+
(datetime(2019, 7, 11, 9, 30, 29), 4),
|
|
876
|
+
],
|
|
877
|
+
dtype=[("x", "datetime64[h]"), ("y", "<i8")],
|
|
878
|
+
).view(np.recarray)
|
|
879
|
+
table = Table(d)
|
|
880
|
+
assert table.schema() == {"x": "datetime", "y": "integer"}
|
|
881
|
+
assert table.view().to_columns() == {
|
|
882
|
+
"x": [datetime(2019, 7, 11, 8, 0, 0), datetime(2019, 7, 11, 9, 0, 0)],
|
|
883
|
+
"y": [2, 4],
|
|
884
|
+
}
|
|
885
|
+
|
|
886
|
+
def test_table_recarray_datetime_D(self):
|
|
887
|
+
d = np.array(
|
|
888
|
+
[
|
|
889
|
+
(datetime(2019, 7, 11, 8, 30, 29), 2),
|
|
890
|
+
(datetime(2019, 7, 12, 8, 30, 29), 4),
|
|
891
|
+
],
|
|
892
|
+
dtype=[("x", "datetime64[D]"), ("y", "<i8")],
|
|
893
|
+
).view(np.recarray)
|
|
894
|
+
table = Table(d)
|
|
895
|
+
assert table.schema() == {"x": "date", "y": "integer"}
|
|
896
|
+
assert table.view().to_columns() == {
|
|
897
|
+
"x": [datetime(2019, 7, 11, 0, 0, 0), datetime(2019, 7, 12, 0, 0, 0)],
|
|
898
|
+
"y": [2, 4],
|
|
899
|
+
}
|
|
900
|
+
|
|
901
|
+
def test_table_recarray_datetime_W(self):
|
|
902
|
+
d = np.array(
|
|
903
|
+
[(datetime(2019, 6, 30, 0, 0, 0), 2), (datetime(2019, 7, 7, 0, 0, 0), 4)],
|
|
904
|
+
dtype=[("x", "datetime64[W]"), ("y", "<i8")],
|
|
905
|
+
).view(np.recarray)
|
|
906
|
+
table = Table(d)
|
|
907
|
+
assert table.schema() == {"x": "date", "y": "integer"}
|
|
908
|
+
assert table.view().to_columns() == {
|
|
909
|
+
# one week apart
|
|
910
|
+
"x": [datetime(2019, 6, 27, 0, 0, 0), datetime(2019, 7, 4, 0, 0, 0)],
|
|
911
|
+
"y": [2, 4],
|
|
912
|
+
}
|
|
913
|
+
|
|
914
|
+
def test_table_recarray_datetime_M(self):
|
|
915
|
+
d = np.array(
|
|
916
|
+
[
|
|
917
|
+
(datetime(2019, 6, 11, 8, 30, 29), 2),
|
|
918
|
+
(datetime(2019, 7, 11, 8, 30, 29), 4),
|
|
919
|
+
],
|
|
920
|
+
dtype=[("x", "datetime64[M]"), ("y", "<i8")],
|
|
921
|
+
).view(np.recarray)
|
|
922
|
+
table = Table(d)
|
|
923
|
+
assert table.schema() == {"x": "date", "y": "integer"}
|
|
924
|
+
assert table.view().to_columns() == {
|
|
925
|
+
"x": [datetime(2019, 6, 1, 0, 0, 0), datetime(2019, 7, 1, 0, 0, 0)],
|
|
926
|
+
"y": [2, 4],
|
|
927
|
+
}
|
|
928
|
+
|
|
929
|
+
def test_table_recarray_datetime_Y(self):
|
|
930
|
+
d = np.array(
|
|
931
|
+
[
|
|
932
|
+
(datetime(2018, 7, 11, 8, 30, 29), 2),
|
|
933
|
+
(datetime(2019, 7, 11, 8, 30, 29), 4),
|
|
934
|
+
],
|
|
935
|
+
dtype=[("x", "datetime64[Y]"), ("y", "<i8")],
|
|
936
|
+
).view(np.recarray)
|
|
937
|
+
table = Table(d)
|
|
938
|
+
assert table.schema() == {"x": "date", "y": "integer"}
|
|
939
|
+
assert table.view().to_columns() == {
|
|
940
|
+
"x": [datetime(2018, 1, 1, 0, 0, 0), datetime(2019, 1, 1, 0, 0, 0)],
|
|
941
|
+
"y": [2, 4],
|
|
942
|
+
}
|
|
943
|
+
|
|
944
|
+
def test_table_recarray_str(self):
|
|
945
|
+
table = Table(
|
|
946
|
+
np.array(
|
|
947
|
+
[("string1", "string2"), ("string3", "string4")],
|
|
948
|
+
dtype=[("x", "O"), ("y", "O")],
|
|
949
|
+
).view(np.recarray)
|
|
950
|
+
)
|
|
951
|
+
assert table.schema() == {"x": "string", "y": "string"}
|
|
952
|
+
assert table.view().to_columns() == {
|
|
953
|
+
"x": ["string1", "string3"],
|
|
954
|
+
"y": ["string2", "string4"],
|
|
955
|
+
}
|
|
956
|
+
|
|
957
|
+
def test_table_recarray_str_dtype(self):
|
|
958
|
+
dtype = "U7"
|
|
959
|
+
table = Table(
|
|
960
|
+
np.array(
|
|
961
|
+
[("string1", "string2"), ("string3", "string4")],
|
|
962
|
+
dtype=[("x", dtype), ("y", dtype)],
|
|
963
|
+
).view(np.recarray)
|
|
964
|
+
)
|
|
965
|
+
assert table.schema() == {"x": "string", "y": "string"}
|
|
966
|
+
assert table.view().to_columns() == {
|
|
967
|
+
"x": ["string1", "string3"],
|
|
968
|
+
"y": ["string2", "string4"],
|
|
969
|
+
}
|
|
970
|
+
|
|
971
|
+
def test_table_float32_to_float64(self):
|
|
972
|
+
data = {
|
|
973
|
+
"a": np.array([1.1, 2.2]).astype(np.float32),
|
|
974
|
+
"b": np.array([3.3, 4.4]).astype(np.float32),
|
|
975
|
+
}
|
|
976
|
+
table = Table(data)
|
|
977
|
+
assert table.size() == 2
|
|
978
|
+
schema = table.schema()
|
|
979
|
+
assert schema == {"a": "float", "b": "float"}
|
|
980
|
+
assert table.view().to_columns() == {
|
|
981
|
+
"a": [1.100000023841858, 2.200000047683716],
|
|
982
|
+
"b": [3.299999952316284, 4.400000095367432],
|
|
983
|
+
}
|
|
984
|
+
|
|
985
|
+
def test_table_float64_to_float32(self):
|
|
986
|
+
data = {
|
|
987
|
+
"a": np.array([1.1, 2.2]).astype(np.float64),
|
|
988
|
+
"b": np.array([3.3, 4.4]).astype(np.float64),
|
|
989
|
+
}
|
|
990
|
+
table = Table(data)
|
|
991
|
+
assert table.size() == 2
|
|
992
|
+
schema = table.schema()
|
|
993
|
+
assert schema == {"a": "float", "b": "float"}
|
|
994
|
+
view = table.view()
|
|
995
|
+
assert view.to_columns() == {"a": [1.1, 2.2], "b": [3.3, 4.4]}
|
|
996
|
+
view.schema({"a": np.float32, "b": np.float32})
|
|
997
|
+
assert view.to_columns() == {"a": [1.1, 2.2], "b": [3.3, 4.4]}
|
|
998
|
+
data["a"] = data["a"].astype(np.float32)
|
|
999
|
+
data["b"] = data["b"].astype(np.float32)
|
|
1000
|
+
table = Table(data)
|
|
1001
|
+
assert table.size() == 2
|
|
1002
|
+
schema = table.schema()
|
|
1003
|
+
assert schema == {"a": "float", "b": "float"}
|
|
1004
|
+
view = table.view()
|
|
1005
|
+
assert view.to_columns() == {
|
|
1006
|
+
"a": [1.100000023841858, 2.200000047683716],
|
|
1007
|
+
"b": [3.299999952316284, 4.400000095367432],
|
|
1008
|
+
}
|
|
1009
|
+
|
|
1010
|
+
def test_table_float32_to_float64_with_nulls(self):
|
|
1011
|
+
data = {
|
|
1012
|
+
"a": np.array([1.1, np.nan, 2.2]).astype(np.float32),
|
|
1013
|
+
"b": np.array([3.3, 4.4, np.nan]).astype(np.float32),
|
|
1014
|
+
}
|
|
1015
|
+
table = Table(data)
|
|
1016
|
+
assert table.size() == 3
|
|
1017
|
+
schema = table.schema()
|
|
1018
|
+
assert schema == {"a": "float", "b": "float"}
|
|
1019
|
+
assert table.view().to_columns() == {
|
|
1020
|
+
"a": [1.100000023841858, None, 2.200000047683716],
|
|
1021
|
+
"b": [3.299999952316284, 4.400000095367432, None],
|
|
1022
|
+
}
|