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.
Files changed (79) hide show
  1. perspective/__init__.py +396 -0
  2. perspective/extension/finos-perspective-nbextension.json +5 -0
  3. perspective/handlers/__init__.py +11 -0
  4. perspective/handlers/aiohttp.py +61 -0
  5. perspective/handlers/starlette.py +55 -0
  6. perspective/handlers/tornado.py +184 -0
  7. perspective/perspective.pyd +0 -0
  8. perspective/templates/exported_widget.html.template +35 -0
  9. perspective/tests/__init__.py +11 -0
  10. perspective/tests/async/test_async_client.py +83 -0
  11. perspective/tests/async/test_websocket_client.py +124 -0
  12. perspective/tests/conftest.py +272 -0
  13. perspective/tests/core/__init__.py +11 -0
  14. perspective/tests/core/test_async.py +351 -0
  15. perspective/tests/multi_threaded/__init__.py +11 -0
  16. perspective/tests/multi_threaded/test_multi_threaded.py +201 -0
  17. perspective/tests/server/__init__.py +11 -0
  18. perspective/tests/server/test_server.py +1016 -0
  19. perspective/tests/server/test_session.py +110 -0
  20. perspective/tests/table/__init__.py +11 -0
  21. perspective/tests/table/arrow/date32.arrow +0 -0
  22. perspective/tests/table/arrow/date64.arrow +0 -0
  23. perspective/tests/table/arrow/dict.arrow +0 -0
  24. perspective/tests/table/arrow/dict_update.arrow +0 -0
  25. perspective/tests/table/arrow/int_float_str.arrow +0 -0
  26. perspective/tests/table/arrow/int_float_str_file.arrow +0 -0
  27. perspective/tests/table/arrow/int_float_str_update.arrow +0 -0
  28. perspective/tests/table/object_sequence.py +402 -0
  29. perspective/tests/table/test_column_paths.py +89 -0
  30. perspective/tests/table/test_delete.py +124 -0
  31. perspective/tests/table/test_exception.py +65 -0
  32. perspective/tests/table/test_leaks.py +54 -0
  33. perspective/tests/table/test_ports.py +178 -0
  34. perspective/tests/table/test_remove.py +102 -0
  35. perspective/tests/table/test_table.py +641 -0
  36. perspective/tests/table/test_table_arrow.py +503 -0
  37. perspective/tests/table/test_table_datetime.py +2409 -0
  38. perspective/tests/table/test_table_infer.py +201 -0
  39. perspective/tests/table/test_table_limit.py +45 -0
  40. perspective/tests/table/test_table_numpy.py +1022 -0
  41. perspective/tests/table/test_table_pandas.py +1018 -0
  42. perspective/tests/table/test_table_polars.py +251 -0
  43. perspective/tests/table/test_table_view_table.py +130 -0
  44. perspective/tests/table/test_to_arrow.py +417 -0
  45. perspective/tests/table/test_to_arrow_lz4.py +32 -0
  46. perspective/tests/table/test_to_format.py +1024 -0
  47. perspective/tests/table/test_to_polars.py +26 -0
  48. perspective/tests/table/test_update.py +545 -0
  49. perspective/tests/table/test_update_arrow.py +980 -0
  50. perspective/tests/table/test_update_pandas.py +211 -0
  51. perspective/tests/table/test_view.py +2261 -0
  52. perspective/tests/table/test_view_expression.py +1940 -0
  53. perspective/tests/test_dependencies.py +53 -0
  54. perspective/tests/viewer/__init__.py +11 -0
  55. perspective/tests/viewer/test_viewer.py +246 -0
  56. perspective/tests/widget/__init__.py +11 -0
  57. perspective/tests/widget/test_widget.py +278 -0
  58. perspective/tests/widget/test_widget_pandas.py +453 -0
  59. perspective/virtual_servers/__init__.py +134 -0
  60. perspective/virtual_servers/clickhouse.py +245 -0
  61. perspective/virtual_servers/duckdb.py +236 -0
  62. perspective/widget/__init__.py +349 -0
  63. perspective/widget/viewer/__init__.py +15 -0
  64. perspective/widget/viewer/validate.py +22 -0
  65. perspective/widget/viewer/viewer.py +343 -0
  66. perspective/widget/viewer/viewer_traitlets.py +101 -0
  67. perspective_python-4.2.0.data/data/share/jupyter/labextensions/@perspective-dev/jupyterlab/install.json +5 -0
  68. perspective_python-4.2.0.data/data/share/jupyter/labextensions/@perspective-dev/jupyterlab/package.json +71 -0
  69. perspective_python-4.2.0.data/data/share/jupyter/labextensions/@perspective-dev/jupyterlab/static/253.5f5c9e80605aa4106a28.js +2 -0
  70. perspective_python-4.2.0.data/data/share/jupyter/labextensions/@perspective-dev/jupyterlab/static/253.5f5c9e80605aa4106a28.js.LICENSE.txt +25 -0
  71. perspective_python-4.2.0.data/data/share/jupyter/labextensions/@perspective-dev/jupyterlab/static/523.c030af5d3c4f67ff83f6.js +1 -0
  72. perspective_python-4.2.0.data/data/share/jupyter/labextensions/@perspective-dev/jupyterlab/static/remoteEntry.95a8ea1b44d96032833f.js +1 -0
  73. perspective_python-4.2.0.data/data/share/jupyter/labextensions/@perspective-dev/jupyterlab/static/style.js +4 -0
  74. perspective_python-4.2.0.data/data/share/jupyter/labextensions/@perspective-dev/jupyterlab/static/third-party-licenses.json +16 -0
  75. perspective_python-4.2.0.dist-info/METADATA +27 -0
  76. perspective_python-4.2.0.dist-info/RECORD +79 -0
  77. perspective_python-4.2.0.dist-info/WHEEL +4 -0
  78. perspective_python-4.2.0.dist-info/licenses/LICENSE.md +193 -0
  79. perspective_python-4.2.0.dist-info/licenses/LICENSE_THIRDPARTY_cargo.yml +17395 -0
