cocoindex 0.1.43__cp311-cp311-macosx_11_0_arm64.whl → 0.1.45__cp311-cp311-macosx_11_0_arm64.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.
- cocoindex/__init__.py +2 -1
- cocoindex/_engine.cpython-311-darwin.so +0 -0
- cocoindex/auth_registry.py +7 -3
- cocoindex/cli.py +186 -67
- cocoindex/convert.py +93 -52
- cocoindex/flow.py +303 -132
- cocoindex/functions.py +17 -4
- cocoindex/index.py +6 -0
- cocoindex/lib.py +14 -9
- cocoindex/llm.py +4 -0
- cocoindex/op.py +126 -61
- cocoindex/query.py +40 -17
- cocoindex/runtime.py +9 -4
- cocoindex/setting.py +35 -12
- cocoindex/setup.py +7 -3
- cocoindex/sources.py +3 -1
- cocoindex/storages.py +50 -7
- cocoindex/tests/test_convert.py +255 -63
- cocoindex/typing.py +116 -70
- cocoindex/utils.py +10 -2
- {cocoindex-0.1.43.dist-info → cocoindex-0.1.45.dist-info}/METADATA +3 -1
- cocoindex-0.1.45.dist-info/RECORD +27 -0
- cocoindex-0.1.43.dist-info/RECORD +0 -27
- {cocoindex-0.1.43.dist-info → cocoindex-0.1.45.dist-info}/WHEEL +0 -0
- {cocoindex-0.1.43.dist-info → cocoindex-0.1.45.dist-info}/entry_points.txt +0 -0
- {cocoindex-0.1.43.dist-info → cocoindex-0.1.45.dist-info}/licenses/LICENSE +0 -0
cocoindex/tests/test_convert.py
CHANGED
@@ -7,6 +7,7 @@ import cocoindex
|
|
7
7
|
from cocoindex.typing import encode_enriched_type
|
8
8
|
from cocoindex.convert import encode_engine_value, make_engine_value_decoder
|
9
9
|
|
10
|
+
|
10
11
|
@dataclass
|
11
12
|
class Order:
|
12
13
|
order_id: str
|
@@ -14,37 +15,44 @@ class Order:
|
|
14
15
|
price: float
|
15
16
|
extra_field: str = "default_extra"
|
16
17
|
|
18
|
+
|
17
19
|
@dataclass
|
18
20
|
class Tag:
|
19
21
|
name: str
|
20
22
|
|
23
|
+
|
21
24
|
@dataclass
|
22
25
|
class Basket:
|
23
26
|
items: list
|
24
27
|
|
28
|
+
|
25
29
|
@dataclass
|
26
30
|
class Customer:
|
27
31
|
name: str
|
28
32
|
order: Order
|
29
33
|
tags: list[Tag] | None = None
|
30
34
|
|
35
|
+
|
31
36
|
@dataclass
|
32
37
|
class NestedStruct:
|
33
38
|
customer: Customer
|
34
39
|
orders: list[Order]
|
35
40
|
count: int = 0
|
36
41
|
|
42
|
+
|
37
43
|
class OrderNamedTuple(NamedTuple):
|
38
44
|
order_id: str
|
39
45
|
name: str
|
40
46
|
price: float
|
41
47
|
extra_field: str = "default_extra"
|
42
48
|
|
49
|
+
|
43
50
|
class CustomerNamedTuple(NamedTuple):
|
44
51
|
name: str
|
45
52
|
order: OrderNamedTuple
|
46
53
|
tags: list[Tag] | None = None
|
47
54
|
|
55
|
+
|
48
56
|
def build_engine_value_decoder(engine_type_in_py, python_type=None):
|
49
57
|
"""
|
50
58
|
Helper to build a converter for the given engine-side type (as represented in Python).
|
@@ -53,16 +61,19 @@ def build_engine_value_decoder(engine_type_in_py, python_type=None):
|
|
53
61
|
engine_type = encode_enriched_type(engine_type_in_py)["type"]
|
54
62
|
return make_engine_value_decoder([], engine_type, python_type or engine_type_in_py)
|
55
63
|
|
64
|
+
|
56
65
|
def test_encode_engine_value_basic_types():
|
57
66
|
assert encode_engine_value(123) == 123
|
58
67
|
assert encode_engine_value(3.14) == 3.14
|
59
68
|
assert encode_engine_value("hello") == "hello"
|
60
69
|
assert encode_engine_value(True) is True
|
61
70
|
|
71
|
+
|
62
72
|
def test_encode_engine_value_uuid():
|
63
73
|
u = uuid.uuid4()
|
64
74
|
assert encode_engine_value(u) == u.bytes
|
65
75
|
|
76
|
+
|
66
77
|
def test_encode_engine_value_date_time_types():
|
67
78
|
d = datetime.date(2024, 1, 1)
|
68
79
|
assert encode_engine_value(d) == d
|
@@ -71,35 +82,65 @@ def test_encode_engine_value_date_time_types():
|
|
71
82
|
dt = datetime.datetime(2024, 1, 1, 12, 30)
|
72
83
|
assert encode_engine_value(dt) == dt
|
73
84
|
|
85
|
+
|
74
86
|
def test_encode_engine_value_struct():
|
75
87
|
order = Order(order_id="O123", name="mixed nuts", price=25.0)
|
76
88
|
assert encode_engine_value(order) == ["O123", "mixed nuts", 25.0, "default_extra"]
|
77
|
-
|
89
|
+
|
78
90
|
order_nt = OrderNamedTuple(order_id="O123", name="mixed nuts", price=25.0)
|
79
|
-
assert encode_engine_value(order_nt) == [
|
91
|
+
assert encode_engine_value(order_nt) == [
|
92
|
+
"O123",
|
93
|
+
"mixed nuts",
|
94
|
+
25.0,
|
95
|
+
"default_extra",
|
96
|
+
]
|
97
|
+
|
80
98
|
|
81
99
|
def test_encode_engine_value_list_of_structs():
|
82
100
|
orders = [Order("O1", "item1", 10.0), Order("O2", "item2", 20.0)]
|
83
|
-
assert encode_engine_value(orders) == [
|
84
|
-
|
85
|
-
|
86
|
-
|
101
|
+
assert encode_engine_value(orders) == [
|
102
|
+
["O1", "item1", 10.0, "default_extra"],
|
103
|
+
["O2", "item2", 20.0, "default_extra"],
|
104
|
+
]
|
105
|
+
|
106
|
+
orders_nt = [
|
107
|
+
OrderNamedTuple("O1", "item1", 10.0),
|
108
|
+
OrderNamedTuple("O2", "item2", 20.0),
|
109
|
+
]
|
110
|
+
assert encode_engine_value(orders_nt) == [
|
111
|
+
["O1", "item1", 10.0, "default_extra"],
|
112
|
+
["O2", "item2", 20.0, "default_extra"],
|
113
|
+
]
|
114
|
+
|
87
115
|
|
88
116
|
def test_encode_engine_value_struct_with_list():
|
89
117
|
basket = Basket(items=["apple", "banana"])
|
90
118
|
assert encode_engine_value(basket) == [["apple", "banana"]]
|
91
119
|
|
120
|
+
|
92
121
|
def test_encode_engine_value_nested_struct():
|
93
122
|
customer = Customer(name="Alice", order=Order("O1", "item1", 10.0))
|
94
|
-
assert encode_engine_value(customer) == [
|
95
|
-
|
96
|
-
|
97
|
-
|
123
|
+
assert encode_engine_value(customer) == [
|
124
|
+
"Alice",
|
125
|
+
["O1", "item1", 10.0, "default_extra"],
|
126
|
+
None,
|
127
|
+
]
|
128
|
+
|
129
|
+
customer_nt = CustomerNamedTuple(
|
130
|
+
name="Alice", order=OrderNamedTuple("O1", "item1", 10.0)
|
131
|
+
)
|
132
|
+
assert encode_engine_value(customer_nt) == [
|
133
|
+
"Alice",
|
134
|
+
["O1", "item1", 10.0, "default_extra"],
|
135
|
+
None,
|
136
|
+
]
|
137
|
+
|
98
138
|
|
99
139
|
def test_encode_engine_value_empty_list():
|
100
140
|
assert encode_engine_value([]) == []
|
101
141
|
assert encode_engine_value([[]]) == [[]]
|
102
142
|
|
143
|
+
|
103
144
|
def test_encode_engine_value_tuple():
|
104
145
|
assert encode_engine_value(()) == []
|
105
146
|
assert encode_engine_value((1, 2, 3)) == [1, 2, 3]
|
@@ -107,9 +148,11 @@ def test_encode_engine_value_tuple():
|
|
107
148
|
assert encode_engine_value(([],)) == [[]]
|
108
149
|
assert encode_engine_value(((),)) == [[]]
|
109
150
|
|
151
|
+
|
110
152
|
def test_encode_engine_value_none():
|
111
153
|
assert encode_engine_value(None) is None
|
112
154
|
|
155
|
+
|
113
156
|
def test_make_engine_value_decoder_basic_types():
|
114
157
|
for engine_type_in_py, value in [
|
115
158
|
(int, 42),
|
@@ -121,80 +164,190 @@ def test_make_engine_value_decoder_basic_types():
|
|
121
164
|
decoder = build_engine_value_decoder(engine_type_in_py)
|
122
165
|
assert decoder(value) == value
|
123
166
|
|
167
|
+
|
124
168
|
@pytest.mark.parametrize(
|
125
169
|
"data_type, engine_val, expected",
|
126
170
|
[
|
127
171
|
# All fields match (dataclass)
|
128
|
-
(
|
172
|
+
(
|
173
|
+
Order,
|
174
|
+
["O123", "mixed nuts", 25.0, "default_extra"],
|
175
|
+
Order("O123", "mixed nuts", 25.0, "default_extra"),
|
176
|
+
),
|
129
177
|
# All fields match (NamedTuple)
|
130
|
-
(
|
178
|
+
(
|
179
|
+
OrderNamedTuple,
|
180
|
+
["O123", "mixed nuts", 25.0, "default_extra"],
|
181
|
+
OrderNamedTuple("O123", "mixed nuts", 25.0, "default_extra"),
|
182
|
+
),
|
131
183
|
# Extra field in engine value (should ignore extra)
|
132
|
-
(
|
133
|
-
|
184
|
+
(
|
185
|
+
Order,
|
186
|
+
["O123", "mixed nuts", 25.0, "default_extra", "unexpected"],
|
187
|
+
Order("O123", "mixed nuts", 25.0, "default_extra"),
|
188
|
+
),
|
189
|
+
(
|
190
|
+
OrderNamedTuple,
|
191
|
+
["O123", "mixed nuts", 25.0, "default_extra", "unexpected"],
|
192
|
+
OrderNamedTuple("O123", "mixed nuts", 25.0, "default_extra"),
|
193
|
+
),
|
134
194
|
# Fewer fields in engine value (should fill with default)
|
135
|
-
(
|
136
|
-
|
195
|
+
(
|
196
|
+
Order,
|
197
|
+
["O123", "mixed nuts", 0.0, "default_extra"],
|
198
|
+
Order("O123", "mixed nuts", 0.0, "default_extra"),
|
199
|
+
),
|
200
|
+
(
|
201
|
+
OrderNamedTuple,
|
202
|
+
["O123", "mixed nuts", 0.0, "default_extra"],
|
203
|
+
OrderNamedTuple("O123", "mixed nuts", 0.0, "default_extra"),
|
204
|
+
),
|
137
205
|
# More fields in engine value (should ignore extra)
|
138
|
-
(
|
139
|
-
|
206
|
+
(
|
207
|
+
Order,
|
208
|
+
["O123", "mixed nuts", 25.0, "unexpected"],
|
209
|
+
Order("O123", "mixed nuts", 25.0, "unexpected"),
|
210
|
+
),
|
211
|
+
(
|
212
|
+
OrderNamedTuple,
|
213
|
+
["O123", "mixed nuts", 25.0, "unexpected"],
|
214
|
+
OrderNamedTuple("O123", "mixed nuts", 25.0, "unexpected"),
|
215
|
+
),
|
140
216
|
# Truly extra field (should ignore the fifth field)
|
141
|
-
(
|
142
|
-
|
217
|
+
(
|
218
|
+
Order,
|
219
|
+
["O123", "mixed nuts", 25.0, "default_extra", "ignored"],
|
220
|
+
Order("O123", "mixed nuts", 25.0, "default_extra"),
|
221
|
+
),
|
222
|
+
(
|
223
|
+
OrderNamedTuple,
|
224
|
+
["O123", "mixed nuts", 25.0, "default_extra", "ignored"],
|
225
|
+
OrderNamedTuple("O123", "mixed nuts", 25.0, "default_extra"),
|
226
|
+
),
|
143
227
|
# Missing optional field in engine value (tags=None)
|
144
|
-
(
|
145
|
-
|
228
|
+
(
|
229
|
+
Customer,
|
230
|
+
["Alice", ["O1", "item1", 10.0, "default_extra"], None],
|
231
|
+
Customer("Alice", Order("O1", "item1", 10.0, "default_extra"), None),
|
232
|
+
),
|
233
|
+
(
|
234
|
+
CustomerNamedTuple,
|
235
|
+
["Alice", ["O1", "item1", 10.0, "default_extra"], None],
|
236
|
+
CustomerNamedTuple(
|
237
|
+
"Alice", OrderNamedTuple("O1", "item1", 10.0, "default_extra"), None
|
238
|
+
),
|
239
|
+
),
|
146
240
|
# Extra field in engine value for Customer (should ignore)
|
147
|
-
(
|
148
|
-
|
241
|
+
(
|
242
|
+
Customer,
|
243
|
+
["Alice", ["O1", "item1", 10.0, "default_extra"], [["vip"]], "extra"],
|
244
|
+
Customer(
|
245
|
+
"Alice", Order("O1", "item1", 10.0, "default_extra"), [Tag("vip")]
|
246
|
+
),
|
247
|
+
),
|
248
|
+
(
|
249
|
+
CustomerNamedTuple,
|
250
|
+
["Alice", ["O1", "item1", 10.0, "default_extra"], [["vip"]], "extra"],
|
251
|
+
CustomerNamedTuple(
|
252
|
+
"Alice",
|
253
|
+
OrderNamedTuple("O1", "item1", 10.0, "default_extra"),
|
254
|
+
[Tag("vip")],
|
255
|
+
),
|
256
|
+
),
|
149
257
|
# Missing optional field with default
|
150
|
-
(
|
151
|
-
|
258
|
+
(
|
259
|
+
Order,
|
260
|
+
["O123", "mixed nuts", 25.0],
|
261
|
+
Order("O123", "mixed nuts", 25.0, "default_extra"),
|
262
|
+
),
|
263
|
+
(
|
264
|
+
OrderNamedTuple,
|
265
|
+
["O123", "mixed nuts", 25.0],
|
266
|
+
OrderNamedTuple("O123", "mixed nuts", 25.0, "default_extra"),
|
267
|
+
),
|
152
268
|
# Partial optional fields
|
153
|
-
(
|
154
|
-
|
155
|
-
|
269
|
+
(
|
270
|
+
Customer,
|
271
|
+
["Alice", ["O1", "item1", 10.0]],
|
272
|
+
Customer("Alice", Order("O1", "item1", 10.0, "default_extra"), None),
|
273
|
+
),
|
274
|
+
(
|
275
|
+
CustomerNamedTuple,
|
276
|
+
["Alice", ["O1", "item1", 10.0]],
|
277
|
+
CustomerNamedTuple(
|
278
|
+
"Alice", OrderNamedTuple("O1", "item1", 10.0, "default_extra"), None
|
279
|
+
),
|
280
|
+
),
|
281
|
+
],
|
156
282
|
)
|
157
283
|
def test_struct_decoder_cases(data_type, engine_val, expected):
|
158
284
|
decoder = build_engine_value_decoder(data_type)
|
159
285
|
assert decoder(engine_val) == expected
|
160
286
|
|
287
|
+
|
161
288
|
def test_make_engine_value_decoder_collections():
|
162
289
|
# List of structs (dataclass)
|
163
290
|
decoder = build_engine_value_decoder(list[Order])
|
164
291
|
engine_val = [
|
165
292
|
["O1", "item1", 10.0, "default_extra"],
|
166
|
-
["O2", "item2", 20.0, "default_extra"]
|
293
|
+
["O2", "item2", 20.0, "default_extra"],
|
167
294
|
]
|
168
|
-
assert decoder(engine_val) == [
|
169
|
-
|
295
|
+
assert decoder(engine_val) == [
|
296
|
+
Order("O1", "item1", 10.0, "default_extra"),
|
297
|
+
Order("O2", "item2", 20.0, "default_extra"),
|
298
|
+
]
|
299
|
+
|
170
300
|
# List of structs (NamedTuple)
|
171
301
|
decoder = build_engine_value_decoder(list[OrderNamedTuple])
|
172
|
-
assert decoder(engine_val) == [
|
173
|
-
|
302
|
+
assert decoder(engine_val) == [
|
303
|
+
OrderNamedTuple("O1", "item1", 10.0, "default_extra"),
|
304
|
+
OrderNamedTuple("O2", "item2", 20.0, "default_extra"),
|
305
|
+
]
|
306
|
+
|
174
307
|
# Struct with list field
|
175
308
|
decoder = build_engine_value_decoder(Customer)
|
176
|
-
engine_val = [
|
177
|
-
|
178
|
-
|
309
|
+
engine_val = [
|
310
|
+
"Alice",
|
311
|
+
["O1", "item1", 10.0, "default_extra"],
|
312
|
+
[["vip"], ["premium"]],
|
313
|
+
]
|
314
|
+
assert decoder(engine_val) == Customer(
|
315
|
+
"Alice",
|
316
|
+
Order("O1", "item1", 10.0, "default_extra"),
|
317
|
+
[Tag("vip"), Tag("premium")],
|
318
|
+
)
|
319
|
+
|
179
320
|
# NamedTuple with list field
|
180
321
|
decoder = build_engine_value_decoder(CustomerNamedTuple)
|
181
|
-
assert decoder(engine_val) == CustomerNamedTuple(
|
182
|
-
|
322
|
+
assert decoder(engine_val) == CustomerNamedTuple(
|
323
|
+
"Alice",
|
324
|
+
OrderNamedTuple("O1", "item1", 10.0, "default_extra"),
|
325
|
+
[Tag("vip"), Tag("premium")],
|
326
|
+
)
|
327
|
+
|
183
328
|
# Struct with struct field
|
184
329
|
decoder = build_engine_value_decoder(NestedStruct)
|
185
330
|
engine_val = [
|
186
331
|
["Alice", ["O1", "item1", 10.0, "default_extra"], [["vip"]]],
|
187
|
-
[
|
188
|
-
|
332
|
+
[
|
333
|
+
["O1", "item1", 10.0, "default_extra"],
|
334
|
+
["O2", "item2", 20.0, "default_extra"],
|
335
|
+
],
|
336
|
+
2,
|
189
337
|
]
|
190
338
|
assert decoder(engine_val) == NestedStruct(
|
191
339
|
Customer("Alice", Order("O1", "item1", 10.0, "default_extra"), [Tag("vip")]),
|
192
|
-
[
|
193
|
-
|
340
|
+
[
|
341
|
+
Order("O1", "item1", 10.0, "default_extra"),
|
342
|
+
Order("O2", "item2", 20.0, "default_extra"),
|
343
|
+
],
|
344
|
+
2,
|
194
345
|
)
|
195
346
|
|
347
|
+
|
196
348
|
def make_engine_order(fields):
|
197
|
-
return make_dataclass(
|
349
|
+
return make_dataclass("EngineOrder", fields)
|
350
|
+
|
198
351
|
|
199
352
|
def make_python_order(fields, defaults=None):
|
200
353
|
if defaults is None:
|
@@ -205,7 +358,8 @@ def make_python_order(fields, defaults=None):
|
|
205
358
|
ordered_fields = non_default_fields + default_fields
|
206
359
|
# Prepare the namespace for defaults (only for fields at the end)
|
207
360
|
namespace = {k: defaults[k] for k, _ in default_fields}
|
208
|
-
return make_dataclass(
|
361
|
+
return make_dataclass("PythonOrder", ordered_fields, namespace=namespace)
|
362
|
+
|
209
363
|
|
210
364
|
@pytest.mark.parametrize(
|
211
365
|
"engine_fields, python_fields, python_defaults, engine_val, expected_python_val",
|
@@ -266,9 +420,11 @@ def make_python_order(fields, defaults=None):
|
|
266
420
|
["O123", "mixed nuts", 25.0],
|
267
421
|
("O123", "mixed nuts"),
|
268
422
|
),
|
269
|
-
]
|
423
|
+
],
|
270
424
|
)
|
271
|
-
def test_field_position_cases(
|
425
|
+
def test_field_position_cases(
|
426
|
+
engine_fields, python_fields, python_defaults, engine_val, expected_python_val
|
427
|
+
):
|
272
428
|
EngineOrder = make_engine_order(engine_fields)
|
273
429
|
PythonOrder = make_python_order(python_fields, python_defaults)
|
274
430
|
decoder = build_engine_value_decoder(EngineOrder, PythonOrder)
|
@@ -277,36 +433,57 @@ def test_field_position_cases(engine_fields, python_fields, python_defaults, eng
|
|
277
433
|
# Instantiate using keyword arguments (order doesn't matter)
|
278
434
|
assert decoder(engine_val) == PythonOrder(**expected_dict)
|
279
435
|
|
436
|
+
|
280
437
|
def test_roundtrip_ltable():
|
281
438
|
t = list[Order]
|
282
439
|
value = [Order("O1", "item1", 10.0), Order("O2", "item2", 20.0)]
|
283
440
|
encoded = encode_engine_value(value)
|
284
|
-
assert encoded == [
|
441
|
+
assert encoded == [
|
442
|
+
["O1", "item1", 10.0, "default_extra"],
|
443
|
+
["O2", "item2", 20.0, "default_extra"],
|
444
|
+
]
|
285
445
|
decoded = build_engine_value_decoder(t)(encoded)
|
286
446
|
assert decoded == value
|
287
|
-
|
447
|
+
|
288
448
|
t_nt = list[OrderNamedTuple]
|
289
|
-
value_nt = [
|
449
|
+
value_nt = [
|
450
|
+
OrderNamedTuple("O1", "item1", 10.0),
|
451
|
+
OrderNamedTuple("O2", "item2", 20.0),
|
452
|
+
]
|
290
453
|
encoded = encode_engine_value(value_nt)
|
291
|
-
assert encoded == [
|
454
|
+
assert encoded == [
|
455
|
+
["O1", "item1", 10.0, "default_extra"],
|
456
|
+
["O2", "item2", 20.0, "default_extra"],
|
457
|
+
]
|
292
458
|
decoded = build_engine_value_decoder(t_nt)(encoded)
|
293
459
|
assert decoded == value_nt
|
294
460
|
|
461
|
+
|
295
462
|
def test_roundtrip_ktable_str_key():
|
296
463
|
t = dict[str, Order]
|
297
464
|
value = {"K1": Order("O1", "item1", 10.0), "K2": Order("O2", "item2", 20.0)}
|
298
465
|
encoded = encode_engine_value(value)
|
299
|
-
assert encoded == [
|
466
|
+
assert encoded == [
|
467
|
+
["K1", "O1", "item1", 10.0, "default_extra"],
|
468
|
+
["K2", "O2", "item2", 20.0, "default_extra"],
|
469
|
+
]
|
300
470
|
decoded = build_engine_value_decoder(t)(encoded)
|
301
471
|
assert decoded == value
|
302
|
-
|
472
|
+
|
303
473
|
t_nt = dict[str, OrderNamedTuple]
|
304
|
-
value_nt = {
|
474
|
+
value_nt = {
|
475
|
+
"K1": OrderNamedTuple("O1", "item1", 10.0),
|
476
|
+
"K2": OrderNamedTuple("O2", "item2", 20.0),
|
477
|
+
}
|
305
478
|
encoded = encode_engine_value(value_nt)
|
306
|
-
assert encoded == [
|
479
|
+
assert encoded == [
|
480
|
+
["K1", "O1", "item1", 10.0, "default_extra"],
|
481
|
+
["K2", "O2", "item2", 20.0, "default_extra"],
|
482
|
+
]
|
307
483
|
decoded = build_engine_value_decoder(t_nt)(encoded)
|
308
484
|
assert decoded == value_nt
|
309
485
|
|
486
|
+
|
310
487
|
def test_roundtrip_ktable_struct_key():
|
311
488
|
@dataclass(frozen=True)
|
312
489
|
class OrderKey:
|
@@ -314,22 +491,35 @@ def test_roundtrip_ktable_struct_key():
|
|
314
491
|
version: int
|
315
492
|
|
316
493
|
t = dict[OrderKey, Order]
|
317
|
-
value = {
|
494
|
+
value = {
|
495
|
+
OrderKey("A", 3): Order("O1", "item1", 10.0),
|
496
|
+
OrderKey("B", 4): Order("O2", "item2", 20.0),
|
497
|
+
}
|
318
498
|
encoded = encode_engine_value(value)
|
319
|
-
assert encoded == [
|
320
|
-
|
499
|
+
assert encoded == [
|
500
|
+
[["A", 3], "O1", "item1", 10.0, "default_extra"],
|
501
|
+
[["B", 4], "O2", "item2", 20.0, "default_extra"],
|
502
|
+
]
|
321
503
|
decoded = build_engine_value_decoder(t)(encoded)
|
322
504
|
assert decoded == value
|
323
|
-
|
505
|
+
|
324
506
|
t_nt = dict[OrderKey, OrderNamedTuple]
|
325
|
-
value_nt = {
|
507
|
+
value_nt = {
|
508
|
+
OrderKey("A", 3): OrderNamedTuple("O1", "item1", 10.0),
|
509
|
+
OrderKey("B", 4): OrderNamedTuple("O2", "item2", 20.0),
|
510
|
+
}
|
326
511
|
encoded = encode_engine_value(value_nt)
|
327
|
-
assert encoded == [
|
328
|
-
|
512
|
+
assert encoded == [
|
513
|
+
[["A", 3], "O1", "item1", 10.0, "default_extra"],
|
514
|
+
[["B", 4], "O2", "item2", 20.0, "default_extra"],
|
515
|
+
]
|
329
516
|
decoded = build_engine_value_decoder(t_nt)(encoded)
|
330
517
|
assert decoded == value_nt
|
331
518
|
|
519
|
+
|
332
520
|
IntVectorType = cocoindex.Vector[int, Literal[5]]
|
521
|
+
|
522
|
+
|
333
523
|
def test_vector_as_vector() -> None:
|
334
524
|
value: IntVectorType = [1, 2, 3, 4, 5]
|
335
525
|
encoded = encode_engine_value(value)
|
@@ -337,11 +527,13 @@ def test_vector_as_vector() -> None:
|
|
337
527
|
decoded = build_engine_value_decoder(IntVectorType)(encoded)
|
338
528
|
assert decoded == value
|
339
529
|
|
530
|
+
|
340
531
|
ListIntType = list[int]
|
532
|
+
|
533
|
+
|
341
534
|
def test_vector_as_list() -> None:
|
342
535
|
value: ListIntType = [1, 2, 3, 4, 5]
|
343
536
|
encoded = encode_engine_value(value)
|
344
537
|
assert encoded == [1, 2, 3, 4, 5]
|
345
538
|
decoded = build_engine_value_decoder(ListIntType)(encoded)
|
346
539
|
assert decoded == value
|
347
|
-
|