cocoindex 0.1.58__cp312-cp312-win_amd64.whl → 0.1.60__cp312-cp312-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.
cocoindex/__init__.py CHANGED
@@ -17,7 +17,16 @@ from .llm import LlmSpec, LlmApiType
17
17
  from .index import VectorSimilarityMetric, VectorIndexDef, IndexOptions
18
18
  from .setting import DatabaseConnectionSpec, Settings, ServerSettings
19
19
  from .setting import get_app_namespace
20
- from .typing import Float32, Float64, LocalDateTime, OffsetDateTime, Range, Vector, Json
20
+ from .typing import (
21
+ Int64,
22
+ Float32,
23
+ Float64,
24
+ LocalDateTime,
25
+ OffsetDateTime,
26
+ Range,
27
+ Vector,
28
+ Json,
29
+ )
21
30
 
22
31
  __all__ = [
23
32
  # Submodules
@@ -64,6 +73,7 @@ __all__ = [
64
73
  "ServerSettings",
65
74
  "get_app_namespace",
66
75
  # Typing
76
+ "Int64",
67
77
  "Float32",
68
78
  "Float64",
69
79
  "LocalDateTime",
Binary file
cocoindex/convert.py CHANGED
@@ -5,7 +5,6 @@ Utilities to convert between Python and engine values.
5
5
  import dataclasses
6
6
  import datetime
7
7
  import inspect
8
- import uuid
9
8
  from enum import Enum
10
9
  from typing import Any, Callable, Mapping, get_origin
11
10
 
@@ -14,7 +13,6 @@ import numpy as np
14
13
  from .typing import (
15
14
  KEY_FIELD_NAME,
16
15
  TABLE_TYPES,
17
- AnalyzedTypeInfo,
18
16
  DtypeRegistry,
19
17
  analyze_type_info,
20
18
  encode_enriched_type,
@@ -74,23 +72,16 @@ def make_engine_value_decoder(
74
72
  Returns:
75
73
  A decoder from an engine value to a Python value.
76
74
  """
77
-
78
75
  src_type_kind = src_type["kind"]
79
76
 
80
- dst_type_info: AnalyzedTypeInfo | None = None
81
- if (
82
- dst_annotation is not None
83
- and dst_annotation is not inspect.Parameter.empty
84
- and dst_annotation is not Any
85
- ):
86
- dst_type_info = analyze_type_info(dst_annotation)
87
- if not _is_type_kind_convertible_to(src_type_kind, dst_type_info.kind):
88
- raise ValueError(
89
- f"Type mismatch for `{''.join(field_path)}`: "
90
- f"passed in {src_type_kind}, declared {dst_annotation} ({dst_type_info.kind})"
91
- )
92
-
93
- if dst_type_info is None:
77
+ dst_is_any = (
78
+ dst_annotation is None
79
+ or dst_annotation is inspect.Parameter.empty
80
+ or dst_annotation is Any
81
+ )
82
+ if dst_is_any:
83
+ if src_type_kind == "Union":
84
+ return lambda value: value[1]
94
85
  if src_type_kind == "Struct" or src_type_kind in TABLE_TYPES:
95
86
  raise ValueError(
96
87
  f"Missing type annotation for `{''.join(field_path)}`."
@@ -98,6 +89,41 @@ def make_engine_value_decoder(
98
89
  )
99
90
  return lambda value: value
100
91
 
92
+ dst_type_info = analyze_type_info(dst_annotation)
93
+
94
+ if src_type_kind == "Union":
95
+ dst_type_variants = (
96
+ dst_type_info.union_variant_types
97
+ if dst_type_info.union_variant_types is not None
98
+ else [dst_annotation]
99
+ )
100
+ src_type_variants = src_type["types"]
101
+ decoders = []
102
+ for i, src_type_variant in enumerate(src_type_variants):
103
+ src_field_path = field_path + [f"[{i}]"]
104
+ decoder = None
105
+ for dst_type_variant in dst_type_variants:
106
+ try:
107
+ decoder = make_engine_value_decoder(
108
+ src_field_path, src_type_variant, dst_type_variant
109
+ )
110
+ break
111
+ except ValueError:
112
+ pass
113
+ if decoder is None:
114
+ raise ValueError(
115
+ f"Type mismatch for `{''.join(field_path)}`: "
116
+ f"cannot find matched target type for source type variant {src_type_variant}"
117
+ )
118
+ decoders.append(decoder)
119
+ return lambda value: decoders[value[0]](value[1])
120
+
121
+ if not _is_type_kind_convertible_to(src_type_kind, dst_type_info.kind):
122
+ raise ValueError(
123
+ f"Type mismatch for `{''.join(field_path)}`: "
124
+ f"passed in {src_type_kind}, declared {dst_annotation} ({dst_type_info.kind})"
125
+ )
126
+
101
127
  if dst_type_info.kind in ("Float32", "Float64", "Int64"):
102
128
  dst_core_type = dst_type_info.core_type
103
129
 
@@ -196,9 +222,6 @@ def make_engine_value_decoder(
196
222
  field_path.pop()
197
223
  return decode
198
224
 
199
- if src_type_kind == "Union":
200
- return lambda value: value[1]
201
-
202
225
  return lambda value: value
203
226
 
204
227
 
cocoindex/llm.py CHANGED
@@ -12,6 +12,7 @@ class LlmApiType(Enum):
12
12
  LITE_LLM = "LiteLlm"
13
13
  OPEN_ROUTER = "OpenRouter"
14
14
  VOYAGE = "Voyage"
15
+ VLLM = "Vllm"
15
16
 
16
17
 
17
18
  @dataclass
@@ -78,16 +78,15 @@ def build_engine_value_decoder(
78
78
  return make_engine_value_decoder([], engine_type, python_type or engine_type_in_py)
79
79
 
80
80
 
81
- def validate_full_roundtrip(
81
+ def validate_full_roundtrip_to(
82
82
  value: Any,
83
- value_type: Any = None,
84
- *other_decoded_values: tuple[Any, Any],
83
+ value_type: Any,
84
+ *decoded_values: tuple[Any, Any],
85
85
  ) -> None:
86
86
  """
87
- Validate the given value doesn't change after encoding, sending to engine (using output_type), receiving back and decoding (using input_type).
87
+ Validate the given value becomes specific values after encoding, sending to engine (using output_type), receiving back and decoding (using input_type).
88
88
 
89
- `other_decoded_values` is a tuple of (value, type) pairs.
90
- If provided, also validate the value can be decoded to the other types.
89
+ `decoded_values` is a tuple of (value, type) pairs.
91
90
  """
92
91
  from cocoindex import _engine # type: ignore
93
92
 
@@ -102,15 +101,27 @@ def validate_full_roundtrip(
102
101
  value_from_engine = _engine.testutil.seder_roundtrip(
103
102
  encoded_value, encoded_output_type
104
103
  )
105
- decoder = make_engine_value_decoder([], encoded_output_type, value_type)
106
- decoded_value = decoder(value_from_engine)
107
- assert eq(decoded_value, value)
108
104
 
109
- if other_decoded_values is not None:
110
- for other_value, other_type in other_decoded_values:
111
- decoder = make_engine_value_decoder([], encoded_output_type, other_type)
112
- other_decoded_value = decoder(value_from_engine)
113
- assert eq(other_decoded_value, other_value)
105
+ for other_value, other_type in decoded_values:
106
+ decoder = make_engine_value_decoder([], encoded_output_type, other_type)
107
+ other_decoded_value = decoder(value_from_engine)
108
+ assert eq(other_decoded_value, other_value)
109
+
110
+
111
+ def validate_full_roundtrip(
112
+ value: Any,
113
+ value_type: Any,
114
+ *other_decoded_values: tuple[Any, Any],
115
+ ) -> None:
116
+ """
117
+ Validate the given value doesn't change after encoding, sending to engine (using output_type), receiving back and decoding (using input_type).
118
+
119
+ `other_decoded_values` is a tuple of (value, type) pairs.
120
+ If provided, also validate the value can be decoded to the other types.
121
+ """
122
+ validate_full_roundtrip_to(
123
+ value, value_type, (value, value_type), *other_decoded_values
124
+ )
114
125
 
115
126
 
116
127
  def test_encode_engine_value_basic_types() -> None:
@@ -218,17 +229,33 @@ def test_encode_engine_value_none() -> None:
218
229
 
219
230
 
220
231
  def test_roundtrip_basic_types() -> None:
221
- validate_full_roundtrip(42, int, (42, None))
222
- validate_full_roundtrip(3.25, float, (3.25, Float64))
223
232
  validate_full_roundtrip(
224
- 3.25, Float64, (3.25, float), (np.float64(3.25), np.float64)
233
+ 42, cocoindex.Int64, (42, int), (np.int64(42), np.int64), (42, None)
234
+ )
235
+ validate_full_roundtrip(42, int, (42, cocoindex.Int64))
236
+ validate_full_roundtrip(np.int64(42), np.int64, (42, cocoindex.Int64))
237
+
238
+ validate_full_roundtrip(
239
+ 3.25, Float64, (3.25, float), (np.float64(3.25), np.float64), (3.25, None)
225
240
  )
241
+ validate_full_roundtrip(3.25, float, (3.25, Float64))
242
+ validate_full_roundtrip(np.float64(3.25), np.float64, (3.25, Float64))
243
+
226
244
  validate_full_roundtrip(
227
- 3.25, Float32, (3.25, float), (np.float32(3.25), np.float32)
245
+ 3.25,
246
+ Float32,
247
+ (3.25, float),
248
+ (np.float32(3.25), np.float32),
249
+ (np.float64(3.25), np.float64),
250
+ (3.25, Float64),
251
+ (3.25, None),
228
252
  )
253
+ validate_full_roundtrip(np.float32(3.25), np.float32, (3.25, Float32))
254
+
229
255
  validate_full_roundtrip("hello", str, ("hello", None))
230
256
  validate_full_roundtrip(True, bool, (True, None))
231
257
  validate_full_roundtrip(False, bool, (False, None))
258
+ validate_full_roundtrip((1, 2), cocoindex.Range, ((1, 2), None))
232
259
  validate_full_roundtrip(
233
260
  datetime.date(2025, 1, 1), datetime.date, (datetime.date(2025, 1, 1), None)
234
261
  )
@@ -238,14 +265,37 @@ def test_roundtrip_basic_types() -> None:
238
265
  cocoindex.LocalDateTime,
239
266
  (datetime.datetime(2025, 1, 2, 3, 4, 5, 123456), datetime.datetime),
240
267
  )
268
+
269
+ tz = datetime.timezone(datetime.timedelta(hours=5))
241
270
  validate_full_roundtrip(
242
- datetime.datetime(2025, 1, 2, 3, 4, 5, 123456, datetime.UTC),
271
+ datetime.datetime(2025, 1, 2, 3, 4, 5, 123456, tz),
272
+ cocoindex.OffsetDateTime,
273
+ (
274
+ datetime.datetime(2025, 1, 2, 3, 4, 5, 123456, tz),
275
+ datetime.datetime,
276
+ ),
277
+ )
278
+ validate_full_roundtrip(
279
+ datetime.datetime(2025, 1, 2, 3, 4, 5, 123456, tz),
280
+ datetime.datetime,
281
+ (datetime.datetime(2025, 1, 2, 3, 4, 5, 123456, tz), cocoindex.OffsetDateTime),
282
+ )
283
+ validate_full_roundtrip_to(
284
+ datetime.datetime(2025, 1, 2, 3, 4, 5, 123456),
243
285
  cocoindex.OffsetDateTime,
244
286
  (
245
287
  datetime.datetime(2025, 1, 2, 3, 4, 5, 123456, datetime.UTC),
246
288
  datetime.datetime,
247
289
  ),
248
290
  )
291
+ validate_full_roundtrip_to(
292
+ datetime.datetime(2025, 1, 2, 3, 4, 5, 123456),
293
+ datetime.datetime,
294
+ (
295
+ datetime.datetime(2025, 1, 2, 3, 4, 5, 123456, datetime.UTC),
296
+ cocoindex.OffsetDateTime,
297
+ ),
298
+ )
249
299
 
250
300
  uuid_value = uuid.uuid4()
251
301
  validate_full_roundtrip(uuid_value, uuid.UUID, (uuid_value, None))
@@ -613,6 +663,18 @@ def test_roundtrip_union_timedelta() -> None:
613
663
  validate_full_roundtrip(value, t)
614
664
 
615
665
 
666
+ def test_roundtrip_vector_of_union() -> None:
667
+ t = list[str | int]
668
+ value = ["a", 1]
669
+ validate_full_roundtrip(value, t)
670
+
671
+
672
+ def test_roundtrip_union_with_vector() -> None:
673
+ t = NDArray[np.float32] | str
674
+ value = np.array([1.0, 2.0, 3.0], dtype=np.float32)
675
+ validate_full_roundtrip(value, t, ([1.0, 2.0, 3.0], list[float] | str))
676
+
677
+
616
678
  def test_roundtrip_ltable() -> None:
617
679
  t = list[Order]
618
680
  value = [Order("O1", "item1", 10.0), Order("O2", "item2", 20.0)]
cocoindex/typing.py CHANGED
@@ -40,6 +40,7 @@ class TypeAttr:
40
40
 
41
41
  Annotation = TypeKind | TypeAttr | VectorInfo
42
42
 
43
+ Int64 = Annotated[int, TypeKind("Int64")]
43
44
  Float32 = Annotated[float, TypeKind("Float32")]
44
45
  Float64 = Annotated[float, TypeKind("Float64")]
45
46
  Range = Annotated[tuple[int, int], TypeKind("Range")]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cocoindex
3
- Version: 0.1.58
3
+ Version: 0.1.60
4
4
  Requires-Dist: click>=8.1.8
5
5
  Requires-Dist: rich>=14.0.0
6
6
  Requires-Dist: python-dotenv>=1.1.0
@@ -1,17 +1,17 @@
1
- cocoindex-0.1.58.dist-info/METADATA,sha256=e7gGcZ9UjhsNZfR79TbsUgrpUJDNGjG4oAtYxicsu14,10185
2
- cocoindex-0.1.58.dist-info/WHEEL,sha256=0ua6B-UmXPKizyn4Mhcu6S66EB8t6wxm_Wsw5H1bZYs,96
3
- cocoindex-0.1.58.dist-info/entry_points.txt,sha256=_NretjYVzBdNTn7dK-zgwr7YfG2afz1u1uSE-5bZXF8,46
4
- cocoindex-0.1.58.dist-info/licenses/LICENSE,sha256=HrhfyXIkWY2tGFK11kg7vPCqhgh5DcxleloqdhrpyMY,11558
5
- cocoindex/__init__.py,sha256=e9T2v2r1WqVNn18Vz63U5paPEQeDaXfhtuaNl8VykTA,1951
6
- cocoindex/_engine.cp312-win_amd64.pyd,sha256=_raeFqyoCK4Nu0crKtHUvAZ-0n1R-pKuADuwvQTJF0w,62009344
1
+ cocoindex-0.1.60.dist-info/METADATA,sha256=-nZQV4R6EgHn6tzgHjA93U3DdUvDkz-1unHB9oHExh4,10185
2
+ cocoindex-0.1.60.dist-info/WHEEL,sha256=0ua6B-UmXPKizyn4Mhcu6S66EB8t6wxm_Wsw5H1bZYs,96
3
+ cocoindex-0.1.60.dist-info/entry_points.txt,sha256=_NretjYVzBdNTn7dK-zgwr7YfG2afz1u1uSE-5bZXF8,46
4
+ cocoindex-0.1.60.dist-info/licenses/LICENSE,sha256=HrhfyXIkWY2tGFK11kg7vPCqhgh5DcxleloqdhrpyMY,11558
5
+ cocoindex/__init__.py,sha256=sACxACrDdaGW9AgRLa4lFx1MdtM_PcuOHwMVZbtoUk8,2018
6
+ cocoindex/_engine.cp312-win_amd64.pyd,sha256=sc3zWAnBAZwxDJbjSklC6RrqMuCnipMok9_2f_k6rvw,62014464
7
7
  cocoindex/auth_registry.py,sha256=LojDKoX0ccO-G3bboFMlAti50_t5GK9BS0ouPJZfyUs,745
8
8
  cocoindex/cli.py,sha256=N3GJUmqaZeqEMcJC4zXvmKyqCd_1p44H2M7jegfUx7U,22053
9
- cocoindex/convert.py,sha256=Gvy2bw0YrhOhqx7EQpa-bZ1TxWREy6ur2sKwMK9J_h4,10522
9
+ cocoindex/convert.py,sha256=cOqouCbaGHf2kaUrN99dQxVOJH1XyT4lXhnVZUZtgo4,11516
10
10
  cocoindex/flow.py,sha256=MuG-LLE3YnGufRtlolVj3KW6-ShER_7ybmQZfpg9-_I,34112
11
11
  cocoindex/functions.py,sha256=ShHLmFPN8DYqxUDFm4EUJhuoKlax8HdU7q69V47ljQo,3307
12
12
  cocoindex/index.py,sha256=GrqTm1rLwICQ8hadtNvJAxVg7GWMvtMmFcbiNtNzmP0,569
13
13
  cocoindex/lib.py,sha256=o2UGq3eWsZbK5nusZEU7Y0R6NTbT0i03G2ye8N6ATNg,3015
14
- cocoindex/llm.py,sha256=zc-5o6qWo8KBXa6a533jbmad5QoSBtJL9b7bj9SFehY,453
14
+ cocoindex/llm.py,sha256=lNVoJ4qxNahqWoH9_bpm4gSS8A_DyeVXnnAYUftWbJ4,472
15
15
  cocoindex/op.py,sha256=h1bp56NEVxCRrOjzyta1h52u6d9Vol_Qau9Pv1sUlVE,12141
16
16
  cocoindex/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
17
17
  cocoindex/runtime.py,sha256=saKEZntVwUVQNASRhiO9bHRVIFmQccemq2f9mo4mo1A,1090
@@ -20,9 +20,9 @@ cocoindex/setup.py,sha256=KbJvmeFu0NbeoH-5iDmHZP86f26HIId8kHmGUNZAePI,3160
20
20
  cocoindex/sources.py,sha256=4hxsntuyClp_jKH4oZbx3iE3UM4P2bZTpWy28dqdyFY,1375
21
21
  cocoindex/targets.py,sha256=7FfG9kuEf5KTXtLwXMFaPFIut3PsIbpb3XIEjjeF7Bg,2931
22
22
  cocoindex/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
23
- cocoindex/tests/test_convert.py,sha256=npvLoWfZenQn4U-7odrP_CG7R3quwZWI0IEMNMDD5H0,37195
23
+ cocoindex/tests/test_convert.py,sha256=Hm8n1XZx58tkKbFiN43cre38bAAV1j9XorBE2x01M4M,39132
24
24
  cocoindex/tests/test_optional_database.py,sha256=dnzmTgaJf37D3q8fQsjP5UDER6FYETaUokDnFBMLtIk,8755
25
25
  cocoindex/tests/test_typing.py,sha256=6W2NQmyTj4LMuWegV5m4NVP2clVNrUa5eD28_3nwzjs,15300
26
- cocoindex/typing.py,sha256=T5BsXOArgXK4yoDSh9Fo-dzXGYYgsnRhLVOH1Z_42Ig,12985
26
+ cocoindex/typing.py,sha256=qdVwkp3jCfWDuvzYKRih4KFLEWKwAbnkSe9MKh9xHr8,13028
27
27
  cocoindex/utils.py,sha256=U3W39zD2uZpXX8v84tJD7sRmbC5ar3z_ljAP1cJrYXI,618
28
- cocoindex-0.1.58.dist-info/RECORD,,
28
+ cocoindex-0.1.60.dist-info/RECORD,,