cocoindex 0.1.57__pp311-pypy311_pp73-manylinux_2_28_aarch64.whl → 0.1.59__pp311-pypy311_pp73-manylinux_2_28_aarch64.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/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/flow.py CHANGED
@@ -5,25 +5,27 @@ Flow is the main interface for building and running flows.
5
5
  from __future__ import annotations
6
6
 
7
7
  import asyncio
8
- import re
9
- import inspect
10
8
  import datetime
11
9
  import functools
10
+ import inspect
11
+ import re
12
+
13
+ from dataclasses import dataclass
14
+ from enum import Enum
15
+ from threading import Lock
12
16
  from typing import (
13
17
  Any,
14
18
  Callable,
19
+ Generic,
20
+ NamedTuple,
15
21
  Sequence,
16
22
  TypeVar,
17
- Generic,
23
+ cast,
18
24
  get_args,
19
25
  get_origin,
20
- NamedTuple,
21
- cast,
22
26
  Iterable,
23
27
  )
24
- from threading import Lock
25
- from enum import Enum
26
- from dataclasses import dataclass
28
+
27
29
  from rich.text import Text
28
30
  from rich.tree import Tree
29
31
 
@@ -32,9 +34,10 @@ from . import index
32
34
  from . import op
33
35
  from . import setting
34
36
  from .convert import dump_engine_object, encode_engine_value, make_engine_value_decoder
35
- from .typing import encode_enriched_type
37
+ from .op import FunctionSpec
36
38
  from .runtime import execution_context
37
39
  from .setup import SetupChangeBundle
40
+ from .typing import encode_enriched_type
38
41
 
39
42
 
40
43
  class _NameBuilder:
@@ -92,6 +95,30 @@ def _spec_kind(spec: Any) -> str:
92
95
  return cast(str, spec.__class__.__name__)
93
96
 
94
97
 
98
+ def _transform_helper(
99
+ flow_builder_state: _FlowBuilderState,
100
+ fn_spec: FunctionSpec,
101
+ transform_args: list[tuple[Any, str | None]],
102
+ name: str | None = None,
103
+ ) -> DataSlice[Any]:
104
+ if not isinstance(fn_spec, FunctionSpec):
105
+ raise ValueError("transform() can only be called on a CocoIndex function")
106
+
107
+ return _create_data_slice(
108
+ flow_builder_state,
109
+ lambda target_scope, name: flow_builder_state.engine_flow_builder.transform(
110
+ _spec_kind(fn_spec),
111
+ dump_engine_object(fn_spec),
112
+ transform_args,
113
+ target_scope,
114
+ flow_builder_state.field_name_builder.build_name(
115
+ name, prefix=_to_snake_case(_spec_kind(fn_spec)) + "_"
116
+ ),
117
+ ),
118
+ name,
119
+ )
120
+
121
+
95
122
  T = TypeVar("T")
96
123
  S = TypeVar("S")
97
124
 
@@ -191,31 +218,19 @@ class DataSlice(Generic[T]):
191
218
  """
192
219
  Apply a function to the data slice.
193
220
  """
194
- if not isinstance(fn_spec, op.FunctionSpec):
195
- raise ValueError("transform() can only be called on a CocoIndex function")
196
-
197
- transform_args: list[tuple[Any, str | None]]
198
- transform_args = [(self._state.engine_data_slice, None)]
221
+ transform_args: list[tuple[Any, str | None]] = [
222
+ (self._state.engine_data_slice, None)
223
+ ]
199
224
  transform_args += [
200
225
  (self._state.flow_builder_state.get_data_slice(v), None) for v in args
201
226
  ]
202
227
  transform_args += [
203
228
  (self._state.flow_builder_state.get_data_slice(v), k)
204
- for (k, v) in kwargs.items()
229
+ for k, v in kwargs.items()
205
230
  ]
206
231
 
207
- flow_builder_state = self._state.flow_builder_state
208
- return _create_data_slice(
209
- flow_builder_state,
210
- lambda target_scope, name: flow_builder_state.engine_flow_builder.transform(
211
- _spec_kind(fn_spec),
212
- dump_engine_object(fn_spec),
213
- transform_args,
214
- target_scope,
215
- flow_builder_state.field_name_builder.build_name(
216
- name, prefix=_to_snake_case(_spec_kind(fn_spec)) + "_"
217
- ),
218
- ),
232
+ return _transform_helper(
233
+ self._state.flow_builder_state, fn_spec, transform_args
219
234
  )
220
235
 
221
236
  def call(self, func: Callable[..., S], *args: Any, **kwargs: Any) -> S:
@@ -446,6 +461,24 @@ class FlowBuilder:
446
461
  name,
447
462
  )
