pixeltable 0.1.1__py3-none-any.whl → 0.2.0__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 +34 -6
- pixeltable/catalog/__init__.py +13 -0
- pixeltable/catalog/catalog.py +159 -0
- pixeltable/catalog/column.py +200 -0
- pixeltable/catalog/dir.py +32 -0
- pixeltable/catalog/globals.py +33 -0
- pixeltable/catalog/insertable_table.py +191 -0
- pixeltable/catalog/named_function.py +36 -0
- pixeltable/catalog/path.py +58 -0
- pixeltable/catalog/path_dict.py +139 -0
- pixeltable/catalog/schema_object.py +39 -0
- pixeltable/catalog/table.py +581 -0
- pixeltable/catalog/table_version.py +749 -0
- pixeltable/catalog/table_version_path.py +133 -0
- pixeltable/catalog/view.py +203 -0
- pixeltable/client.py +520 -30
- pixeltable/dataframe.py +540 -349
- pixeltable/env.py +373 -45
- pixeltable/exceptions.py +12 -21
- pixeltable/exec/__init__.py +9 -0
- pixeltable/exec/aggregation_node.py +78 -0
- pixeltable/exec/cache_prefetch_node.py +113 -0
- pixeltable/exec/component_iteration_node.py +79 -0
- pixeltable/exec/data_row_batch.py +95 -0
- pixeltable/exec/exec_context.py +22 -0
- pixeltable/exec/exec_node.py +61 -0
- pixeltable/exec/expr_eval_node.py +217 -0
- pixeltable/exec/in_memory_data_node.py +69 -0
- pixeltable/exec/media_validation_node.py +43 -0
- pixeltable/exec/sql_scan_node.py +225 -0
- pixeltable/exprs/__init__.py +24 -0
- pixeltable/exprs/arithmetic_expr.py +102 -0
- pixeltable/exprs/array_slice.py +71 -0
- pixeltable/exprs/column_property_ref.py +77 -0
- pixeltable/exprs/column_ref.py +105 -0
- pixeltable/exprs/comparison.py +77 -0
- pixeltable/exprs/compound_predicate.py +98 -0
- pixeltable/exprs/data_row.py +187 -0
- pixeltable/exprs/expr.py +586 -0
- pixeltable/exprs/expr_set.py +39 -0
- pixeltable/exprs/function_call.py +380 -0
- pixeltable/exprs/globals.py +69 -0
- pixeltable/exprs/image_member_access.py +115 -0
- pixeltable/exprs/image_similarity_predicate.py +58 -0
- pixeltable/exprs/inline_array.py +107 -0
- pixeltable/exprs/inline_dict.py +101 -0
- pixeltable/exprs/is_null.py +38 -0
- pixeltable/exprs/json_mapper.py +121 -0
- pixeltable/exprs/json_path.py +159 -0
- pixeltable/exprs/literal.py +54 -0
- pixeltable/exprs/object_ref.py +41 -0
- pixeltable/exprs/predicate.py +44 -0
- pixeltable/exprs/row_builder.py +355 -0
- pixeltable/exprs/rowid_ref.py +94 -0
- pixeltable/exprs/type_cast.py +53 -0
- pixeltable/exprs/variable.py +45 -0
- pixeltable/func/__init__.py +9 -0
- pixeltable/func/aggregate_function.py +194 -0
- pixeltable/func/batched_function.py +53 -0
- pixeltable/func/callable_function.py +69 -0
- pixeltable/func/expr_template_function.py +82 -0
- pixeltable/func/function.py +110 -0
- pixeltable/func/function_registry.py +227 -0
- pixeltable/func/globals.py +36 -0
- pixeltable/func/nos_function.py +202 -0
- pixeltable/func/signature.py +166 -0
- pixeltable/func/udf.py +163 -0
- pixeltable/functions/__init__.py +52 -103
- pixeltable/functions/eval.py +216 -0
- pixeltable/functions/fireworks.py +61 -0
- pixeltable/functions/huggingface.py +120 -0
- pixeltable/functions/image.py +16 -0
- pixeltable/functions/openai.py +88 -0
- pixeltable/functions/pil/image.py +148 -7
- pixeltable/functions/string.py +13 -0
- pixeltable/functions/together.py +27 -0
- pixeltable/functions/util.py +41 -0
- pixeltable/functions/video.py +62 -0
- pixeltable/iterators/__init__.py +3 -0
- pixeltable/iterators/base.py +48 -0
- pixeltable/iterators/document.py +311 -0
- pixeltable/iterators/video.py +89 -0
- pixeltable/metadata/__init__.py +54 -0
- pixeltable/metadata/converters/convert_10.py +18 -0
- pixeltable/metadata/schema.py +211 -0
- pixeltable/plan.py +656 -0
- pixeltable/store.py +413 -182
- pixeltable/tests/conftest.py +143 -87
- pixeltable/tests/test_audio.py +65 -0
- pixeltable/tests/test_catalog.py +27 -0
- pixeltable/tests/test_client.py +14 -14
- pixeltable/tests/test_component_view.py +372 -0
- pixeltable/tests/test_dataframe.py +433 -0
- pixeltable/tests/test_dirs.py +78 -62
- pixeltable/tests/test_document.py +117 -0
- pixeltable/tests/test_exprs.py +591 -135
- pixeltable/tests/test_function.py +297 -67
- pixeltable/tests/test_functions.py +283 -1
- pixeltable/tests/test_migration.py +43 -0
- pixeltable/tests/test_nos.py +54 -0
- pixeltable/tests/test_snapshot.py +208 -0
- pixeltable/tests/test_table.py +1085 -262
- pixeltable/tests/test_transactional_directory.py +42 -0
- pixeltable/tests/test_types.py +5 -11
- pixeltable/tests/test_video.py +149 -34
- pixeltable/tests/test_view.py +530 -0
- pixeltable/tests/utils.py +186 -45
- pixeltable/tool/create_test_db_dump.py +149 -0
- pixeltable/type_system.py +490 -126
- pixeltable/utils/__init__.py +17 -46
- pixeltable/utils/clip.py +12 -15
- pixeltable/utils/coco.py +136 -0
- pixeltable/utils/documents.py +39 -0
- pixeltable/utils/filecache.py +195 -0
- pixeltable/utils/help.py +11 -0
- pixeltable/utils/media_store.py +76 -0
- pixeltable/utils/parquet.py +126 -0
- pixeltable/utils/pytorch.py +172 -0
- pixeltable/utils/s3.py +13 -0
- pixeltable/utils/sql.py +17 -0
- pixeltable/utils/transactional_directory.py +35 -0
- pixeltable-0.2.0.dist-info/LICENSE +18 -0
- pixeltable-0.2.0.dist-info/METADATA +117 -0
- pixeltable-0.2.0.dist-info/RECORD +125 -0
- {pixeltable-0.1.1.dist-info → pixeltable-0.2.0.dist-info}/WHEEL +1 -1
- pixeltable/catalog.py +0 -1421
- pixeltable/exprs.py +0 -1745
- pixeltable/function.py +0 -269
- pixeltable/functions/clip.py +0 -10
- pixeltable/functions/pil/__init__.py +0 -23
- pixeltable/functions/tf.py +0 -21
- pixeltable/index.py +0 -57
- pixeltable/tests/test_dict.py +0 -24
- pixeltable/tests/test_tf.py +0 -69
- pixeltable/tf.py +0 -33
- pixeltable/utils/tf.py +0 -33
- pixeltable/utils/video.py +0 -32
- pixeltable-0.1.1.dist-info/METADATA +0 -31
- pixeltable-0.1.1.dist-info/RECORD +0 -36
|
@@ -1,94 +1,324 @@
|
|
|
1
|
+
from typing import Optional
|
|
2
|
+
|
|
1
3
|
import numpy as np
|
|
2
|
-
import pandas as pd
|
|
3
4
|
import pytest
|
|
4
5
|
|
|
5
|
-
|
|
6
|
-
|
|
6
|
+
import pixeltable as pxt
|
|
7
|
+
import pixeltable.exceptions as excs
|
|
7
8
|
from pixeltable import catalog
|
|
8
|
-
|
|
9
|
-
from pixeltable import
|
|
9
|
+
from pixeltable.func import Function, FunctionRegistry, Batch
|
|
10
|
+
from pixeltable.type_system import IntType, FloatType
|
|
11
|
+
from pixeltable.tests.utils import assert_resultset_eq
|
|
12
|
+
import pixeltable.func as func
|
|
10
13
|
|
|
11
14
|
|
|
12
15
|
def dummy_fn(i: int) -> int:
|
|
13
16
|
return i
|
|
14
17
|
|
|
15
18
|
class TestFunction:
|
|
16
|
-
|
|
17
|
-
func
|
|
19
|
+
@pxt.udf(return_type=IntType(), param_types=[IntType()])
|
|
20
|
+
def func(x: int) -> int:
|
|
21
|
+
return x + 1
|
|
22
|
+
|
|
23
|
+
@pxt.uda(name='agg', value_type=IntType(), update_types=[IntType()])
|
|
24
|
+
class Aggregator:
|
|
25
|
+
def __init__(self):
|
|
26
|
+
self.sum = 0
|
|
27
|
+
def update(self, val: int) -> None:
|
|
28
|
+
if val is not None:
|
|
29
|
+
self.sum += val
|
|
30
|
+
def value(self) -> int:
|
|
31
|
+
return self.sum
|
|
18
32
|
|
|
19
|
-
def test_serialize_anonymous(self,
|
|
33
|
+
def test_serialize_anonymous(self, init_env) -> None:
|
|
20
34
|
d = self.func.as_dict()
|
|
21
35
|
FunctionRegistry.get().clear_cache()
|
|
22
36
|
deserialized = Function.from_dict(d)
|
|
23
|
-
|
|
37
|
+
# TODO: add Function.exec() and then use that
|
|
38
|
+
assert deserialized.py_fn(1) == 2
|
|
24
39
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
40
|
+
@pytest.mark.skip(reason='deprecated')
|
|
41
|
+
def test_create(self, test_client: pxt.Client) -> None:
|
|
42
|
+
cl = test_client
|
|
43
|
+
cl.create_function('test_fn', self.func)
|
|
44
|
+
assert self.func.md.fqn == 'test_fn'
|
|
28
45
|
FunctionRegistry.get().clear_cache()
|
|
29
|
-
cl =
|
|
30
|
-
|
|
31
|
-
fn2 =
|
|
32
|
-
assert fn2.
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
46
|
+
cl = pxt.Client(reload=True)
|
|
47
|
+
_ = cl.list_functions()
|
|
48
|
+
fn2 = cl.get_function('test_fn')
|
|
49
|
+
assert fn2.md.fqn == 'test_fn'
|
|
50
|
+
assert fn2.py_fn(1) == 2
|
|
51
|
+
|
|
52
|
+
with pytest.raises(excs.Error):
|
|
53
|
+
cl.create_function('test_fn', self.func)
|
|
54
|
+
with pytest.raises(excs.Error):
|
|
55
|
+
cl.create_function('dir1.test_fn', self.func)
|
|
56
|
+
with pytest.raises(excs.Error):
|
|
57
|
+
library_fn = make_library_function(IntType(), [IntType()], __name__, 'dummy_fn')
|
|
58
|
+
cl.create_function('library_fn', library_fn)
|
|
59
|
+
|
|
60
|
+
@pytest.mark.skip(reason='deprecated')
|
|
61
|
+
def test_update(self, test_client: pxt.Client, test_tbl: catalog.Table) -> None:
|
|
62
|
+
cl = test_client
|
|
63
|
+
t = test_tbl
|
|
64
|
+
cl.create_function('test_fn', self.func)
|
|
65
|
+
res1 = t[self.func(t.c2)].show(0).to_pandas()
|
|
66
|
+
|
|
67
|
+
# load function from db and make sure it computes the same thing as before
|
|
45
68
|
FunctionRegistry.get().clear_cache()
|
|
46
|
-
cl =
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
69
|
+
cl = pxt.Client(reload=True)
|
|
70
|
+
fn = cl.get_function('test_fn')
|
|
71
|
+
res2 = t[fn(t.c2)].show(0).to_pandas()
|
|
72
|
+
assert res1.col_0.equals(res2.col_0)
|
|
73
|
+
fn.py_fn = lambda x: x + 2
|
|
74
|
+
cl.update_function('test_fn', fn)
|
|
75
|
+
assert self.func.md.fqn == fn.md.fqn # fqn doesn't change
|
|
52
76
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
77
|
+
FunctionRegistry.get().clear_cache()
|
|
78
|
+
cl = pxt.Client(reload=True)
|
|
79
|
+
fn = cl.get_function('test_fn')
|
|
80
|
+
assert self.func.md.fqn == fn.md.fqn # fqn doesn't change
|
|
81
|
+
res3 = t[fn(t.c2)].show(0).to_pandas()
|
|
82
|
+
assert (res2.col_0 + 1).equals(res3.col_0)
|
|
83
|
+
|
|
84
|
+
# signature changes
|
|
85
|
+
with pytest.raises(excs.Error):
|
|
86
|
+
cl.update_function('test_fn', make_function(FloatType(), [IntType()], fn.py_fn))
|
|
87
|
+
with pytest.raises(excs.Error):
|
|
88
|
+
cl.update_function('test_fn', make_function(IntType(), [FloatType()], fn.py_fn))
|
|
89
|
+
with pytest.raises(excs.Error):
|
|
90
|
+
cl.update_function('test_fn', self.agg)
|
|
91
|
+
|
|
92
|
+
@pytest.mark.skip(reason='deprecated')
|
|
93
|
+
def test_move(self, test_client: pxt.Client) -> None:
|
|
94
|
+
cl = test_client
|
|
95
|
+
cl.create_function('test_fn', self.func)
|
|
56
96
|
|
|
57
97
|
FunctionRegistry.get().clear_cache()
|
|
58
|
-
cl =
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
func
|
|
64
|
-
assert func.
|
|
98
|
+
cl = pxt.Client(reload=True)
|
|
99
|
+
with pytest.raises(excs.Error):
|
|
100
|
+
cl.move('test_fn2', 'test_fn')
|
|
101
|
+
cl.move('test_fn', 'test_fn2')
|
|
102
|
+
func = cl.get_function('test_fn2')
|
|
103
|
+
assert func.py_fn(1) == 2
|
|
104
|
+
assert func.md.fqn == 'test_fn2'
|
|
65
105
|
|
|
66
|
-
with pytest.raises(
|
|
67
|
-
_ =
|
|
106
|
+
with pytest.raises(excs.Error):
|
|
107
|
+
_ = cl.get_function('test_fn')
|
|
68
108
|
|
|
69
109
|
# move function between directories
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
with pytest.raises(
|
|
74
|
-
|
|
75
|
-
|
|
110
|
+
cl.create_dir('functions')
|
|
111
|
+
cl.create_dir('functions2')
|
|
112
|
+
cl.create_function('functions.func1', self.func)
|
|
113
|
+
with pytest.raises(excs.Error):
|
|
114
|
+
cl.move('functions2.func1', 'functions.func1')
|
|
115
|
+
cl.move('functions.func1', 'functions2.func1')
|
|
116
|
+
func = cl.get_function('functions2.func1')
|
|
117
|
+
assert func.md.fqn == 'functions2.func1'
|
|
118
|
+
|
|
76
119
|
|
|
77
120
|
FunctionRegistry.get().clear_cache()
|
|
78
|
-
cl =
|
|
79
|
-
|
|
80
|
-
func
|
|
81
|
-
assert func.
|
|
82
|
-
with pytest.raises(
|
|
83
|
-
_ =
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
121
|
+
cl = pxt.Client(reload=True)
|
|
122
|
+
func = cl.get_function('functions2.func1')
|
|
123
|
+
assert func.py_fn(1) == 2
|
|
124
|
+
assert func.md.fqn == 'functions2.func1'
|
|
125
|
+
with pytest.raises(excs.Error):
|
|
126
|
+
_ = cl.get_function('functions.func1')
|
|
127
|
+
|
|
128
|
+
@pytest.mark.skip(reason='deprecated')
|
|
129
|
+
def test_drop(self, test_client: pxt.Client) -> None:
|
|
130
|
+
cl = test_client
|
|
131
|
+
cl.create_function('test_fn', self.func)
|
|
88
132
|
FunctionRegistry.get().clear_cache()
|
|
89
|
-
cl =
|
|
90
|
-
|
|
91
|
-
|
|
133
|
+
cl = pxt.Client(reload=True)
|
|
134
|
+
cl.drop_function('test_fn')
|
|
135
|
+
|
|
136
|
+
with pytest.raises(excs.Error):
|
|
137
|
+
_ = cl.get_function('test_fn')
|
|
138
|
+
|
|
139
|
+
def test_list(self, test_client: pxt.Client) -> None:
|
|
140
|
+
_ = FunctionRegistry.get().list_functions()
|
|
141
|
+
print(_)
|
|
142
|
+
|
|
143
|
+
def test_stored_udf(self, test_client: pxt.Client) -> None:
|
|
144
|
+
cl = test_client
|
|
145
|
+
t = cl.create_table('test', {'c1': pxt.IntType(), 'c2': pxt.FloatType()})
|
|
146
|
+
rows = [{'c1': i, 'c2': i + 0.5} for i in range(100)]
|
|
147
|
+
status = t.insert(rows)
|
|
148
|
+
assert status.num_rows == len(rows)
|
|
149
|
+
assert status.num_excs == 0
|
|
150
|
+
|
|
151
|
+
@pxt.udf(_force_stored=True)
|
|
152
|
+
def f1(a: int, b: float) -> float:
|
|
153
|
+
return a + b
|
|
154
|
+
t['f1'] = f1(t.c1, t.c2)
|
|
155
|
+
|
|
156
|
+
func.FunctionRegistry.get().clear_cache()
|
|
157
|
+
cl = pxt.Client(reload=True)
|
|
158
|
+
t = cl.get_table('test')
|
|
159
|
+
status = t.insert(rows)
|
|
160
|
+
assert status.num_rows == len(rows)
|
|
161
|
+
assert status.num_excs == 0
|
|
162
|
+
|
|
163
|
+
def test_call(self, test_tbl: catalog.Table) -> None:
|
|
164
|
+
t = test_tbl
|
|
165
|
+
|
|
166
|
+
@pxt.udf(return_type=IntType(), param_types=[IntType(), FloatType(), FloatType(), FloatType()])
|
|
167
|
+
def f1(a: int, b: float, c: float = 0.0, d: float = 1.0) -> float:
|
|
168
|
+
return a + b + c + d
|
|
169
|
+
|
|
170
|
+
r0 = t[t.c2, t.c3].show(0).to_pandas()
|
|
171
|
+
# positional params with default args
|
|
172
|
+
r1 = t[f1(t.c2, t.c3)].show(0).to_pandas()['col_0']
|
|
173
|
+
assert np.all(r1 == r0.c2 + r0.c3 + 1.0)
|
|
174
|
+
# kw args only
|
|
175
|
+
r2 = t[f1(c=0.0, b=t.c3, a=t.c2)].show(0).to_pandas()['col_0']
|
|
176
|
+
assert np.all(r1 == r2)
|
|
177
|
+
# overriding default args
|
|
178
|
+
r3 = t[f1(d=0.0, c=1.0, b=t.c3, a=t.c2)].show(0).to_pandas()['col_0']
|
|
179
|
+
assert np.all(r2 == r3)
|
|
180
|
+
# overriding default with positional arg
|
|
181
|
+
r4 = t[f1(t.c2, t.c3, 0.0)].show(0).to_pandas()['col_0']
|
|
182
|
+
assert np.all(r3 == r4)
|
|
183
|
+
# overriding default with positional arg and kw arg
|
|
184
|
+
r5 = t[f1(t.c2, t.c3, 1.0, d=0.0)].show(0).to_pandas()['col_0']
|
|
185
|
+
assert np.all(r4 == r5)
|
|
186
|
+
# d is kwarg
|
|
187
|
+
r6 = t[f1(t.c2, d=1.0, b=t.c3)].show(0).to_pandas()['col_0']
|
|
188
|
+
assert np.all(r5 == r6)
|
|
189
|
+
# d is Expr kwarg
|
|
190
|
+
r6 = t[f1(1, d=t.c3, b=t.c3)].show(0).to_pandas()['col_0']
|
|
191
|
+
assert np.all(r5 == r6)
|
|
192
|
+
|
|
193
|
+
# test handling of Nones
|
|
194
|
+
@pxt.udf(
|
|
195
|
+
return_type=IntType(),
|
|
196
|
+
param_types=[IntType(nullable=True), FloatType(nullable=False), FloatType(nullable=True)])
|
|
197
|
+
def f2(a: int, b: float = 0.0, c: float = 1.0) -> float:
|
|
198
|
+
return (0.0 if a is None else a) + b + (0.0 if c is None else c)
|
|
199
|
+
r0 = t[f2(1, t.c3)].show(0).to_pandas()['col_0']
|
|
200
|
+
r1 = t[f2(None, t.c3, 2.0)].show(0).to_pandas()['col_0']
|
|
201
|
+
assert np.all(r0 == r1)
|
|
202
|
+
r2 = t[f2(2, t.c3, None)].show(0).to_pandas()['col_0']
|
|
203
|
+
assert np.all(r1 == r2)
|
|
204
|
+
# kwarg with None
|
|
205
|
+
r3 = t[f2(c=None, a=t.c2)].show(0).to_pandas()['col_0']
|
|
206
|
+
# kwarg with Expr
|
|
207
|
+
r4 = t[f2(c=t.c3, a=None)].show(0).to_pandas()['col_0']
|
|
208
|
+
assert np.all(r3 == r4)
|
|
209
|
+
|
|
210
|
+
with pytest.raises(TypeError) as exc_info:
|
|
211
|
+
_ = t[f1(t.c2, c=0.0)].show(0)
|
|
212
|
+
assert "'b'" in str(exc_info.value)
|
|
213
|
+
with pytest.raises(TypeError) as exc_info:
|
|
214
|
+
_ = t[f1(t.c2)].show(0)
|
|
215
|
+
assert "'b'" in str(exc_info.value)
|
|
216
|
+
with pytest.raises(TypeError) as exc_info:
|
|
217
|
+
_ = t[f1(c=1.0, a=t.c2)].show(0)
|
|
218
|
+
assert "'b'" in str(exc_info.value)
|
|
219
|
+
|
|
220
|
+
# bad default value
|
|
221
|
+
with pytest.raises(excs.Error) as exc_info:
|
|
222
|
+
@pxt.udf(return_type=IntType(), param_types=[IntType(), FloatType(), FloatType()])
|
|
223
|
+
def f1(a: int, b: float, c: str = '') -> float:
|
|
224
|
+
return a + b + c
|
|
225
|
+
assert 'default value' in str(exc_info.value).lower()
|
|
226
|
+
# missing param type
|
|
227
|
+
with pytest.raises(excs.Error) as exc_info:
|
|
228
|
+
@pxt.udf(return_type=IntType(), param_types=[IntType(), FloatType()])
|
|
229
|
+
def f1(a: int, b: float, c: str = '') -> float:
|
|
230
|
+
return a + b + c
|
|
231
|
+
assert 'missing type for parameter c' in str(exc_info.value).lower()
|
|
232
|
+
# bad parameter name
|
|
233
|
+
with pytest.raises(excs.Error) as exc_info:
|
|
234
|
+
@pxt.udf(return_type=IntType(), param_types=[IntType()])
|
|
235
|
+
def f1(group_by: int) -> int:
|
|
236
|
+
return group_by
|
|
237
|
+
assert 'reserved' in str(exc_info.value)
|
|
238
|
+
# bad parameter name
|
|
239
|
+
with pytest.raises(excs.Error) as exc_info:
|
|
240
|
+
@pxt.udf(return_type=IntType(), param_types=[IntType()])
|
|
241
|
+
def f1(order_by: int) -> int:
|
|
242
|
+
return order_by
|
|
243
|
+
assert 'reserved' in str(exc_info.value)
|
|
244
|
+
|
|
245
|
+
def test_expr_udf(self, test_tbl: catalog.Table) -> None:
|
|
246
|
+
t = test_tbl
|
|
247
|
+
@pxt.expr_udf
|
|
248
|
+
def times2(x: int) -> int:
|
|
249
|
+
return x + x
|
|
250
|
+
res1 = t.select(out=times2(t.c2)).order_by(t.c2).collect()
|
|
251
|
+
res2 = t.select(t.c2 * 2).order_by(t.c2).collect()
|
|
252
|
+
assert_resultset_eq(res1, res2)
|
|
253
|
+
|
|
254
|
+
with pytest.raises(TypeError) as exc_info:
|
|
255
|
+
_ = t.select(times2(y=t.c2)).collect()
|
|
256
|
+
assert 'missing a required argument' in str(exc_info.value).lower()
|
|
257
|
+
|
|
258
|
+
with pytest.raises(excs.Error) as exc_info:
|
|
259
|
+
# parameter types cannot be inferred
|
|
260
|
+
@pxt.expr_udf
|
|
261
|
+
def add1(x, y) -> int:
|
|
262
|
+
return x + y
|
|
263
|
+
assert 'cannot infer pixeltable type' in str(exc_info.value).lower()
|
|
264
|
+
|
|
265
|
+
with pytest.raises(excs.Error) as exc_info:
|
|
266
|
+
# return type cannot be inferred
|
|
267
|
+
@pxt.expr_udf
|
|
268
|
+
def add1(x: int, y: int):
|
|
269
|
+
return x + y
|
|
270
|
+
assert 'cannot infer pixeltable return type' in str(exc_info.value).lower()
|
|
271
|
+
|
|
272
|
+
with pytest.raises(excs.Error) as exc_info:
|
|
273
|
+
# missing param types
|
|
274
|
+
@pxt.expr_udf(param_types=[IntType()])
|
|
275
|
+
def add1(x, y) -> int:
|
|
276
|
+
return x + y
|
|
277
|
+
assert 'missing type for parameter y' in str(exc_info.value).lower()
|
|
278
|
+
|
|
279
|
+
with pytest.raises(TypeError) as exc_info:
|
|
280
|
+
# signature has correct parameter kind
|
|
281
|
+
@pxt.expr_udf
|
|
282
|
+
def add1(*, x: int) -> int:
|
|
283
|
+
return x + 1
|
|
284
|
+
_ = t.select(add1(t.c2)).collect()
|
|
285
|
+
assert 'takes 0 positional arguments' in str(exc_info.value).lower()
|
|
286
|
+
|
|
287
|
+
@pxt.expr_udf
|
|
288
|
+
def add2(x: int, y: int = 1) -> int:
|
|
289
|
+
return x + y
|
|
290
|
+
res1 = t.select(out=add2(t.c2)).order_by(t.c2).collect()
|
|
291
|
+
|
|
292
|
+
# Test that various invalid udf definitions generate
|
|
293
|
+
# correct error messages.
|
|
294
|
+
def test_invalid_udfs(self):
|
|
295
|
+
with pytest.raises(excs.Error) as exc_info:
|
|
296
|
+
@pxt.udf
|
|
297
|
+
def udf1(name: Batch[str]) -> str:
|
|
298
|
+
return ''
|
|
299
|
+
assert 'batched parameters in udf, but no `batch_size` given' in str(exc_info.value).lower()
|
|
300
|
+
|
|
301
|
+
with pytest.raises(excs.Error) as exc_info:
|
|
302
|
+
@pxt.udf(batch_size=32)
|
|
303
|
+
def udf2(name: Batch[str]) -> str:
|
|
304
|
+
return ''
|
|
305
|
+
assert 'batch_size is specified; Python return type must be a `Batch`' in str(exc_info.value)
|
|
306
|
+
|
|
307
|
+
with pytest.raises(excs.Error) as exc_info:
|
|
308
|
+
@pxt.udf
|
|
309
|
+
def udf3(name: str) -> Optional[np.ndarray]:
|
|
310
|
+
return None
|
|
311
|
+
assert 'cannot infer pixeltable return type' in str(exc_info.value).lower()
|
|
312
|
+
|
|
313
|
+
with pytest.raises(excs.Error) as exc_info:
|
|
314
|
+
@pxt.udf
|
|
315
|
+
def udf4(array: np.ndarray) -> str:
|
|
316
|
+
return ''
|
|
317
|
+
assert 'cannot infer pixeltable type for parameter array' in str(exc_info.value).lower()
|
|
318
|
+
|
|
319
|
+
with pytest.raises(excs.Error) as exc_info:
|
|
320
|
+
@pxt.udf
|
|
321
|
+
def udf5(name: str, untyped) -> str:
|
|
322
|
+
return ''
|
|
323
|
+
assert 'cannot infer pixeltable type for parameter untyped' in str(exc_info.value).lower()
|
|
92
324
|
|
|
93
|
-
with pytest.raises(exc.UnknownEntityError):
|
|
94
|
-
_ = db2.load_function('test_fn')
|