pixeltable 0.2.5__py3-none-any.whl → 0.2.7__py3-none-any.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.
Potentially problematic release.
This version of pixeltable might be problematic. Click here for more details.
- pixeltable/__init__.py +20 -9
- pixeltable/__version__.py +3 -0
- pixeltable/catalog/column.py +23 -7
- pixeltable/catalog/insertable_table.py +32 -19
- pixeltable/catalog/table.py +210 -20
- pixeltable/catalog/table_version.py +272 -111
- pixeltable/catalog/table_version_path.py +6 -1
- pixeltable/dataframe.py +184 -110
- pixeltable/datatransfer/__init__.py +1 -0
- pixeltable/datatransfer/label_studio.py +526 -0
- pixeltable/datatransfer/remote.py +113 -0
- pixeltable/env.py +213 -79
- pixeltable/exec/__init__.py +2 -1
- pixeltable/exec/data_row_batch.py +6 -7
- pixeltable/exec/expr_eval_node.py +28 -28
- pixeltable/exec/sql_scan_node.py +7 -6
- pixeltable/exprs/__init__.py +4 -3
- pixeltable/exprs/column_ref.py +11 -2
- pixeltable/exprs/comparison.py +39 -1
- pixeltable/exprs/data_row.py +7 -0
- pixeltable/exprs/expr.py +26 -19
- pixeltable/exprs/function_call.py +17 -18
- pixeltable/exprs/globals.py +14 -2
- pixeltable/exprs/image_member_access.py +9 -28
- pixeltable/exprs/in_predicate.py +96 -0
- pixeltable/exprs/inline_array.py +13 -11
- pixeltable/exprs/inline_dict.py +15 -13
- pixeltable/exprs/row_builder.py +7 -1
- pixeltable/exprs/similarity_expr.py +67 -0
- pixeltable/ext/functions/whisperx.py +30 -0
- pixeltable/ext/functions/yolox.py +16 -0
- pixeltable/func/__init__.py +0 -2
- pixeltable/func/aggregate_function.py +5 -2
- pixeltable/func/callable_function.py +57 -13
- pixeltable/func/expr_template_function.py +14 -3
- pixeltable/func/function.py +35 -4
- pixeltable/func/signature.py +5 -15
- pixeltable/func/udf.py +8 -12
- pixeltable/functions/fireworks.py +9 -4
- pixeltable/functions/huggingface.py +48 -5
- pixeltable/functions/openai.py +49 -11
- pixeltable/functions/pil/image.py +61 -64
- pixeltable/functions/together.py +32 -6
- pixeltable/functions/util.py +0 -43
- pixeltable/functions/video.py +46 -8
- pixeltable/globals.py +443 -0
- pixeltable/index/__init__.py +1 -0
- pixeltable/index/base.py +9 -2
- pixeltable/index/btree.py +54 -0
- pixeltable/index/embedding_index.py +91 -15
- pixeltable/io/__init__.py +4 -0
- pixeltable/io/globals.py +59 -0
- pixeltable/{utils → io}/hf_datasets.py +48 -17
- pixeltable/io/pandas.py +148 -0
- pixeltable/{utils → io}/parquet.py +58 -33
- pixeltable/iterators/__init__.py +1 -1
- pixeltable/iterators/base.py +8 -4
- pixeltable/iterators/document.py +225 -93
- pixeltable/iterators/video.py +16 -9
- pixeltable/metadata/__init__.py +8 -4
- pixeltable/metadata/converters/convert_12.py +3 -0
- pixeltable/metadata/converters/convert_13.py +41 -0
- pixeltable/metadata/converters/convert_14.py +13 -0
- pixeltable/metadata/converters/convert_15.py +29 -0
- pixeltable/metadata/converters/util.py +63 -0
- pixeltable/metadata/schema.py +12 -6
- pixeltable/plan.py +11 -24
- pixeltable/store.py +16 -23
- pixeltable/tool/create_test_db_dump.py +49 -14
- pixeltable/type_system.py +27 -58
- pixeltable/utils/coco.py +94 -0
- pixeltable/utils/documents.py +42 -12
- pixeltable/utils/http_server.py +70 -0
- pixeltable-0.2.7.dist-info/METADATA +137 -0
- pixeltable-0.2.7.dist-info/RECORD +126 -0
- {pixeltable-0.2.5.dist-info → pixeltable-0.2.7.dist-info}/WHEEL +1 -1
- pixeltable/client.py +0 -600
- pixeltable/exprs/image_similarity_predicate.py +0 -58
- pixeltable/func/batched_function.py +0 -53
- pixeltable/func/nos_function.py +0 -202
- pixeltable/tests/conftest.py +0 -171
- pixeltable/tests/ext/test_yolox.py +0 -21
- pixeltable/tests/functions/test_fireworks.py +0 -43
- pixeltable/tests/functions/test_functions.py +0 -60
- pixeltable/tests/functions/test_huggingface.py +0 -158
- pixeltable/tests/functions/test_openai.py +0 -162
- pixeltable/tests/functions/test_together.py +0 -112
- pixeltable/tests/test_audio.py +0 -65
- pixeltable/tests/test_catalog.py +0 -27
- pixeltable/tests/test_client.py +0 -21
- pixeltable/tests/test_component_view.py +0 -379
- pixeltable/tests/test_dataframe.py +0 -440
- pixeltable/tests/test_dirs.py +0 -107
- pixeltable/tests/test_document.py +0 -120
- pixeltable/tests/test_exprs.py +0 -802
- pixeltable/tests/test_function.py +0 -332
- pixeltable/tests/test_index.py +0 -138
- pixeltable/tests/test_migration.py +0 -44
- pixeltable/tests/test_nos.py +0 -54
- pixeltable/tests/test_snapshot.py +0 -231
- pixeltable/tests/test_table.py +0 -1343
- pixeltable/tests/test_transactional_directory.py +0 -42
- pixeltable/tests/test_types.py +0 -52
- pixeltable/tests/test_video.py +0 -159
- pixeltable/tests/test_view.py +0 -535
- pixeltable/tests/utils.py +0 -442
- pixeltable/utils/clip.py +0 -18
- pixeltable-0.2.5.dist-info/METADATA +0 -128
- pixeltable-0.2.5.dist-info/RECORD +0 -139
- {pixeltable-0.2.5.dist-info → pixeltable-0.2.7.dist-info}/LICENSE +0 -0
pixeltable/tests/test_view.py
DELETED
|
@@ -1,535 +0,0 @@
|
|
|
1
|
-
import datetime
|
|
2
|
-
import logging
|
|
3
|
-
|
|
4
|
-
import PIL
|
|
5
|
-
import pytest
|
|
6
|
-
|
|
7
|
-
import pixeltable as pxt
|
|
8
|
-
from pixeltable import catalog
|
|
9
|
-
from pixeltable import exceptions as excs
|
|
10
|
-
from pixeltable.tests.utils import create_test_tbl, assert_resultset_eq
|
|
11
|
-
from pixeltable.type_system import IntType, FloatType, ImageType
|
|
12
|
-
|
|
13
|
-
logger = logging.getLogger('pixeltable')
|
|
14
|
-
|
|
15
|
-
class TestView:
|
|
16
|
-
"""
|
|
17
|
-
TODO:
|
|
18
|
-
- test tree of views
|
|
19
|
-
- test consecutive component views
|
|
20
|
-
|
|
21
|
-
"""
|
|
22
|
-
def create_tbl(self, cl: pxt.Client) -> catalog.InsertableTable:
|
|
23
|
-
"""Create table with computed columns"""
|
|
24
|
-
t = create_test_tbl(cl)
|
|
25
|
-
t.add_column(d1=t.c3 - 1)
|
|
26
|
-
# add column that can be updated
|
|
27
|
-
t.add_column(c10=FloatType(nullable=True))
|
|
28
|
-
t.update({'c10': t.c3})
|
|
29
|
-
# computed column that depends on two columns: exercise duplicate elimination during query construction
|
|
30
|
-
t.add_column(d2=t.c3 - t.c10)
|
|
31
|
-
return t
|
|
32
|
-
|
|
33
|
-
def test_basic(self, test_client: pxt.Client) -> None:
|
|
34
|
-
cl = test_client
|
|
35
|
-
t = self.create_tbl(cl)
|
|
36
|
-
|
|
37
|
-
# create view with filter and computed columns
|
|
38
|
-
schema = {
|
|
39
|
-
'v1': t.c3 * 2.0,
|
|
40
|
-
'v2': t.c6.f5,
|
|
41
|
-
}
|
|
42
|
-
v = cl.create_view('test_view', t, schema=schema, filter=t.c2 < 10)
|
|
43
|
-
# TODO: test repr more thoroughly
|
|
44
|
-
_ = v.__repr__()
|
|
45
|
-
assert_resultset_eq(
|
|
46
|
-
v.select(v.v1).order_by(v.c2).collect(),
|
|
47
|
-
t.select(t.c3 * 2.0).where(t.c2 < 10).order_by(t.c2).collect())
|
|
48
|
-
# view-only query; returns the same result
|
|
49
|
-
assert_resultset_eq(
|
|
50
|
-
v.select(v.v1).order_by(v.v1).collect(),
|
|
51
|
-
t.select(t.c3 * 2.0).where(t.c2 < 10).order_by(t.c2).collect())
|
|
52
|
-
# computed columns that don't reference the base table
|
|
53
|
-
v.add_column(v3=v.v1 * 2.0)
|
|
54
|
-
v.add_column(v4=v.v2[0])
|
|
55
|
-
|
|
56
|
-
def check_view(t: pxt.Table, v: pxt.Table) -> None:
|
|
57
|
-
assert v.count() == t.where(t.c2 < 10).count()
|
|
58
|
-
assert_resultset_eq(
|
|
59
|
-
v.select(v.v1).order_by(v.c2).collect(),
|
|
60
|
-
t.select(t.c3 * 2.0).where(t.c2 < 10).order_by(t.c2).collect())
|
|
61
|
-
assert_resultset_eq(
|
|
62
|
-
v.select(v.v3).order_by(v.c2).collect(),
|
|
63
|
-
t.select(t.c3 * 4.0).where(t.c2 < 10).order_by(t.c2).collect())
|
|
64
|
-
assert_resultset_eq(
|
|
65
|
-
v.select(v.v4).order_by(v.c2).collect(),
|
|
66
|
-
t.select(t.c6.f5[0]).where(t.c2 < 10).order_by(t.c2).collect())
|
|
67
|
-
check_view(t, v)
|
|
68
|
-
|
|
69
|
-
# check view md after reload
|
|
70
|
-
cl = pxt.Client(reload=True)
|
|
71
|
-
t = cl.get_table('test_tbl')
|
|
72
|
-
v = cl.get_table('test_view')
|
|
73
|
-
check_view(t, v)
|
|
74
|
-
|
|
75
|
-
view_query = v.select(v.v1).order_by(v.c2)
|
|
76
|
-
base_query = t.select(t.c3 * 2.0).where(t.c2 < 10).order_by(t.c2)
|
|
77
|
-
|
|
78
|
-
# insert data: of 20 new rows, only 10 are reflected in the view
|
|
79
|
-
rows = list(t.select(t.c1, t.c1n, t.c2, t.c3, t.c4, t.c5, t.c6, t.c7, t.c10).where(t.c2 < 20).collect())
|
|
80
|
-
status = t.insert(rows)
|
|
81
|
-
assert status.num_rows == 30
|
|
82
|
-
assert t.count() == 120
|
|
83
|
-
check_view(t, v)
|
|
84
|
-
|
|
85
|
-
# update data: cascade to view
|
|
86
|
-
status = t.update({'c4': True, 'c3': t.c3 + 1.0, 'c10': t.c10 - 1.0}, where=t.c2 < 5, cascade=True)
|
|
87
|
-
assert status.num_rows == 10 * 2 # *2: rows affected in both base table and view
|
|
88
|
-
assert t.count() == 120
|
|
89
|
-
check_view(t, v)
|
|
90
|
-
|
|
91
|
-
# base table delete is reflected in view
|
|
92
|
-
status = t.delete(where=t.c2 < 5)
|
|
93
|
-
status.num_rows == 10 * 2 # *2: rows affected in both base table and view
|
|
94
|
-
assert t.count() == 110
|
|
95
|
-
check_view(t, v)
|
|
96
|
-
|
|
97
|
-
# test delete view
|
|
98
|
-
cl.drop_table('test_view')
|
|
99
|
-
with pytest.raises(excs.Error) as exc_info:
|
|
100
|
-
_ = cl.get_table('test_view')
|
|
101
|
-
assert 'No such path:' in str(exc_info.value)
|
|
102
|
-
cl = pxt.Client(reload=True)
|
|
103
|
-
# still true after reload
|
|
104
|
-
with pytest.raises(excs.Error) as exc_info:
|
|
105
|
-
_ = cl.get_table('test_view')
|
|
106
|
-
assert 'No such path:' in str(exc_info.value)
|
|
107
|
-
|
|
108
|
-
t = cl.get_table('test_tbl')
|
|
109
|
-
with pytest.raises(excs.Error) as exc_info:
|
|
110
|
-
_ = cl.create_view('lambda_view', t, schema={'v1': lambda c3: c3 * 2.0})
|
|
111
|
-
assert 'computed with a callable' in str(exc_info.value).lower()
|
|
112
|
-
|
|
113
|
-
def test_parallel_views(self, test_client: pxt.Client) -> None:
|
|
114
|
-
"""Two views over the same base table, with non-overlapping filters"""
|
|
115
|
-
cl = test_client
|
|
116
|
-
t = self.create_tbl(cl)
|
|
117
|
-
|
|
118
|
-
# create view with filter and computed columns
|
|
119
|
-
v1 = cl.create_view('v1', t, schema={'v1': t.c3 * 2}, filter=t.c2 < 10)
|
|
120
|
-
# create another view with a non-overlapping filter and computed columns
|
|
121
|
-
v2 = cl.create_view('v2', t, schema={'v1': t.c3 * 3}, filter=(t.c2 < 20) & (t.c2 >= 10))
|
|
122
|
-
|
|
123
|
-
# sanity checks
|
|
124
|
-
v1_query = v1.select(v1.v1).order_by(v1.c2)
|
|
125
|
-
v2_query = v2.select(v2.v1).order_by(v2.c2)
|
|
126
|
-
b1_query = t.select(t.c3 * 2).where(t.c2 < 10).order_by(t.c2)
|
|
127
|
-
b2_query = t.select(t.c3 * 3).where((t.c2 >= 10) & (t.c2 < 20)).order_by(t.c2)
|
|
128
|
-
assert_resultset_eq(v1_query.collect(), b1_query.collect())
|
|
129
|
-
assert_resultset_eq(v2_query.collect(), b2_query.collect())
|
|
130
|
-
|
|
131
|
-
# insert data: of 20 new rows, only 10 show up in each view
|
|
132
|
-
rows = list(t.select(t.c1, t.c1n, t.c2, t.c3, t.c4, t.c5, t.c6, t.c7, t.c10).where(t.c2 < 20).collect())
|
|
133
|
-
status = t.insert(rows)
|
|
134
|
-
assert status.num_rows == 40
|
|
135
|
-
assert t.count() == 120
|
|
136
|
-
assert v1.count() == 20
|
|
137
|
-
assert v2.count() == 20
|
|
138
|
-
assert_resultset_eq(v1_query.collect(), b1_query.collect())
|
|
139
|
-
assert_resultset_eq(v2_query.collect(), b2_query.collect())
|
|
140
|
-
|
|
141
|
-
# update data: cascade to views
|
|
142
|
-
status = t.update(
|
|
143
|
-
{'c4': True, 'c3': t.c3 + 1, 'c10': t.c10 - 1.0}, where=(t.c2 >= 5) & (t.c2 < 15), cascade=True)
|
|
144
|
-
assert status.num_rows == 20 * 2 # *2: rows affected in both base table and view
|
|
145
|
-
assert t.count() == 120
|
|
146
|
-
assert v1.count() == 20
|
|
147
|
-
assert v2.count() == 20
|
|
148
|
-
assert_resultset_eq(v1_query.collect(), b1_query.collect())
|
|
149
|
-
assert_resultset_eq(v2_query.collect(), b2_query.collect())
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
# base table delete is reflected in view
|
|
153
|
-
status = t.delete(where=(t.c2 >= 5) & (t.c2 < 15))
|
|
154
|
-
status.num_rows == 10 * 2 # *2: rows affected in both base table and view
|
|
155
|
-
assert t.count() == 100
|
|
156
|
-
assert v1.count() == 10
|
|
157
|
-
assert v2.count() == 10
|
|
158
|
-
assert_resultset_eq(v1_query.collect(), b1_query.collect())
|
|
159
|
-
assert_resultset_eq(v2_query.collect(), b2_query.collect())
|
|
160
|
-
|
|
161
|
-
def test_chained_views(self, test_client: pxt.Client) -> None:
|
|
162
|
-
"""Two views, the second one is a view over the first one"""
|
|
163
|
-
cl = test_client
|
|
164
|
-
t = self.create_tbl(cl)
|
|
165
|
-
|
|
166
|
-
# create view with filter and computed columns
|
|
167
|
-
v1 = cl.create_view('v1', t, schema={'col1': t.c3 * 2}, filter=t.c2 < 10)
|
|
168
|
-
# create a view on top of v1
|
|
169
|
-
v2_schema = {
|
|
170
|
-
'col2': t.c3 * 3, # only base
|
|
171
|
-
'col3': v1.col1 / 2, # only v1
|
|
172
|
-
'col4': t.c10 + v1.col1, # both base and v1
|
|
173
|
-
}
|
|
174
|
-
v2 = cl.create_view('v2', v1, schema=v2_schema, filter=t.c2 < 5)
|
|
175
|
-
|
|
176
|
-
def check_views():
|
|
177
|
-
assert_resultset_eq(
|
|
178
|
-
v1.select(v1.col1).order_by(v1.c2).collect(),
|
|
179
|
-
t.select(t.c3 * 2).where(t.c2 < 10).order_by(t.c2).collect())
|
|
180
|
-
assert_resultset_eq(
|
|
181
|
-
v2.select(v2.col1).order_by(v2.c2).collect(),
|
|
182
|
-
v1.select(v1.col1).where(v1.c2 < 5).order_by(v1.c2).collect())
|
|
183
|
-
assert_resultset_eq(
|
|
184
|
-
v2.select(v2.col2).order_by(v2.c2).collect(),
|
|
185
|
-
t.select(t.c3 * 3).where(t.c2 < 5).order_by(t.c2).collect())
|
|
186
|
-
assert_resultset_eq(
|
|
187
|
-
v2.select(v2.col3).order_by(v2.c2).collect(),
|
|
188
|
-
v1.select(v1.col1 / 2).where(v1.c2 < 5).order_by(v2.c2).collect())
|
|
189
|
-
assert_resultset_eq(
|
|
190
|
-
v2.select(v2.col4).order_by(v2.c2).collect(),
|
|
191
|
-
v1.select(v1.c10 + v1.col1).where(v1.c2 < 5).order_by(v1.c2).collect())
|
|
192
|
-
#t.select(t.c10 * 2).where(t.c2 < 5).order_by(t.c2).collect())
|
|
193
|
-
check_views()
|
|
194
|
-
|
|
195
|
-
# insert data: of 20 new rows; 10 show up in v1, 5 in v2
|
|
196
|
-
base_version, v1_version, v2_version = t.version(), v1.version(), v2.version()
|
|
197
|
-
rows = list(t.select(t.c1, t.c1n, t.c2, t.c3, t.c4, t.c5, t.c6, t.c7, t.c10).where(t.c2 < 20).collect())
|
|
198
|
-
status = t.insert(rows)
|
|
199
|
-
assert status.num_rows == 20 + 10 + 5
|
|
200
|
-
assert t.count() == 120
|
|
201
|
-
assert v1.count() == 20
|
|
202
|
-
assert v2.count() == 10
|
|
203
|
-
# all versions were incremented
|
|
204
|
-
assert t.version() == base_version + 1
|
|
205
|
-
assert v1.version() == v1_version + 1
|
|
206
|
-
assert v2.version() == v2_version + 1
|
|
207
|
-
check_views()
|
|
208
|
-
|
|
209
|
-
# update data: cascade to both views
|
|
210
|
-
base_version, v1_version, v2_version = t.version(), v1.version(), v2.version()
|
|
211
|
-
status = t.update({'c4': True, 'c3': t.c3 + 1}, where=t.c2 < 15, cascade=True)
|
|
212
|
-
assert status.num_rows == 30 + 20 + 10
|
|
213
|
-
assert t.count() == 120
|
|
214
|
-
# all versions were incremented
|
|
215
|
-
assert t.version() == base_version + 1
|
|
216
|
-
assert v1.version() == v1_version + 1
|
|
217
|
-
assert v2.version() == v2_version + 1
|
|
218
|
-
check_views()
|
|
219
|
-
|
|
220
|
-
# update data: cascade only to v2
|
|
221
|
-
base_version, v1_version, v2_version = t.version(), v1.version(), v2.version()
|
|
222
|
-
status = t.update({'c10': t.c10 - 1.0}, where=t.c2 < 15, cascade=True)
|
|
223
|
-
assert status.num_rows == 30 + 10
|
|
224
|
-
assert t.count() == 120
|
|
225
|
-
# v1 did not get updated
|
|
226
|
-
assert t.version() == base_version + 1
|
|
227
|
-
assert v1.version() == v1_version
|
|
228
|
-
assert v2.version() == v2_version + 1
|
|
229
|
-
check_views()
|
|
230
|
-
|
|
231
|
-
# base table delete is reflected in both views
|
|
232
|
-
base_version, v1_version, v2_version = t.version(), v1.version(), v2.version()
|
|
233
|
-
status = t.delete(where=t.c2 == 0)
|
|
234
|
-
status.num_rows == 1 + 1 + 1
|
|
235
|
-
assert t.count() == 118
|
|
236
|
-
assert v1.count() == 18
|
|
237
|
-
assert v2.count() == 8
|
|
238
|
-
# all versions were incremented
|
|
239
|
-
assert t.version() == base_version + 1
|
|
240
|
-
assert v1.version() == v1_version + 1
|
|
241
|
-
assert v2.version() == v2_version + 1
|
|
242
|
-
check_views()
|
|
243
|
-
|
|
244
|
-
# base table delete is reflected only in v1
|
|
245
|
-
base_version, v1_version, v2_version = t.version(), v1.version(), v2.version()
|
|
246
|
-
status = t.delete(where=t.c2 == 5)
|
|
247
|
-
status.num_rows == 1 + 1
|
|
248
|
-
assert t.count() == 116
|
|
249
|
-
assert v1.count() == 16
|
|
250
|
-
assert v2.count() == 8
|
|
251
|
-
# v2 was not updated
|
|
252
|
-
assert t.version() == base_version + 1
|
|
253
|
-
assert v1.version() == v1_version + 1
|
|
254
|
-
assert v2.version() == v2_version
|
|
255
|
-
check_views()
|
|
256
|
-
|
|
257
|
-
def test_unstored_columns(self, test_client: pxt.Client) -> None:
|
|
258
|
-
"""Test chained views with unstored columns"""
|
|
259
|
-
# create table with image column and two updateable int columns
|
|
260
|
-
cl = test_client
|
|
261
|
-
schema = {
|
|
262
|
-
'img': ImageType(),
|
|
263
|
-
'int1': IntType(nullable=False),
|
|
264
|
-
'int2': IntType(nullable=False),
|
|
265
|
-
}
|
|
266
|
-
t = cl.create_table('test_tbl', schema)
|
|
267
|
-
# populate table with images of a defined size
|
|
268
|
-
width, height = 100, 100
|
|
269
|
-
rows = [
|
|
270
|
-
{
|
|
271
|
-
'img': PIL.Image.new('RGB', (width, height), color=(0, 0, 0)).tobytes('jpeg', 'RGB'),
|
|
272
|
-
'int1': i,
|
|
273
|
-
'int2': i,
|
|
274
|
-
}
|
|
275
|
-
for i in range(100)
|
|
276
|
-
]
|
|
277
|
-
t.insert(rows)
|
|
278
|
-
|
|
279
|
-
# view with unstored column that depends on int1 and a manually updated column (int4)
|
|
280
|
-
v1_schema = {
|
|
281
|
-
'img2': {
|
|
282
|
-
'value': t.img.crop([t.int1, t.int1, width, height]),
|
|
283
|
-
'stored': False,
|
|
284
|
-
},
|
|
285
|
-
'int3': t.int1 * 2,
|
|
286
|
-
'int4': IntType(nullable=True), # TODO: add default
|
|
287
|
-
}
|
|
288
|
-
logger.debug('******************* CREATE V1')
|
|
289
|
-
v1 = cl.create_view('v1', t, schema=v1_schema)
|
|
290
|
-
v1.update({'int4': 1})
|
|
291
|
-
_ = v1.select(v1.img2.width, v1.img2.height).collect()
|
|
292
|
-
|
|
293
|
-
# view with stored column that depends on t and view1
|
|
294
|
-
v2_schema = {
|
|
295
|
-
'img3': {
|
|
296
|
-
# use the actual width and height of the image (not 100, which will pad the image)
|
|
297
|
-
'value': v1.img2.crop([t.int1 + t.int2, v1.int3 + v1.int4, v1.img2.width, v1.img2.height]),
|
|
298
|
-
'stored': True,
|
|
299
|
-
},
|
|
300
|
-
}
|
|
301
|
-
logger.debug('******************* CREATE V2')
|
|
302
|
-
v2 = cl.create_view('v2', v1, schema=v2_schema, filter=v1.int1 < 10)
|
|
303
|
-
|
|
304
|
-
def check_views() -> None:
|
|
305
|
-
assert_resultset_eq(
|
|
306
|
-
v1.select(v1.img2.width, v1.img2.height).order_by(v1.int1).collect(),
|
|
307
|
-
t.select(t.img.width - t.int1, t.img.height - t.int1).order_by(t.int1).collect())
|
|
308
|
-
assert_resultset_eq(
|
|
309
|
-
v2.select(v2.img3.width, v2.img3.height).order_by(v2.int1).collect(),
|
|
310
|
-
v1.select(v1.img2.width - v1.int1 - v1.int2, v1.img2.height - v1.int3 - v1.int4)\
|
|
311
|
-
.where(v1.int1 < 10).order_by(v1.int1).collect())
|
|
312
|
-
check_views()
|
|
313
|
-
|
|
314
|
-
logger.debug('******************* INSERT')
|
|
315
|
-
status = t.insert(rows, fail_on_exception=False)
|
|
316
|
-
v1.update({'int4': 1}, where=v1.int4 == None)
|
|
317
|
-
logger.debug('******************* POST INSERT')
|
|
318
|
-
check_views()
|
|
319
|
-
|
|
320
|
-
# update int1:
|
|
321
|
-
# - cascades to v1 and v2
|
|
322
|
-
# - removes a row from v2 (only 9 rows in t now qualify)
|
|
323
|
-
logger.debug('******************* UPDATE INT1')
|
|
324
|
-
t.update({'int1': t.int1 + 1})
|
|
325
|
-
logger.debug('******************* POST UPDATE INT1')
|
|
326
|
-
check_views()
|
|
327
|
-
|
|
328
|
-
# update int2:
|
|
329
|
-
# - cascades only to v2
|
|
330
|
-
# - but requires join against v1 to access int4
|
|
331
|
-
# TODO: but requires join against v1 to access int3 and int4
|
|
332
|
-
logger.debug('******************* UPDATE INT2')
|
|
333
|
-
t.update({'int2': t.int2 + 1})
|
|
334
|
-
logger.debug('******************* POST UPDATE INT2')
|
|
335
|
-
check_views()
|
|
336
|
-
|
|
337
|
-
def test_computed_cols(self, test_client: pxt.Client) -> None:
|
|
338
|
-
cl = test_client
|
|
339
|
-
t = self.create_tbl(cl)
|
|
340
|
-
|
|
341
|
-
# create view with computed columns
|
|
342
|
-
schema = {
|
|
343
|
-
'v1': t.c3 * 2.0,
|
|
344
|
-
'v2': t.c6.f5,
|
|
345
|
-
}
|
|
346
|
-
v = cl.create_view('test_view', t, schema=schema)
|
|
347
|
-
assert_resultset_eq(
|
|
348
|
-
v.select(v.v1).order_by(v.c2).show(0),
|
|
349
|
-
t.select(t.c3 * 2.0).order_by(t.c2).show(0))
|
|
350
|
-
# computed columns that don't reference the base table
|
|
351
|
-
v.add_column(v3=v.v1 * 2.0)
|
|
352
|
-
v.add_column(v4=v.v2[0])
|
|
353
|
-
|
|
354
|
-
# use view md after reload
|
|
355
|
-
cl = pxt.Client(reload=True)
|
|
356
|
-
t = cl.get_table('test_tbl')
|
|
357
|
-
v = cl.get_table('test_view')
|
|
358
|
-
|
|
359
|
-
# insert data
|
|
360
|
-
rows = list(t.select(t.c1, t.c1n, t.c2, t.c3, t.c4, t.c5, t.c6, t.c7, t.c10).collect())
|
|
361
|
-
t.insert(rows)
|
|
362
|
-
assert t.count() == 200
|
|
363
|
-
assert_resultset_eq(
|
|
364
|
-
v.select(v.v1).order_by(v.c2).show(0),
|
|
365
|
-
t.select(t.c3 * 2.0).order_by(t.c2).show(0))
|
|
366
|
-
|
|
367
|
-
# update data: cascade to view
|
|
368
|
-
t.update({'c4': True, 'c3': t.c3 + 1.0, 'c10': t.c10 - 1.0}, where=t.c2 < 5, cascade=True)
|
|
369
|
-
assert t.count() == 200
|
|
370
|
-
assert_resultset_eq(
|
|
371
|
-
v.select(v.v1).order_by(v.c2).show(0),
|
|
372
|
-
t.select(t.c3 * 2.0).order_by(t.c2).show(0))
|
|
373
|
-
|
|
374
|
-
# base table delete is reflected in view
|
|
375
|
-
t.delete(where=t.c2 < 5)
|
|
376
|
-
assert t.count() == 190
|
|
377
|
-
assert_resultset_eq(
|
|
378
|
-
v.select(v.v1).order_by(v.c2).show(0),
|
|
379
|
-
t.select(t.c3 * 2.0).order_by(t.c2).show(0))
|
|
380
|
-
|
|
381
|
-
def test_filter(self, test_client: pxt.Client) -> None:
|
|
382
|
-
cl = test_client
|
|
383
|
-
t = create_test_tbl(cl)
|
|
384
|
-
|
|
385
|
-
# create view with filter
|
|
386
|
-
v = cl.create_view('test_view', t, filter=t.c2 < 10)
|
|
387
|
-
assert_resultset_eq(
|
|
388
|
-
v.order_by(v.c2).show(0),
|
|
389
|
-
t.where(t.c2 < 10).order_by(t.c2).show(0))
|
|
390
|
-
|
|
391
|
-
# use view md after reload
|
|
392
|
-
cl = pxt.Client(reload=True)
|
|
393
|
-
t = cl.get_table('test_tbl')
|
|
394
|
-
v = cl.get_table('test_view')
|
|
395
|
-
|
|
396
|
-
# insert data: of 20 new rows, only 10 are reflected in the view
|
|
397
|
-
rows = list(t.select(t.c1, t.c1n, t.c2, t.c3, t.c4, t.c5, t.c6, t.c7).where(t.c2 < 20).collect())
|
|
398
|
-
t.insert(rows)
|
|
399
|
-
assert t.count() == 120
|
|
400
|
-
assert_resultset_eq(
|
|
401
|
-
v.order_by(v.c2).show(0),
|
|
402
|
-
t.where(t.c2 < 10).order_by(t.c2).show(0))
|
|
403
|
-
|
|
404
|
-
# update data
|
|
405
|
-
t.update({'c4': True, 'c3': t.c3 + 1.0}, where=t.c2 < 5, cascade=True)
|
|
406
|
-
assert t.count() == 120
|
|
407
|
-
assert_resultset_eq(
|
|
408
|
-
v.order_by(v.c2).show(0),
|
|
409
|
-
t.where(t.c2 < 10).order_by(t.c2).show(0))
|
|
410
|
-
|
|
411
|
-
# base table delete is reflected in view
|
|
412
|
-
t.delete(where=t.c2 < 5)
|
|
413
|
-
assert t.count() == 110
|
|
414
|
-
assert_resultset_eq(
|
|
415
|
-
v.order_by(v.c2).show(0),
|
|
416
|
-
t.where(t.c2 < 10).order_by(t.c2).show(0))
|
|
417
|
-
|
|
418
|
-
# create views with filters containing date and datetime
|
|
419
|
-
_ = cl.create_view('test_view_2', t, filter=t.c5 >= datetime.date.today())
|
|
420
|
-
_ = cl.create_view('test_view_3', t, filter=t.c5 < datetime.datetime.now())
|
|
421
|
-
|
|
422
|
-
def test_view_of_snapshot(self, test_client: pxt.Client) -> None:
|
|
423
|
-
"""Test view over a snapshot"""
|
|
424
|
-
cl = test_client
|
|
425
|
-
t = self.create_tbl(cl)
|
|
426
|
-
snap = cl.create_view('test_snap', t, is_snapshot=True)
|
|
427
|
-
|
|
428
|
-
# create view with filter and computed columns
|
|
429
|
-
schema = {
|
|
430
|
-
'v1': snap.c3 * 2.0,
|
|
431
|
-
'v2': snap.c6.f5,
|
|
432
|
-
}
|
|
433
|
-
v = cl.create_view('test_view', snap, schema=schema, filter=snap.c2 < 10)
|
|
434
|
-
|
|
435
|
-
def check_view(s: pxt.Table, v: pxt.Table) -> None:
|
|
436
|
-
assert v.count() == s.where(s.c2 < 10).count()
|
|
437
|
-
assert_resultset_eq(
|
|
438
|
-
v.select(v.v1).order_by(v.c2).collect(),
|
|
439
|
-
s.select(s.c3 * 2.0).where(s.c2 < 10).order_by(s.c2).collect())
|
|
440
|
-
assert_resultset_eq(
|
|
441
|
-
v.select(v.v2).order_by(v.c2).collect(),
|
|
442
|
-
s.select(s.c6.f5).where(s.c2 < 10).order_by(s.c2).collect())
|
|
443
|
-
|
|
444
|
-
check_view(snap, v)
|
|
445
|
-
# computed columns that don't reference the base table
|
|
446
|
-
v.add_column(v3=v.v1 * 2.0)
|
|
447
|
-
v.add_column(v4=v.v2[0])
|
|
448
|
-
assert v.count() == t.where(t.c2 < 10).count()
|
|
449
|
-
|
|
450
|
-
# use view md after reload
|
|
451
|
-
cl = pxt.Client(reload=True)
|
|
452
|
-
t = cl.get_table('test_tbl')
|
|
453
|
-
snap = cl.get_table('test_snap')
|
|
454
|
-
v = cl.get_table('test_view')
|
|
455
|
-
|
|
456
|
-
# insert data: no changes to view
|
|
457
|
-
rows = list(t.select(t.c1, t.c1n, t.c2, t.c3, t.c4, t.c5, t.c6, t.c7, t.c10).where(t.c2 < 20).collect())
|
|
458
|
-
t.insert(rows)
|
|
459
|
-
assert t.count() == 120
|
|
460
|
-
check_view(snap, v)
|
|
461
|
-
|
|
462
|
-
# update data: no changes to view
|
|
463
|
-
t.update({'c4': True, 'c3': t.c3 + 1.0, 'c10': t.c10 - 1.0}, where=t.c2 < 5, cascade=True)
|
|
464
|
-
assert t.count() == 120
|
|
465
|
-
check_view(snap, v)
|
|
466
|
-
|
|
467
|
-
# base table delete: no change to view
|
|
468
|
-
t.delete(where=t.c2 < 5)
|
|
469
|
-
assert t.count() == 110
|
|
470
|
-
check_view(snap, v)
|
|
471
|
-
|
|
472
|
-
def test_snapshots(self, test_client: pxt.Client) -> None:
|
|
473
|
-
"""Test snapshot of a view of a snapshot"""
|
|
474
|
-
cl = test_client
|
|
475
|
-
t = self.create_tbl(cl)
|
|
476
|
-
s = cl.create_view('test_snap', t, is_snapshot=True)
|
|
477
|
-
assert s.select(s.c2).order_by(s.c2).collect()['c2'] == t.select(t.c2).order_by(t.c2).collect()['c2']
|
|
478
|
-
|
|
479
|
-
with pytest.raises(excs.Error) as exc_info:
|
|
480
|
-
v = cl.create_view('test_view', s, schema={'v1': t.c3 * 2.0})
|
|
481
|
-
assert 'value expression cannot be computed in the context of the base test_snap' in str(exc_info.value)
|
|
482
|
-
|
|
483
|
-
with pytest.raises(excs.Error) as exc_info:
|
|
484
|
-
v = cl.create_view('test_view', s, filter=t.c2 < 10)
|
|
485
|
-
assert 'filter cannot be computed in the context of the base test_snap' in str(exc_info.value).lower()
|
|
486
|
-
|
|
487
|
-
# create view with filter and computed columns
|
|
488
|
-
schema = {
|
|
489
|
-
'v1': s.c3 * 2.0,
|
|
490
|
-
'v2': s.c6.f5,
|
|
491
|
-
}
|
|
492
|
-
v = cl.create_view('test_view', s, schema=schema, filter=s.c2 < 10)
|
|
493
|
-
orig_view_cols = v.column_names()
|
|
494
|
-
view_s = cl.create_view('test_view_snap', v, is_snapshot=True)
|
|
495
|
-
assert set(view_s.column_names()) == set(orig_view_cols)
|
|
496
|
-
|
|
497
|
-
def check(s1: pxt.Table, v: pxt.Table, s2: pxt.Table) -> None:
|
|
498
|
-
assert s1.where(s1.c2 < 10).count() == v.count()
|
|
499
|
-
assert v.count() == s2.count()
|
|
500
|
-
assert_resultset_eq(
|
|
501
|
-
s1.select(s1.c3 * 2.0, s1.c6.f5).where(s1.c2 < 10).order_by(s1.c2).collect(),
|
|
502
|
-
v.select(v.v1, v.v2).order_by(v.c2).collect())
|
|
503
|
-
assert_resultset_eq(
|
|
504
|
-
v.select(v.c3, v.c6, v.v1, v.v2).order_by(v.c2).collect(),
|
|
505
|
-
s2.select(s2.c3, s2.c6, s2.v1, s2.v2).order_by(s2.c2).collect())
|
|
506
|
-
check(s, v, view_s)
|
|
507
|
-
|
|
508
|
-
# add more columns
|
|
509
|
-
v.add_column(v3=v.v1 * 2.0)
|
|
510
|
-
v.add_column(v4=v.v2[0])
|
|
511
|
-
check(s, v, view_s)
|
|
512
|
-
assert set(view_s.column_names()) == set(orig_view_cols)
|
|
513
|
-
|
|
514
|
-
# check md after reload
|
|
515
|
-
cl = pxt.Client(reload=True)
|
|
516
|
-
t = cl.get_table('test_tbl')
|
|
517
|
-
view_s = cl.get_table('test_view_snap')
|
|
518
|
-
check(s, v, view_s)
|
|
519
|
-
assert set(view_s.column_names()) == set(orig_view_cols)
|
|
520
|
-
|
|
521
|
-
# insert data: no changes to snapshot
|
|
522
|
-
rows = list(t.select(t.c1, t.c1n, t.c2, t.c3, t.c4, t.c5, t.c6, t.c7, t.c10).where(t.c2 < 20).collect())
|
|
523
|
-
t.insert(rows)
|
|
524
|
-
assert t.count() == 120
|
|
525
|
-
check(s, v, view_s)
|
|
526
|
-
|
|
527
|
-
# update data: no changes to snapshot
|
|
528
|
-
t.update({'c4': True, 'c3': t.c3 + 1.0, 'c10': t.c10 - 1.0}, where=t.c2 < 5, cascade=True)
|
|
529
|
-
assert t.count() == 120
|
|
530
|
-
check(s, v, view_s)
|
|
531
|
-
|
|
532
|
-
# base table delete: no changes to snapshot
|
|
533
|
-
t.delete(where=t.c2 < 5)
|
|
534
|
-
assert t.count() == 110
|
|
535
|
-
check(s, v, view_s)
|