@@ -0,0 +1,1024 @@
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 os
14
+ from datetime import date, datetime
15
+ from io import StringIO
16
+
17
+ import numpy as np
18
+ import pandas as pd
19
+ import pytz
20
+ from pytest import mark
21
+ import perspective as psp
22
+
23
+ client = psp.Server().new_local_client()
24
+ Table = client.table
25
+
26
+ IS_WIN = os.name == "nt"
27
+
28
+
29
+ class TestToFormat(object):
30
+ # to_records
31
+
32
+ def test_to_records_int(self):
33
+ data = [{"a": 1, "b": 2}, {"a": 3, "b": 4}]
34
+ tbl = Table(data)
35
+ view = tbl.view()
36
+ assert view.to_records() == data
37
+
38
+ def test_to_records_float(self):
39
+ data = [{"a": 1.5, "b": 2.5}, {"a": 3.5, "b": 4.5}]
40
+ tbl = Table(data)
41
+ view = tbl.view()
42
+ assert view.to_records() == data
43
+
44
+ def test_to_records_string(self):
45
+ data = [{"a": "string1", "b": "string2"}, {"a": "string3", "b": "string4"}]
46
+ tbl = Table(data)
47
+ view = tbl.view()
48
+ assert view.to_records() == data
49
+
50
+ def test_to_records_date(self, util):
51
+ today = date.today()
52
+ dt = datetime(today.year, today.month, today.day)
53
+ data = [{"a": today, "b": "string2"}, {"a": today, "b": "string4"}]
54
+ tbl = Table(data)
55
+ view = tbl.view()
56
+ assert view.to_records() == [
57
+ {"a": util.to_timestamp(dt), "b": "string2"},
58
+ {"a": util.to_timestamp(dt), "b": "string4"},
59
+ ]
60
+
61
+ def test_to_records_date_no_dst(self, util):
62
+ # make sure that DST does not affect the way we read dates - if tm_dst in `t_date::get_tm()` isn't set to -1, it could reverse 1hr by assuming DST is not in effect.
63
+ today = date.today()
64
+ dt = datetime(today.year, today.month, today.day)
65
+ data = [{"a": today, "b": "string2"}, {"a": today, "b": "string4"}]
66
+ tbl = Table(data)
67
+ view = tbl.view()
68
+ assert view.to_records() == [
69
+ {"a": util.to_timestamp(dt), "b": "string2"},
70
+ {"a": util.to_timestamp(dt), "b": "string4"},
71
+ ]
72
+
73
+ def test_to_records_date_str(self, util):
74
+ data = [
75
+ {"a": "03/11/2019", "b": "string2"},
76
+ {"a": "03/12/2019", "b": "string4"},
77
+ ]
78
+ tbl = Table(data)
79
+ view = tbl.view()
80
+ assert view.to_records() == [
81
+ {"a": util.to_timestamp(datetime(2019, 3, 11)), "b": "string2"},
82
+ {"a": util.to_timestamp(datetime(2019, 3, 12)), "b": "string4"},
83
+ ]
84
+
85
+ def test_to_records_date_str_month_first(self, util):
86
+ data = [{"a": "1/2/2019", "b": "string2"}, {"a": "3/4/2019", "b": "string4"}]
87
+ tbl = Table(data)
88
+ view = tbl.view()
89
+ assert view.schema() == {"a": "date", "b": "string"}
90
+ assert view.to_records() == [
91
+ {"a": util.to_timestamp(datetime(2019, 1, 2)), "b": "string2"},
92
+ {"a": util.to_timestamp(datetime(2019, 3, 4)), "b": "string4"},
93
+ ]
94
+
95
+ def test_to_records_date_str_month_ymd(self, util):
96
+ tbl = Table({"a": "date", "b": "string"})
97
+ data = [
98
+ {"a": "2019/01/02", "b": "string2"},
99
+ {"a": "2019/03/04", "b": "string4"},
100
+ ]
101
+ tbl.update(data)
102
+ view = tbl.view()
103
+ assert view.schema() == {"a": "date", "b": "string"}
104
+ assert view.to_records() == [
105
+ {"a": util.to_timestamp(datetime(2019, 1, 2)), "b": "string2"},
106
+ {"a": util.to_timestamp(datetime(2019, 3, 4)), "b": "string4"},
107
+ ]
108
+
109
+ def test_to_records_datetime(self, util):
110
+ dt = datetime(2019, 9, 10, 19, 30, 59, 515000)
111
+ data = [{"a": str(dt), "b": "string2"}, {"a": str(dt), "b": "string4"}]
112
+ tbl = Table({"a": "datetime", "b": "string"})
113
+ tbl.update(data)
114
+ view = tbl.view()
115
+ data_out = [
116
+ {"a": util.to_timestamp(dt), "b": "string2"},
117
+ {"a": util.to_timestamp(dt), "b": "string4"},
118
+ ]
119
+ assert view.to_records() == data_out # should have symmetric input/output
120
+
121
+ @mark.skip(reason="No longer supported format")
122
+ def test_to_records_datetime_str(self, util):
123
+ data = [
124
+ {"a": "03/11/2019 3:15PM", "b": "string2"},
125
+ {"a": "3/11/2019 3:20PM", "b": "string4"},
126
+ ]
127
+ tbl = Table({"a": "datetime", "b": "string"})
128
+ tbl.update(data)
129
+ view = tbl.view()
130
+ assert view.schema()["a"] == "datetime"
131
+ assert view.to_records() == [
132
+ {"a": util.to_timestamp(datetime(2019, 3, 11, 15, 15)), "b": "string2"},
133
+ {"a": util.to_timestamp(datetime(2019, 3, 11, 15, 20)), "b": "string4"},
134
+ ]
135
+
136
+ @mark.skip(reason="No longer supported format")
137
+ def test_to_records_datetime_str_tz(self, util):
138
+ dt = "2019/07/25T15:30:00+00:00"
139
+ data = [{"a": dt}, {"a": dt}]
140
+ tbl = Table({"a": "datetime"})
141
+ tbl.update(data)
142
+
143
+ view = tbl.view()
144
+ assert view.schema()["a"] == "datetime"
145
+ records = view.to_records()
146
+ for r in records:
147
+ r["a"] = r["a"].replace(tzinfo=pytz.utc)
148
+ assert records == [
149
+ {"a": (datetime(2019, 7, 25, 15, 30, tzinfo=pytz.utc))},
150
+ {"a": (datetime(2019, 7, 25, 15, 30, tzinfo=pytz.utc))},
151
+ ]
152
+
153
+ @mark.skip(reason="No longer supported format")
154
+ def test_to_records_datetime_ms_str(self, util):
155
+ data = [{"a": "03/11/2019 3:15:15.999PM"}, {"a": "3/11/2019 3:15:16.001PM"}]
156
+ tbl = Table({"a": "datetime"})
157
+ tbl.update(data)
158
+
159
+ view = tbl.view()
160
+ assert view.schema()["a"] == "datetime"
161
+ assert view.to_records() == [
162
+ {"a": util.to_timestamp(datetime(2019, 3, 11, 15, 15, 15, 999000))},
163
+ {"a": util.to_timestamp(datetime(2019, 3, 11, 15, 15, 16, 1000))},
164
+ ]
165
+
166
+ def test_to_records_none(self):
167
+ data = [{"a": None, "b": 1}, {"a": None, "b": 2}]
168
+ tbl = Table(data)
169
+ view = tbl.view()
170
+ assert view.to_records() == data
171
+
172
+ def test_to_records_one(self):
173
+ data = [{"a": 1, "b": "string1"}, {"a": 1, "b": "string2"}]
174
+ tbl = Table(data)
175
+ view = tbl.view(group_by=["a"])
176
+ assert view.to_records() == [
177
+ {"__ROW_PATH__": [], "a": 2, "b": 2},
178
+ {"__ROW_PATH__": [1], "a": 2, "b": 2},
179
+ ]
180
+
181
+ def test_to_records_two(self):
182
+ data = [{"a": 1, "b": "string1"}, {"a": 1, "b": "string2"}]
183
+ tbl = Table(data)
184
+ view = tbl.view(group_by=["a"], split_by=["b"])
185
+ assert view.to_records() == [
186
+ {
187
+ "__ROW_PATH__": [],
188
+ "string1|a": 1,
189
+ "string1|b": 1,
190
+ "string2|a": 1,
191
+ "string2|b": 1,
192
+ },
193
+ {
194
+ "__ROW_PATH__": [1],
195
+ "string1|a": 1,
196
+ "string1|b": 1,
197
+ "string2|a": 1,
198
+ "string2|b": 1,
199
+ },
200
+ ]
201
+
202
+ def test_to_records_column_only(self):
203
+ data = [{"a": 1, "b": "string1"}, {"a": 1, "b": "string2"}]
204
+ tbl = Table(data)
205
+ view = tbl.view(split_by=["b"])
206
+ assert view.to_records() == [
207
+ {
208
+ "string1|a": 1,
209
+ "string1|b": "string1",
210
+ "string2|a": None,
211
+ "string2|b": None,
212
+ },
213
+ {
214
+ "string1|a": None,
215
+ "string1|b": None,
216
+ "string2|a": 1,
217
+ "string2|b": "string2",
218
+ },
219
+ ]
220
+
221
+ # to_columns
222
+
223
+ def test_to_columns_int(self):
224
+ data = [{"a": 1, "b": 2}, {"a": 3, "b": 4}]
225
+ tbl = Table(data)
226
+ view = tbl.view()
227
+ assert view.to_columns() == {"a": [1, 3], "b": [2, 4]}
228
+
229
+ def test_to_columns_float(self):
230
+ data = [{"a": 1.5, "b": 2.5}, {"a": 3.5, "b": 4.5}]
231
+ tbl = Table(data)
232
+ view = tbl.view()
233
+ assert view.to_columns() == {"a": [1.5, 3.5], "b": [2.5, 4.5]}
234
+
235
+ def test_to_columns_date(self, util):
236
+ today = date.today()
237
+ dt = datetime(today.year, today.month, today.day)
238
+ data = [{"a": today, "b": 2}, {"a": today, "b": 4}]
239
+ tbl = Table(data)
240
+ view = tbl.view()
241
+ assert view.to_columns() == {
242
+ "a": [util.to_timestamp(dt), util.to_timestamp(dt)],
243
+ "b": [2, 4],
244
+ }
245
+
246
+ def test_to_columns_datetime(self, util):
247
+ dt = datetime(2019, 3, 15, 20, 30, 59, 6000)
248
+ data = [{"a": dt, "b": 2}, {"a": dt, "b": 4}]
249
+ tbl = Table(data)
250
+ view = tbl.view()
251
+ assert view.to_columns() == {
252
+ "a": [util.to_timestamp(dt), util.to_timestamp(dt)],
253
+ "b": [2, 4],
254
+ }
255
+
256
+ def test_to_columns_bool(self):
257
+ data = [{"a": True, "b": False}, {"a": True, "b": False}]
258
+ tbl = Table(data)
259
+ view = tbl.view()
260
+ assert view.to_columns() == {"a": [True, True], "b": [False, False]}
261
+
262
+ def test_to_columns_string(self):
263
+ data = [{"a": "string1", "b": "string2"}, {"a": "string3", "b": "string4"}]
264
+ tbl = Table(data)
265
+ view = tbl.view()
266
+ assert view.to_columns() == {
267
+ "a": ["string1", "string3"],
268
+ "b": ["string2", "string4"],
269
+ }
270
+
271
+ def test_to_columns_none(self):
272
+ data = [{"a": None, "b": None}, {"a": None, "b": None}]
273
+ tbl = Table(data)
274
+ view = tbl.view()
275
+ assert view.to_columns() == {"a": [None, None], "b": [None, None]}
276
+
277
+ def test_to_columns_one(self):
278
+ data = [{"a": 1, "b": 2}, {"a": 1, "b": 2}]
279
+ tbl = Table(data)
280
+ view = tbl.view(group_by=["a"])
281
+ assert view.to_columns() == {
282
+ "__ROW_PATH__": [[], [1]],
283
+ "a": [2, 2],
284
+ "b": [4, 4],
285
+ }
286
+
287
+ def test_to_columns_two(self):
288
+ data = [{"a": 1, "b": 2}, {"a": 1, "b": 2}]
289
+ tbl = Table(data)
290
+ view = tbl.view(group_by=["a"], split_by=["b"])
291
+ assert view.to_columns() == {
292
+ "__ROW_PATH__": [[], [1]],
293
+ "2|a": [2, 2],
294
+ "2|b": [4, 4],
295
+ }
296
+
297
+ def test_to_columns_column_only(self):
298
+ data = [{"a": 1, "b": 2}, {"a": 1, "b": 2}]
299
+ tbl = Table(data)
300
+ view = tbl.view(split_by=["b"])
301
+ assert view.to_columns() == {
302
+ "2|a": [1, 1],
303
+ "2|b": [2, 2],
304
+ }
305
+
306
+ def test_to_columns_one_no_columns(self):
307
+ data = [{"a": 1, "b": 2}, {"a": 1, "b": 2}]
308
+ tbl = Table(data)
309
+ view = tbl.view(group_by=["a"], columns=[])
310
+ assert view.to_columns() == {"__ROW_PATH__": [[], [1]]}
311
+
312
+ def test_to_columns_two_no_columns(self):
313
+ data = [{"a": 1, "b": 2}, {"a": 1, "b": 2}]
314
+ tbl = Table(data)
315
+ view = tbl.view(group_by=["a"], split_by=["b"], columns=[])
316
+ assert view.to_columns() == {"__ROW_PATH__": [[], [1]]}
317
+
318
+ def test_to_columns_column_only_no_columns(self):
319
+ data = [{"a": 1, "b": 2}, {"a": 1, "b": 2}]
320
+ tbl = Table(data)
321
+ view = tbl.view(split_by=["b"], columns=[])
322
+ assert view.to_columns() == {}
323
+
324
+ # to_numpy
325
+
326
+ @mark.skip(reason="No numpy support")
327
+ def test_to_numpy_int(self):
328
+ data = [{"a": 1, "b": 2}, {"a": 3, "b": 4}]
329
+ tbl = Table(data)
330
+ view = tbl.view()
331
+ v = view.to_numpy()
332
+ assert np.array_equal(v["a"], np.array([1, 3]))
333
+ assert np.array_equal(v["b"], np.array([2, 4]))
334
+
335
+ @mark.skip(reason="No numpy support")
336
+ def test_to_numpy_float(self):
337
+ data = [{"a": 1.5, "b": 2.5}, {"a": 3.5, "b": 4.5}]
338
+ tbl = Table(data)
339
+ view = tbl.view()
340
+ v = view.to_numpy()
341
+ assert np.array_equal(v["a"], np.array([1.5, 3.5]))
342
+ assert np.array_equal(v["b"], np.array([2.5, 4.5]))
343
+
344
+ @mark.skip(reason="No numpy support")
345
+ def test_to_numpy_bool(self):
346
+ data = [{"a": True, "b": False}, {"a": True, "b": False}]
347
+ tbl = Table(data)
348
+ view = tbl.view()
349
+ v = view.to_numpy()
350
+ assert np.array_equal(v["a"], np.array([True, True]))
351
+ assert np.array_equal(v["b"], np.array([False, False]))
352
+
353
+ @mark.skip(reason="No numpy support")
354
+ def test_to_numpy_date(self):
355
+ today = date.today()
356
+ dt = datetime(today.year, today.month, today.day)
357
+ data = [{"a": dt, "b": 2}, {"a": dt, "b": 4}]
358
+ tbl = Table(data)
359
+ view = tbl.view()
360
+ v = view.to_numpy()
361
+ assert np.array_equal(v["a"], np.array([dt, dt]))
362
+
363
+ @mark.skip(reason="No numpy support")
364
+ def test_to_numpy_datetime(self):
365
+ dt = datetime(2019, 3, 15, 20, 30, 59, 6000)
366
+ data = [{"a": dt}, {"a": dt}]
367
+ tbl = Table(data)
368
+ view = tbl.view()
369
+ v = view.to_numpy()
370
+ assert np.array_equal(v["a"], np.array([dt, dt]))
371
+
372
+ @mark.skip(reason="No numpy support")
373
+ def test_to_numpy_string(self):
374
+ data = [{"a": "string1", "b": "string2"}, {"a": "string3", "b": "string4"}]
375
+ tbl = Table(data)
376
+ view = tbl.view()
377
+ v = view.to_numpy()
378
+ assert np.array_equal(v["a"], np.array(["string1", "string3"]))
379
+ assert np.array_equal(v["b"], np.array(["string2", "string4"]))
380
+
381
+ @mark.skip(reason="No numpy support")
382
+ def test_to_numpy_none(self):
383
+ data = [{"a": None, "b": None}, {"a": None, "b": None}]
384
+ tbl = Table(data)
385
+ view = tbl.view()
386
+ v = view.to_numpy()
387
+ assert np.array_equal(v["a"], np.array([None, None]))
388
+ assert np.array_equal(v["b"], np.array([None, None]))
389
+
390
+ @mark.skip(reason="No numpy support")
391
+ def test_to_numpy_one(self):
392
+ data = [{"a": 1, "b": 2}, {"a": 1, "b": 2}]
393
+ tbl = Table(data)
394
+ view = tbl.view(group_by=["a"])
395
+ v = view.to_numpy()
396
+ assert np.array_equal(v["__ROW_PATH__"], np.array([[], [1]], dtype="object"))
397
+ assert np.array_equal(v["a"], np.array([2, 2]))
398
+ assert np.array_equal(v["b"], np.array([4, 4]))
399
+
400
+ @mark.skip(reason="No numpy support")
401
+ def test_to_numpy_two(self):
402
+ data = [{"a": 1, "b": 2}, {"a": 1, "b": 2}]
403
+ tbl = Table(data)
404
+ view = tbl.view(group_by=["a"], split_by=["b"])
405
+ v = view.to_numpy()
406
+ assert np.array_equal(v["__ROW_PATH__"], np.array([[], [1]], dtype="object"))
407
+ assert np.array_equal(v["2|a"], np.array([2, 2]))
408
+ assert np.array_equal(v["2|b"], np.array([4, 4]))
409
+
410
+ @mark.skip(reason="No numpy support")
411
+ def test_to_numpy_column_only(self):
412
+ data = [{"a": 1, "b": 2}, {"a": 1, "b": 2}]
413
+ tbl = Table(data)
414
+ view = tbl.view(split_by=["b"])
415
+ v = view.to_numpy()
416
+ assert np.array_equal(v["2|a"], np.array([1, 1]))
417
+ assert np.array_equal(v["2|b"], np.array([2, 2]))
418
+
419
+ @mark.skip(reason="No numpy support")
420
+ def test_to_pandas_df_simple(self):
421
+ data = [{"a": 1, "b": 2}, {"a": 1, "b": 2}]
422
+ df = pd.DataFrame(data)
423
+ tbl = Table(df)
424
+ view = tbl.view()
425
+ df2 = view.to_df()
426
+ assert np.array_equal(df2.columns, pd.Index(["index", "a", "b"], dtype=object))
427
+ assert np.array_equal(df2["a"].values, df["a"].values)
428
+ assert np.array_equal(df2["b"].values, df["b"].values)
429
+
430
+ @mark.skip(reason="No numpy support")
431
+ def test_to_pandas_df_simple_series(self):
432
+ inp = pd.Series([1, 2, 3], name="a")
433
+ df = pd.DataFrame()
434
+ df["a"] = pd.Series([1, 2, 3])
435
+ tbl = Table(inp)
436
+ view = tbl.view()
437
+ df2 = view.to_df()
438
+ assert np.array_equal(df2.columns, pd.Index(["index", "a"], dtype=object))
439
+ assert np.array_equal(df2["a"].values, df["a"].values)
440
+
441
+ # start_row/end_row
442
+ def test_to_records_zero_over_max_row(self):
443
+ data = [{"a": 1.5, "b": 2.5}, {"a": 3.5, "b": 4.5}]
444
+ tbl = Table(data)
445
+ view = tbl.view()
446
+ records = view.to_records(end_row=1000)
447
+ assert records == data
448
+
449
+ def test_to_records_one_over_max_row(self):
450
+ data = [{"a": 1.5, "b": 2.5}, {"a": 3.5, "b": 4.5}]
451
+ tbl = Table(data)
452
+ view = tbl.view(group_by=["a"])
453
+ records = view.to_records(end_row=1000)
454
+ assert records == [
455
+ {"__ROW_PATH__": [], "a": 5, "b": 7},
456
+ {"__ROW_PATH__": [1.5], "a": 1.5, "b": 2.5},
457
+ {"__ROW_PATH__": [3.5], "a": 3.5, "b": 4.5},
458
+ ]
459
+
460
+ def test_to_records_two_over_max_row(self):
461
+ data = [{"a": 1, "b": 2}, {"a": 3, "b": 4}]
462
+ tbl = Table(data)
463
+ view = tbl.view(group_by=["a"], split_by=["b"])
464
+ records = view.to_records(end_row=1000)
465
+ assert records == [
466
+ {"2|a": 1, "2|b": 2, "4|a": 3, "4|b": 4, "__ROW_PATH__": []},
467
+ {"2|a": 1, "2|b": 2, "4|a": None, "4|b": None, "__ROW_PATH__": [1]},
468
+ {"2|a": None, "2|b": None, "4|a": 3, "4|b": 4, "__ROW_PATH__": [3]},
469
+ ]
470
+
471
+ def test_to_records_start_row(self):
472
+ data = [{"a": 1, "b": 2}, {"a": 3, "b": 4}]
473
+ tbl = Table(data)
474
+ view = tbl.view()
475
+ records = view.to_records(start_row=1)
476
+ assert records == [{"a": 3, "b": 4}]
477
+
478
+ def test_to_records_end_row(self):
479
+ data = [{"a": 1, "b": 2}, {"a": 3, "b": 4}]
480
+ tbl = Table(data)
481
+ view = tbl.view()
482
+ records = view.to_records(end_row=1)
483
+ assert records == [{"a": 1, "b": 2}]
484
+
485
+ def test_to_records_start_row_end_row(self):
486
+ data = [{"a": 1, "b": 2}, {"a": 3, "b": 4}, {"a": 5, "b": 6}]
487
+ tbl = Table(data)
488
+ view = tbl.view()
489
+ records = view.to_records(start_row=1, end_row=2)
490
+ assert records == [{"a": 3, "b": 4}]
491
+
492
+ def test_to_records_start_row_end_row_equiv(self):
493
+ data = [{"a": 1, "b": 2}, {"a": 3, "b": 4}, {"a": 5, "b": 6}]
494
+ tbl = Table(data)
495
+ view = tbl.view()
496
+ records = view.to_records(start_row=1, end_row=1)
497
+ assert records == []
498
+
499
+ def test_to_records_floor_start_row(self):
500
+ data = [{"a": 1, "b": 2}, {"a": 3, "b": 4}]
501
+ tbl = Table(data)
502
+ view = tbl.view()
503
+ records = view.to_records(start_row=1.5)
504
+ assert records == [{"a": 3, "b": 4}]
505
+
506
+ def test_to_records_ceil_end_row(self):
507
+ data = [{"a": 1, "b": 2}, {"a": 3, "b": 4}]
508
+ tbl = Table(data)
509
+ view = tbl.view()
510
+ records = view.to_records(end_row=0.5)
511
+ assert records == [{"a": 1, "b": 2}]
512
+
513
+ def test_to_records_floor_start_row_ceil_end_row(self):
514
+ data = [{"a": 1, "b": 2}, {"a": 3, "b": 4}, {"a": 5, "b": 6}]
515
+ tbl = Table(data)
516
+ view = tbl.view()
517
+ records = view.to_records(start_row=1.5, end_row=1.5)
518
+ assert records == [{"a": 3, "b": 4}]
519
+
520
+ def test_to_records_floor_start_row_ceil_end_row_equiv(self):
521
+ data = [{"a": 1, "b": 2}, {"a": 3, "b": 4}, {"a": 5, "b": 6}]
522
+ tbl = Table(data)
523
+ view = tbl.view()
524
+ records = view.to_records(start_row=1.5, end_row=0.5)
525
+ assert records == []
526
+
527
+ # start_col/end_col
528
+
529
+ def test_to_records_zero_over_max_col(self):
530
+ data = [{"a": 1.5, "b": 2.5}, {"a": 3.5, "b": 4.5}]
531
+ tbl = Table(data)
532
+ view = tbl.view()
533
+ records = view.to_records(end_col=1000)
534
+ assert records == data
535
+
536
+ def test_to_records_zero_start_gt_end_col(self):
537
+ data = [{"a": 1.5, "b": 2.5}, {"a": 3.5, "b": 4.5}]
538
+ tbl = Table(data)
539
+ view = tbl.view()
540
+ records = view.to_records(start_col=2, end_col=1)
541
+ assert records == []
542
+
543
+ def test_to_records_zero_start_eq_end_col(self):
544
+ data = [{"a": 1.5, "b": 2.5}, {"a": 3.5, "b": 4.5}]
545
+ tbl = Table(data)
546
+ view = tbl.view()
547
+ records = view.to_records(start_col=1, end_col=1)
548
+ assert records == []
549
+
550
+ def test_to_records_one_over_max_col(self):
551
+ data = [{"a": 1.5, "b": 2.5}, {"a": 3.5, "b": 4.5}]
552
+ tbl = Table(data)
553
+ view = tbl.view(group_by=["a"])
554
+ records = view.to_records(end_col=1000)
555
+ assert records == [
556
+ {"__ROW_PATH__": [], "a": 5, "b": 7},
557
+ {"__ROW_PATH__": [1.5], "a": 1.5, "b": 2.5},
558
+ {"__ROW_PATH__": [3.5], "a": 3.5, "b": 4.5},
559
+ ]
560
+
561
+ def test_to_records_one_start_gt_end_col(self):
562
+ data = [{"a": 1.5, "b": 2.5}, {"a": 3.5, "b": 4.5}]
563
+ tbl = Table(data)
564
+ view = tbl.view(group_by=["a"])
565
+ records = view.to_records(start_col=2, end_col=1)
566
+ assert records == [
567
+ {"__ROW_PATH__": []},
568
+ {"__ROW_PATH__": [1.5]},
569
+ {"__ROW_PATH__": [3.5]},
570
+ ]
571
+
572
+ def test_to_records_one_start_gt_end_col_large(self):
573
+ data = [{"a": 1.5, "b": 2.5}, {"a": 3.5, "b": 4.5}]
574
+ tbl = Table(data)
575
+ view = tbl.view(group_by=["a"])
576
+ records = view.to_records(start_col=20, end_col=19)
577
+ assert records == [
578
+ {"__ROW_PATH__": []},
579
+ {"__ROW_PATH__": [1.5]},
580
+ {"__ROW_PATH__": [3.5]},
581
+ ]
582
+
583
+ def test_to_records_one_start_eq_end_col(self):
584
+ data = [{"a": 1.5, "b": 2.5}, {"a": 3.5, "b": 4.5}]
585
+ tbl = Table(data)
586
+ view = tbl.view(group_by=["a"])
587
+ records = view.to_records(start_col=0, end_col=0)
588
+ assert records == [
589
+ {"__ROW_PATH__": []},
590
+ {"__ROW_PATH__": [1.5]},
591
+ {"__ROW_PATH__": [3.5]},
592
+ ]
593
+
594
+ def test_to_records_two_over_max_col(self):
595
+ data = [{"a": 1, "b": 2}, {"a": 3, "b": 4}]
596
+ tbl = Table(data)
597
+ view = tbl.view(group_by=["a"], split_by=["b"])
598
+ records = view.to_records(end_col=1000)
599
+ assert records == [
600
+ {"2|a": 1, "2|b": 2, "4|a": 3, "4|b": 4, "__ROW_PATH__": []},
601
+ {"2|a": 1, "2|b": 2, "4|a": None, "4|b": None, "__ROW_PATH__": [1]},
602
+ {"2|a": None, "2|b": None, "4|a": 3, "4|b": 4, "__ROW_PATH__": [3]},
603
+ ]
604
+
605
+ def test_to_records_start_col(self):
606
+ data = [{"a": 1, "b": 2}, {"a": 3, "b": 4}]
607
+ tbl = Table(data)
608
+ view = tbl.view()
609
+ records = view.to_records(start_col=1)
610
+ assert records == [{"b": 2}, {"b": 4}]
611
+
612
+ def test_to_records_end_col(self):
613
+ data = [{"a": 1, "b": 2}, {"a": 3, "b": 4}]
614
+ tbl = Table(data)
615
+ view = tbl.view()
616
+ records = view.to_records(end_col=1)
617
+ assert records == [{"a": 1}, {"a": 3}]
618
+
619
+ def test_to_records_two_end_col(self):
620
+ data = [{"a": 1, "b": 2}, {"a": 3, "b": 4}]
621
+ tbl = Table(data)
622
+ view = tbl.view(group_by=["a"], split_by=["b"])
623
+ records = view.to_records(end_row=12, end_col=5)
624
+ assert records == [
625
+ {"2|a": 1, "2|b": 2, "4|a": 3, "4|b": 4, "__ROW_PATH__": []},
626
+ {"2|a": 1, "2|b": 2, "4|a": None, "4|b": None, "__ROW_PATH__": [1]},
627
+ {"2|a": None, "2|b": None, "4|a": 3, "4|b": 4, "__ROW_PATH__": [3]},
628
+ ]
629
+
630
+ def test_to_records_two_start_gt_end_col(self):
631
+ data = [{"a": 1, "b": 2}, {"a": 3, "b": 4}]
632
+ tbl = Table(data)
633
+ view = tbl.view(group_by=["a"], split_by=["b"])
634
+ records = view.to_records(end_row=12, start_col=5, end_col=4)
635
+ assert records == [
636
+ {"__ROW_PATH__": []},
637
+ {"__ROW_PATH__": [1]},
638
+ {"__ROW_PATH__": [3]},
639
+ ]
640
+
641
+ def test_to_records_two_start_gt_end_col_large_overage(self):
642
+ data = [{"a": 1, "b": 2}, {"a": 3, "b": 4}]
643
+ tbl = Table(data)
644
+ view = tbl.view(group_by=["a"], split_by=["b"])
645
+ records = view.to_records(end_row=12, start_col=50, end_col=49)
646
+ assert records == [
647
+ {"__ROW_PATH__": []},
648
+ {"__ROW_PATH__": [1]},
649
+ {"__ROW_PATH__": [3]},
650
+ ]
651
+
652
+ def test_to_records_two_start_end_col_equiv(self):
653
+ data = [{"a": 1, "b": 2}, {"a": 3, "b": 4}]
654
+ tbl = Table(data)
655
+ view = tbl.view(group_by=["a"], split_by=["b"])
656
+ records = view.to_records(end_row=12, start_col=5, end_col=5)
657
+ assert records == [
658
+ {"__ROW_PATH__": []},
659
+ {"__ROW_PATH__": [1]},
660
+ {"__ROW_PATH__": [3]},
661
+ ]
662
+
663
+ def test_to_records_two_sorted_start_gt_end_col(self):
664
+ data = [{"a": 1, "b": 2}, {"a": 3, "b": 4}]
665
+ tbl = Table(data)
666
+ view = tbl.view(group_by=["a"], split_by=["b"], sort=[["a", "desc"]])
667
+ records = view.to_records(end_row=12, start_col=5, end_col=4)
668
+ assert records == [
669
+ {"__ROW_PATH__": []},
670
+ {"__ROW_PATH__": [3]},
671
+ {"__ROW_PATH__": [1]},
672
+ ]
673
+
674
+ def test_to_records_two_sorted_start_gt_end_col_large_overage(self):
675
+ data = [{"a": 1, "b": 2}, {"a": 3, "b": 4}]
676
+ tbl = Table(data)
677
+ view = tbl.view(group_by=["a"], split_by=["b"], sort=[["a", "desc"]])
678
+ records = view.to_records(end_row=12, start_col=20, end_col=30)
679
+ assert records == [
680
+ {"__ROW_PATH__": []},
681
+ {"__ROW_PATH__": [3]},
682
+ {"__ROW_PATH__": [1]},
683
+ ]
684
+
685
+ def test_to_records_two_sorted_start_gt_end_col_overage(self):
686
+ data = [{"a": 1, "b": 2}, {"a": 3, "b": 4}]
687
+ tbl = Table(data)
688
+ view = tbl.view(
689
+ columns=[], group_by=["a"], split_by=["b"], sort=[["a", "desc"]]
690
+ )
691
+ records = view.to_records(end_row=12, start_col=1, end_col=3)
692
+ assert records == [
693
+ {"__ROW_PATH__": []},
694
+ {"__ROW_PATH__": [3]},
695
+ {"__ROW_PATH__": [1]},
696
+ ]
697
+
698
+ def test_to_records_two_sorted_start_end_col(self):
699
+ data = [{"a": 1, "b": 2}, {"a": 3, "b": 4}]
700
+ tbl = Table(data)
701
+ view = tbl.view(group_by=["a"], split_by=["b"], sort=[["a", "desc"]])
702
+ records = view.to_records(start_col=1, end_col=2)
703
+ assert records == [
704
+ {"2|b": 2, "__ROW_PATH__": []},
705
+ {"2|b": None, "__ROW_PATH__": [3]},
706
+ {"2|b": 2, "__ROW_PATH__": [1]},
707
+ ]
708
+
709
+ def test_to_records_two_sorted_start_end_col_equiv(self):
710
+ data = [{"a": 1, "b": 2}, {"a": 3, "b": 4}]
711
+ tbl = Table(data)
712
+ view = tbl.view(group_by=["a"], split_by=["b"], sort=[["a", "desc"]])
713
+ records = view.to_records(end_row=12, start_col=5, end_col=5)
714
+ assert records == [
715
+ {"__ROW_PATH__": []},
716
+ {"__ROW_PATH__": [3]},
717
+ {"__ROW_PATH__": [1]},
718
+ ]
719
+
720
+ def test_to_records_start_col_end_col(self):
721
+ data = [{"a": 1, "b": 2, "c": 3}, {"a": 3, "b": 4, "c": 5}]
722
+ tbl = Table(data)
723
+ view = tbl.view()
724
+ records = view.to_records(start_col=1, end_col=2)
725
+ # start_col and end_col access columns at that index - dict key order not guaranteed in python2
726
+ assert records == [{"b": 2}, {"b": 4}]
727
+
728
+ def test_to_records_start_col_end_col_equiv(self):
729
+ data = [{"a": 1, "b": 2, "c": 3}, {"a": 3, "b": 4, "c": 5}]
730
+ tbl = Table(data)
731
+ view = tbl.view()
732
+ records = view.to_records(start_col=1, end_col=1)
733
+ assert records == []
734
+
735
+ def test_to_records_floor_start_col(self):
736
+ data = [{"a": 1, "b": 2}, {"a": 3, "b": 4}]
737
+ tbl = Table(data)
738
+ view = tbl.view()
739
+ records = view.to_records(start_col=1.5)
740
+ assert records == [{"b": 2}, {"b": 4}]
741
+
742
+ def test_to_records_ceil_end_col(self):
743
+ data = [{"a": 1, "b": 2}, {"a": 3, "b": 4}]
744
+ tbl = Table(data)
745
+ view = tbl.view()
746
+ records = view.to_records(end_col=1)
747
+ assert records == [{"a": 1}, {"a": 3}]
748
+
749
+ def test_to_records_two_ceil_end_col(self):
750
+ data = [{"a": 1, "b": 2}, {"a": 3, "b": 4}]
751
+ tbl = Table(data)
752
+ view = tbl.view(group_by=["a"], split_by=["b"])
753
+ records = view.to_records(end_row=12, end_col=4.5)
754
+ assert records == [
755
+ {"2|a": 1, "2|b": 2, "4|a": 3, "4|b": 4, "__ROW_PATH__": []},
756
+ {"2|a": 1, "2|b": 2, "4|a": None, "4|b": None, "__ROW_PATH__": [1]},
757
+ {"2|a": None, "2|b": None, "4|a": 3, "4|b": 4, "__ROW_PATH__": [3]},
758
+ ]
759
+
760
+ def test_to_records_floor_start_col_ceil_end_col(self):
761
+ data = [{"a": 1, "b": 2, "c": 3}, {"a": 3, "b": 4, "c": 5}]
762
+ tbl = Table(data)
763
+ view = tbl.view()
764
+ records = view.to_records(start_col=1.5, end_col=1.5)
765
+ # start_col and end_col access columns at that index - dict key order not guaranteed in python2
766
+ assert records == [{"b": 2}, {"b": 4}]
767
+
768
+ def test_to_columns_start_col_end_col(self):
769
+ data = [{"a": 1, "b": 2, "c": 3, "d": 4}, {"a": 3, "b": 4, "c": 5, "d": 6}]
770
+ tbl = Table(data)
771
+ view = tbl.view()
772
+ d = view.to_columns(start_col=1, end_col=3)
773
+ assert d == {"b": [2, 4], "c": [3, 5]}
774
+
775
+ # to csv
776
+
777
+ # XXX: Table(pandas_df) does not include the index column anymore.
778
+ def test_to_csv_symmetric(self):
779
+ csv = "a,b\n1,2\n3,4"
780
+ df = pd.read_csv(StringIO(csv))
781
+ tbl = Table(df)
782
+ view = tbl.view()
783
+ assert view.to_csv() == '"index","a","b"\n0,1,2\n1,3,4\n'
784
+
785
+ def test_to_csv_int(self):
786
+ data = [{"a": 1, "b": 2}, {"a": 3, "b": 4}]
787
+ tbl = Table(data)
788
+ view = tbl.view()
789
+ assert view.to_csv() == '"a","b"\n1,2\n3,4\n'
790
+
791
+ def test_to_csv_float(self):
792
+ data = [{"a": 1.5, "b": 2.5}, {"a": 3.5, "b": 4.5}]
793
+ tbl = Table(data)
794
+ view = tbl.view()
795
+ assert view.to_csv() == '"a","b"\n1.5,2.5\n3.5,4.5\n'
796
+
797
+ def test_to_csv_date(self):
798
+ today = date.today()
799
+ dt_str = today.strftime("%Y-%m-%d")
800
+ data = [{"a": today, "b": 2}, {"a": today, "b": 4}]
801
+ tbl = Table(data)
802
+ assert tbl.schema()["a"] == "date"
803
+ view = tbl.view()
804
+ assert view.to_csv() == '"a","b"\n{},2\n{},4\n'.format(dt_str, dt_str)
805
+
806
+ # XXX: Broken because our datetime parsing is broken
807
+ def test_to_csv_datetime(self):
808
+ dt = datetime(2019, 3, 15, 20, 30, 59, 6000)
809
+ dt_str = dt.strftime("%Y-%m-%d %H:%M:%S.%f")[:-3]
810
+ data = [{"a": dt, "b": 2}, {"a": dt, "b": 4}]
811
+ tbl = Table(data)
812
+ view = tbl.view()
813
+ assert view.to_csv() == '"a","b"\n{},2\n{},4\n'.format(dt_str, dt_str)
814
+
815
+ def test_to_csv_bool(self):
816
+ data = [{"a": True, "b": False}, {"a": True, "b": False}]
817
+ tbl = Table(data)
818
+ view = tbl.view()
819
+ assert view.to_csv() == '"a","b"\ntrue,false\ntrue,false\n'
820
+
821
+ def test_to_csv_string(self):
822
+ data = [{"a": "string1", "b": "string2"}, {"a": "string3", "b": "string4"}]
823
+ tbl = Table(data)
824
+ view = tbl.view()
825
+ assert view.to_csv() == '"a","b"\n"string1","string2"\n"string3","string4"\n'
826
+
827
+ def test_to_csv_none(self):
828
+ data = [{"a": None, "b": None}, {"a": None, "b": None}]
829
+ tbl = Table(data)
830
+ view = tbl.view()
831
+ assert view.to_csv() == '"a","b"\n,\n,\n'
832
+
833
+ def test_to_csv_custom_rows(self):
834
+ data = [{"a": 1, "b": 2}, {"a": 3, "b": 4}]
835
+ tbl = Table(data)
836
+ view = tbl.view()
837
+ assert view.to_csv(start_row=1) == '"a","b"\n3,4\n'
838
+
839
+ def test_to_csv_custom_cols(self):
840
+ data = [{"a": 1, "b": 2}, {"a": 3, "b": 4}]
841
+ tbl = Table(data)
842
+ view = tbl.view()
843
+ assert view.to_csv(start_col=1) == '"b"\n2\n4\n'
844
+
845
+ def test_to_csv_custom_rows_cols(self):
846
+ data = [{"a": 1, "b": 2}, {"a": 3, "b": 4}]
847
+ tbl = Table(data)
848
+ view = tbl.view()
849
+ assert view.to_csv(start_row=1, start_col=1) == '"b"\n4\n'
850
+
851
+ def test_to_csv_one(self):
852
+ data = [{"a": 1, "b": 2}, {"a": 1, "b": 2}]
853
+ tbl = Table(data)
854
+ view = tbl.view(group_by=["a"])
855
+ assert view.to_csv() == '"a (Group by 1)","a","b"\n,2,4\n1,2,4\n'
856
+
857
+ def test_to_csv_two(self):
858
+ data = [{"a": 1, "b": 2}, {"a": 1, "b": 2}]
859
+ tbl = Table(data)
860
+ view = tbl.view(group_by=["a"], split_by=["b"])
861
+ assert view.to_csv() == '"a (Group by 1)","2|a","2|b"\n,2,4\n1,2,4\n'
862
+
863
+ def test_to_csv_column_only(self):
864
+ data = [{"a": 1, "b": 2}, {"a": 1, "b": 2}]
865
+ tbl = Table(data)
866
+ view = tbl.view(split_by=["b"])
867
+ assert view.to_csv() == '"2|a","2|b"\n1,2\n1,2\n'
868
+
869
+ def test_to_csv_one_no_columns(self):
870
+ data = [{"a": 1, "b": 2}, {"a": 1, "b": 2}]
871
+ tbl = Table(data)
872
+ view = tbl.view(group_by=["a"], columns=[])
873
+ assert view.to_csv() == '"a (Group by 1)"\n\n1\n'
874
+
875
+ def test_to_csv_two_no_columns(self):
876
+ data = [{"a": 1, "b": 2}, {"a": 1, "b": 2}]
877
+ tbl = Table(data)
878
+ view = tbl.view(group_by=["a"], split_by=["b"], columns=[])
879
+ assert view.to_csv() == '"a (Group by 1)"\n\n1\n'
880
+
881
+ def test_to_csv_column_only_no_columns(self):
882
+ data = [{"a": 1, "b": 2}, {"a": 1, "b": 2}]
883
+ tbl = Table(data)
884
+ view = tbl.view(split_by=["b"], columns=[])
885
+
886
+ assert view.to_csv() == ""
887
+
888
+ # implicit index
889
+
890
+ def test_to_format_implicit_index_records(self):
891
+ data = [{"a": 1.5, "b": 2.5}, {"a": 3.5, "b": 4.5}]
892
+ tbl = Table(data)
893
+ view = tbl.view()
894
+ assert view.to_records(index=True) == [
895
+ {"__INDEX__": [0], "a": 1.5, "b": 2.5},
896
+ {"__INDEX__": [1], "a": 3.5, "b": 4.5},
897
+ ]
898
+
899
+ def test_to_format_implicit_index_dict(self):
900
+ data = [{"a": 1.5, "b": 2.5}, {"a": 3.5, "b": 4.5}]
901
+ tbl = Table(data)
902
+ view = tbl.view()
903
+ assert view.to_columns(index=True) == {
904
+ "__INDEX__": [[0], [1]],
905
+ "a": [1.5, 3.5],
906
+ "b": [2.5, 4.5],
907
+ }
908
+
909
+ def test_to_format_implicit_id_records(self):
910
+ data = [{"a": 1.5, "b": 2.5}, {"a": 3.5, "b": 4.5}]
911
+ tbl = Table(data)
912
+ view = tbl.view()
913
+ assert view.to_records(id=True) == [
914
+ {"__ID__": [0], "a": 1.5, "b": 2.5},
915
+ {"__ID__": [1], "a": 3.5, "b": 4.5},
916
+ ]
917
+
918
+ def test_to_format_implicit_id_dict(self):
919
+ data = [{"a": 1.5, "b": 2.5}, {"a": 3.5, "b": 4.5}]
920
+ tbl = Table(data)
921
+ view = tbl.view()
922
+ assert view.to_columns(id=True) == {
923
+ "__ID__": [[0], [1]],
924
+ "a": [1.5, 3.5],
925
+ "b": [2.5, 4.5],
926
+ }
927
+
928
+ def test_to_format_implicit_index_two_dict_1(self):
929
+ data = [{"a": 1.5, "b": 2.5}, {"a": 3.5, "b": 4.5}]
930
+ tbl = Table(data)
931
+ view = tbl.view(group_by=["a"], split_by=["b"])
932
+ assert view.to_columns(index=True) == {
933
+ "2.5|a": [1.5, 1.5, None],
934
+ "2.5|b": [2.5, 2.5, None],
935
+ "4.5|a": [3.5, None, 3.5],
936
+ "4.5|b": [4.5, None, 4.5],
937
+ "__INDEX__": [
938
+ [],
939
+ [],
940
+ [],
941
+ ], # index needs to be the same length as each column
942
+ "__ROW_PATH__": [[], [1.5], [3.5]],
943
+ }
944
+
945
+ def test_to_format_implicit_index_two_dict_2(self):
946
+ data = [{"a": 1.5, "b": 2.5}, {"a": 3.5, "b": 4.5}]
947
+ tbl = Table(data)
948
+ view = tbl.view(group_by=["a"], split_by=["b"])
949
+ assert view.to_columns(id=True) == {
950
+ "2.5|a": [1.5, 1.5, None],
951
+ "2.5|b": [2.5, 2.5, None],
952
+ "4.5|a": [3.5, None, 3.5],
953
+ "4.5|b": [4.5, None, 4.5],
954
+ "__ID__": [
955
+ [],
956
+ [1.5],
957
+ [3.5],
958
+ ], # index needs to be the same length as each column
959
+ "__ROW_PATH__": [[], [1.5], [3.5]],
960
+ }
961
+
962
+ @mark.skip(reason="No numpy support")
963
+ def test_to_format_implicit_index_np(self):
964
+ data = [{"a": 1.5, "b": 2.5}, {"a": 3.5, "b": 4.5}]
965
+ tbl = Table(data)
966
+ view = tbl.view()
967
+ cols = view.to_numpy(index=True)
968
+ assert np.array_equal(cols["__INDEX__"], np.array([[0], [1]]))
969
+
970
+ def test_to_format_explicit_index_records(self):
971
+ data = [{"a": 1.5, "b": 2.5}, {"a": 3.5, "b": 4.5}]
972
+ tbl = Table(data, index="a")
973
+ view = tbl.view()
974
+ assert view.to_records(index=True) == [
975
+ {"__INDEX__": [1.5], "a": 1.5, "b": 2.5},
976
+ {"__INDEX__": [3.5], "a": 3.5, "b": 4.5},
977
+ ]
978
+
979
+ def test_to_format_explicit_index_dict(self):
980
+ data = [{"a": 1.5, "b": 2.5}, {"a": 3.5, "b": 4.5}]
981
+ tbl = Table(data, index="a")
982
+ view = tbl.view()
983
+ assert view.to_columns(index=True) == {
984
+ "__INDEX__": [[1.5], [3.5]],
985
+ "a": [1.5, 3.5],
986
+ "b": [2.5, 4.5],
987
+ }
988
+
989
+ @mark.skip(reason="No numpy supprt")
990
+ def test_to_format_explicit_index_np(self):
991
+ data = [{"a": 1.5, "b": 2.5}, {"a": 3.5, "b": 4.5}]
992
+ tbl = Table(data, index="a")
993
+ view = tbl.view()
994
+ cols = view.to_numpy(index=True)
995
+ assert np.array_equal(cols["__INDEX__"], np.array([[1.5], [3.5]]))
996
+
997
+ def test_to_format_explicit_index_str_records(self):
998
+ data = [{"a": "a", "b": 2.5}, {"a": "b", "b": 4.5}]
999
+ tbl = Table(data, index="a")
1000
+ view = tbl.view()
1001
+ assert view.to_records(index=True) == [
1002
+ {"__INDEX__": ["a"], "a": "a", "b": 2.5},
1003
+ {"__INDEX__": ["b"], "a": "b", "b": 4.5},
1004
+ ]
1005
+
1006
+ def test_to_format_explicit_index_datetime_records(self, util):
1007
+ data = [
1008
+ {"a": datetime(2019, 7, 11, 9, 0), "b": 2.5},
1009
+ {"a": datetime(2019, 7, 11, 9, 1), "b": 4.5},
1010
+ ]
1011
+ tbl = Table(data, index="a")
1012
+ view = tbl.view()
1013
+ assert view.to_records(index=True) == [
1014
+ {
1015
+ "__INDEX__": [util.to_timestamp(datetime(2019, 7, 11, 9, 0))],
1016
+ "a": util.to_timestamp(datetime(2019, 7, 11, 9, 0)),
1017
+ "b": 2.5,
1018
+ },
1019
+ {
1020
+ "__INDEX__": [util.to_timestamp(datetime(2019, 7, 11, 9, 1))],
1021
+ "a": util.to_timestamp(datetime(2019, 7, 11, 9, 1)),
1022
+ "b": 4.5,
1023
+ },
1024
+ ]