448
463
 
464
+ def transform(
465
+ self, fn_spec: FunctionSpec, *args: Any, **kwargs: Any
466
+ ) -> DataSlice[Any]:
467
+ """
468
+ Apply a function to inputs, returning a DataSlice.
469
+ """
470
+ transform_args: list[tuple[Any, str | None]] = [
471
+ (self._state.get_data_slice(v), None) for v in args
472
+ ]
473
+ transform_args += [
474
+ (self._state.get_data_slice(v), k) for k, v in kwargs.items()
475
+ ]
476
+
477
+ if not transform_args:
478
+ raise ValueError("At least one input is required for transformation")
479
+
480
+ return _transform_helper(self._state, fn_spec, transform_args)
481
+
449
482
  def declare(self, spec: op.DeclarationSpec) -> None:
450
483
  """
451
484
  Add a declaration to the flow.
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
cocoindex/op.py CHANGED
@@ -5,13 +5,12 @@ Facilities for defining cocoindex operations.
5
5
  import asyncio
6
6
  import dataclasses
7
7
  import inspect
8
-
9
- from typing import Protocol, Any, Callable, Awaitable, dataclass_transform
10
8
  from enum import Enum
9
+ from typing import Any, Awaitable, Callable, Protocol, dataclass_transform
11
10
 
12
- from .typing import encode_enriched_type, resolve_forward_ref
13
- from .convert import encode_engine_value, make_engine_value_decoder
14
11
  from . import _engine # type: ignore
12
+ from .convert import encode_engine_value, make_engine_value_decoder
13
+ from .typing import encode_enriched_type, resolve_forward_ref
15
14
 
16
15
 
17
16
  class OpCategory(Enum):
@@ -104,7 +104,7 @@ def validate_full_roundtrip(
104
104
  )
105
105
  decoder = make_engine_value_decoder([], encoded_output_type, value_type)
106
106
  decoded_value = decoder(value_from_engine)
107
- assert eq(decoded_value, value)
107
+ assert eq(decoded_value, value), f"{decoded_value} != {value}"
108
108
 
109
109
  if other_decoded_values is not None:
110
110
  for other_value, other_type in other_decoded_values:
@@ -613,6 +613,18 @@ def test_roundtrip_union_timedelta() -> None:
613
613
  validate_full_roundtrip(value, t)
614
614
 
615
615
 
616
+ def test_roundtrip_vector_of_union() -> None:
617
+ t = list[str | int]
618
+ value = ["a", 1]
619
+ validate_full_roundtrip(value, t)
620
+
621
+
622
+ def test_roundtrip_union_with_vector() -> None:
623
+ t = NDArray[np.float32] | str
624
+ value = np.array([1.0, 2.0, 3.0], dtype=np.float32)
625
+ validate_full_roundtrip(value, t, ([1.0, 2.0, 3.0], list[float] | str))
626
+
627
+
616
628
  def test_roundtrip_ltable() -> None:
617
629
  t = list[Order]
618
630
  value = [Order("O1", "item1", 10.0), Order("O2", "item2", 20.0)]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cocoindex
3
- Version: 0.1.57
3
+ Version: 0.1.59
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,18 +1,18 @@
1
- cocoindex-0.1.57.dist-info/METADATA,sha256=B506wZaMqr_x4PwQrv-tQZqvkukTH4nkUkreAFAZkIk,10020
2
- cocoindex-0.1.57.dist-info/WHEEL,sha256=TukzpKFr1idb1-jhlJ5YrX48K0jJGkUZ6ZjYHenSQjw,116
3
- cocoindex-0.1.57.dist-info/entry_points.txt,sha256=_NretjYVzBdNTn7dK-zgwr7YfG2afz1u1uSE-5bZXF8,46
4
- cocoindex-0.1.57.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
1
+ cocoindex-0.1.59.dist-info/METADATA,sha256=XyuEgs1E6LhwzhvSwCwjcRmzFZkEHaw-GFEgpp5qVn8,10020
2
+ cocoindex-0.1.59.dist-info/WHEEL,sha256=TukzpKFr1idb1-jhlJ5YrX48K0jJGkUZ6ZjYHenSQjw,116
3
+ cocoindex-0.1.59.dist-info/entry_points.txt,sha256=_NretjYVzBdNTn7dK-zgwr7YfG2afz1u1uSE-5bZXF8,46
4
+ cocoindex-0.1.59.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
5
5
  cocoindex/__init__.py,sha256=MFm-QJzrr0ODJCsAAsPUzJXh8KH1WdZod8F60B1iUYw,1877
6
- cocoindex/_engine.pypy311-pp73-aarch64-linux-gnu.so,sha256=th7-r0uWeNbxN0QRexxbea4tdMTJ2vOUgLseTsqgr-s,60983336
6
+ cocoindex/_engine.pypy311-pp73-aarch64-linux-gnu.so,sha256=a_r4KT0uFdJBxdUw7yaIQQ4xofzur-2SaOEI8o8k9g8,60987392
7
7
  cocoindex/auth_registry.py,sha256=1XqO7ibjmBBd8i11XSJTvTgdz8p1ptW-ZpuSgo_5zzk,716
8
8
  cocoindex/cli.py,sha256=8bDL-Qmd9NYtn1DsDfvUMk45xfAqNf9YTyM7H9KRuNU,21345
9
- cocoindex/convert.py,sha256=XeSr0ykudBrB-RWRmcbdbt3WCihlLDSBIYUcDtPbTdA,10228
10
- cocoindex/flow.py,sha256=YUDXhCEolKIMIW_0ba2bwu27-kJIo1_t3ePy_sSkYHw,32191
9
+ cocoindex/convert.py,sha256=FsKb2Pfbm7e1VQDOs_AsoiW9PbIUuyHQuqUlrENXmUY,11199
10
+ cocoindex/flow.py,sha256=UQviW2O6nzCKt3jf7N1xAXULvK7YRCZDAj5hy5VLkjM,33041
11
11
  cocoindex/functions.py,sha256=IBwvdPpGR-S5mk53HvHpT2GVs15MI9wQznxgOdxA0ac,3202
12
12
  cocoindex/index.py,sha256=j93B9jEvvLXHtpzKWL88SY6wCGEoPgpsQhEGHlyYGFg,540
13
13
  cocoindex/lib.py,sha256=BeRUn3RqE_wSsVtsgCzbFFKe1LXgRyRmMOcmwWBuEXo,2940
14
- cocoindex/llm.py,sha256=hpwvHjWiLkoV018TkC191rztq62NQeewwF3kDsHUols,430
15
- cocoindex/op.py,sha256=Z7V9Fdz4qeTeozzKmp1Dk1lPUP0GBgVgD_vBEhTJS5Y,11810
14
+ cocoindex/llm.py,sha256=0ri8ZRg9_Zf2gyC5xuQ1Kq6kdZUO8r-A5WLnxit5S_4,448
15
+ cocoindex/op.py,sha256=r_Usx7Jqh49Cck3tsYLx2vLRNUZArkQP_g7bIID6LPU,11809
16
16
  cocoindex/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
17
17
  cocoindex/runtime.py,sha256=bAdHYaXFWiiUWyAgzmKTeaAaRR0D_AmaqVCIdPO-v00,1056
18
18
  cocoindex/setting.py,sha256=Zl8K86r8RVvG9c3pCsH0Ot8BHhDAQAQCjoBp7TnXMLQ,3590
@@ -20,9 +20,9 @@ cocoindex/setup.py,sha256=7uIHKN4FOCuoidPXcKyGTrkqpkl9luL49-6UcnMxYzw,3068
20
20
  cocoindex/sources.py,sha256=JCnOhv1w4o28e03i7yvo4ESicWYAhckkBg5bQlxNH4U,1330
21
21
  cocoindex/targets.py,sha256=Nfh_tpFd1goTnS_cxBjIs4j9zl3Z4Z1JomAQ1dl3Sic,2796
22
22
  cocoindex/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
23
- cocoindex/tests/test_convert.py,sha256=1IoJzfPtM5zoy0YKhTsZTX-fF4xA3w_4usyS4UN44vE,36150
23
+ cocoindex/tests/test_convert.py,sha256=fY3p1gRHZpuWUgk5v28UGPYzyaMI4Qakv4I4qHSNGu8,36528
24
24
  cocoindex/tests/test_optional_database.py,sha256=snAmkNa6wtOSaxoZE1HgjvL5v_ylitt3Jt_9df4Cgdc,8506
25
25
  cocoindex/tests/test_typing.py,sha256=t6UCYShcfonTfjBlGRWPiFGMZ8DGFfABXo6idekPoJE,14757
26
26
  cocoindex/typing.py,sha256=kPMFVKs2i4SCLzW1Tn5NP_Ev9DAc-2qW6eJ68gpLexU,12580
27
27
  cocoindex/utils.py,sha256=hUhX-XV6XGCtJSEIpBOuDv6VvqImwPlgBxztBTw7u0U,598
28
- cocoindex-0.1.57.dist-info/RECORD,,
28
+ cocoindex-0.1.59.dist-info/RECORD,,