cocoindex 0.1.53__cp313-cp313-macosx_11_0_arm64.whl → 0.1.54__cp313-cp313-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/_engine.cpython-313-darwin.so +0 -0
- cocoindex/cli.py +6 -6
- cocoindex/convert.py +80 -60
- cocoindex/flow.py +3 -2
- cocoindex/functions.py +10 -0
- cocoindex/llm.py +1 -0
- cocoindex/tests/__init__.py +0 -1
- cocoindex/tests/test_convert.py +134 -35
- cocoindex/tests/test_typing.py +26 -7
- cocoindex/typing.py +31 -12
- {cocoindex-0.1.53.dist-info → cocoindex-0.1.54.dist-info}/METADATA +11 -10
- cocoindex-0.1.54.dist-info/RECORD +28 -0
- cocoindex-0.1.53.dist-info/RECORD +0 -28
- {cocoindex-0.1.53.dist-info → cocoindex-0.1.54.dist-info}/WHEEL +0 -0
- {cocoindex-0.1.53.dist-info → cocoindex-0.1.54.dist-info}/entry_points.txt +0 -0
- {cocoindex-0.1.53.dist-info → cocoindex-0.1.54.dist-info}/licenses/LICENSE +0 -0
Binary file
|
cocoindex/cli.py
CHANGED
@@ -1,19 +1,19 @@
|
|
1
|
-
import
|
1
|
+
import atexit
|
2
2
|
import datetime
|
3
|
-
import sys
|
4
3
|
import importlib.util
|
5
4
|
import os
|
6
|
-
import
|
5
|
+
import sys
|
7
6
|
import types
|
7
|
+
from typing import Any
|
8
8
|
|
9
|
-
|
9
|
+
import click
|
10
|
+
from dotenv import find_dotenv, load_dotenv
|
10
11
|
from rich.console import Console
|
11
12
|
from rich.panel import Panel
|
12
13
|
from rich.table import Table
|
13
|
-
from typing import Any
|
14
14
|
|
15
15
|
from . import flow, lib, setting
|
16
|
-
from .setup import
|
16
|
+
from .setup import apply_setup_changes, drop_setup, flow_names_with_setup, sync_setup
|
17
17
|
|
18
18
|
# Create ServerSettings lazily upon first call, as environment variables may be loaded from files, etc.
|
19
19
|
COCOINDEX_HOST = "https://cocoindex.io"
|
cocoindex/convert.py
CHANGED
@@ -14,6 +14,7 @@ import numpy as np
|
|
14
14
|
from .typing import (
|
15
15
|
KEY_FIELD_NAME,
|
16
16
|
TABLE_TYPES,
|
17
|
+
AnalyzedTypeInfo,
|
17
18
|
DtypeRegistry,
|
18
19
|
analyze_type_info,
|
19
20
|
encode_enriched_type,
|
@@ -46,6 +47,19 @@ def encode_engine_value(value: Any) -> Any:
|
|
46
47
|
return value
|
47
48
|
|
48
49
|
|
50
|
+
_CONVERTIBLE_KINDS = {
|
51
|
+
("Float32", "Float64"),
|
52
|
+
("LocalDateTime", "OffsetDateTime"),
|
53
|
+
}
|
54
|
+
|
55
|
+
|
56
|
+
def _is_type_kind_convertible_to(src_type_kind: str, dst_type_kind: str) -> bool:
|
57
|
+
return (
|
58
|
+
src_type_kind == dst_type_kind
|
59
|
+
or (src_type_kind, dst_type_kind) in _CONVERTIBLE_KINDS
|
60
|
+
)
|
61
|
+
|
62
|
+
|
49
63
|
def make_engine_value_decoder(
|
50
64
|
field_path: list[str],
|
51
65
|
src_type: dict[str, Any],
|
@@ -65,11 +79,23 @@ def make_engine_value_decoder(
|
|
65
79
|
|
66
80
|
src_type_kind = src_type["kind"]
|
67
81
|
|
82
|
+
dst_type_info: AnalyzedTypeInfo | None = None
|
68
83
|
if (
|
69
|
-
dst_annotation is None
|
70
|
-
|
71
|
-
|
84
|
+
dst_annotation is not None
|
85
|
+
and dst_annotation is not inspect.Parameter.empty
|
86
|
+
and dst_annotation is not Any
|
72
87
|
):
|
88
|
+
dst_type_info = analyze_type_info(dst_annotation)
|
89
|
+
if not _is_type_kind_convertible_to(src_type_kind, dst_type_info.kind):
|
90
|
+
raise ValueError(
|
91
|
+
f"Type mismatch for `{''.join(field_path)}`: "
|
92
|
+
f"passed in {src_type_kind}, declared {dst_annotation} ({dst_type_info.kind})"
|
93
|
+
)
|
94
|
+
|
95
|
+
if src_type_kind == "Uuid":
|
96
|
+
return lambda value: uuid.UUID(bytes=value)
|
97
|
+
|
98
|
+
if dst_type_info is None:
|
73
99
|
if src_type_kind == "Struct" or src_type_kind in TABLE_TYPES:
|
74
100
|
raise ValueError(
|
75
101
|
f"Missing type annotation for `{''.join(field_path)}`."
|
@@ -77,32 +103,66 @@ def make_engine_value_decoder(
|
|
77
103
|
)
|
78
104
|
return lambda value: value
|
79
105
|
|
80
|
-
dst_type_info
|
106
|
+
if dst_type_info.kind in ("Float32", "Float64", "Int64"):
|
107
|
+
dst_core_type = dst_type_info.core_type
|
81
108
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
109
|
+
def decode_scalar(value: Any) -> Any | None:
|
110
|
+
if value is None:
|
111
|
+
if dst_type_info.nullable:
|
112
|
+
return None
|
113
|
+
raise ValueError(
|
114
|
+
f"Received null for non-nullable scalar `{''.join(field_path)}`"
|
115
|
+
)
|
116
|
+
return dst_core_type(value)
|
87
117
|
|
88
|
-
|
89
|
-
|
90
|
-
|
118
|
+
return decode_scalar
|
119
|
+
|
120
|
+
if src_type_kind == "Vector":
|
121
|
+
field_path_str = "".join(field_path)
|
122
|
+
expected_dim = (
|
123
|
+
dst_type_info.vector_info.dim if dst_type_info.vector_info else None
|
91
124
|
)
|
92
125
|
|
93
|
-
|
94
|
-
|
126
|
+
elem_decoder = None
|
127
|
+
scalar_dtype = None
|
128
|
+
if dst_type_info.np_number_type is None: # for Non-NDArray vector
|
129
|
+
elem_decoder = make_engine_value_decoder(
|
130
|
+
field_path + ["[*]"],
|
131
|
+
src_type["element_type"],
|
132
|
+
dst_type_info.elem_type,
|
133
|
+
)
|
134
|
+
else: # for NDArray vector
|
135
|
+
scalar_dtype = extract_ndarray_scalar_dtype(dst_type_info.np_number_type)
|
136
|
+
_ = DtypeRegistry.validate_dtype_and_get_kind(scalar_dtype)
|
95
137
|
|
96
|
-
def
|
138
|
+
def decode_vector(value: Any) -> Any | None:
|
97
139
|
if value is None:
|
98
140
|
if dst_type_info.nullable:
|
99
141
|
return None
|
100
142
|
raise ValueError(
|
101
|
-
f"Received null for non-nullable
|
143
|
+
f"Received null for non-nullable vector `{field_path_str}`"
|
102
144
|
)
|
103
|
-
|
145
|
+
if not isinstance(value, (np.ndarray, list)):
|
146
|
+
raise TypeError(
|
147
|
+
f"Expected NDArray or list for vector `{field_path_str}`, got {type(value)}"
|
148
|
+
)
|
149
|
+
if expected_dim is not None and len(value) != expected_dim:
|
150
|
+
raise ValueError(
|
151
|
+
f"Vector dimension mismatch for `{field_path_str}`: "
|
152
|
+
f"expected {expected_dim}, got {len(value)}"
|
153
|
+
)
|
154
|
+
|
155
|
+
if elem_decoder is not None: # for Non-NDArray vector
|
156
|
+
return [elem_decoder(v) for v in value]
|
157
|
+
else: # for NDArray vector
|
158
|
+
return np.array(value, dtype=scalar_dtype)
|
104
159
|
|
105
|
-
return
|
160
|
+
return decode_vector
|
161
|
+
|
162
|
+
if dst_type_info.struct_type is not None:
|
163
|
+
return _make_engine_struct_value_decoder(
|
164
|
+
field_path, src_type["fields"], dst_type_info.struct_type
|
165
|
+
)
|
106
166
|
|
107
167
|
if src_type_kind in TABLE_TYPES:
|
108
168
|
field_path.append("[*]")
|
@@ -141,48 +201,8 @@ def make_engine_value_decoder(
|
|
141
201
|
field_path.pop()
|
142
202
|
return decode
|
143
203
|
|
144
|
-
if src_type_kind == "
|
145
|
-
return lambda value:
|
146
|
-
|
147
|
-
if src_type_kind == "Vector":
|
148
|
-
|
149
|
-
def decode_vector(value: Any) -> Any | None:
|
150
|
-
field_path_str = "".join(field_path)
|
151
|
-
expected_dim = (
|
152
|
-
dst_type_info.vector_info.dim if dst_type_info.vector_info else None
|
153
|
-
)
|
154
|
-
|
155
|
-
if value is None:
|
156
|
-
if dst_type_info.nullable:
|
157
|
-
return None
|
158
|
-
raise ValueError(
|
159
|
-
f"Received null for non-nullable vector `{field_path_str}`"
|
160
|
-
)
|
161
|
-
if not isinstance(value, (np.ndarray, list)):
|
162
|
-
raise TypeError(
|
163
|
-
f"Expected NDArray or list for vector `{field_path_str}`, got {type(value)}"
|
164
|
-
)
|
165
|
-
if expected_dim is not None and len(value) != expected_dim:
|
166
|
-
raise ValueError(
|
167
|
-
f"Vector dimension mismatch for `{field_path_str}`: "
|
168
|
-
f"expected {expected_dim}, got {len(value)}"
|
169
|
-
)
|
170
|
-
|
171
|
-
if dst_type_info.np_number_type is None: # for Non-NDArray vector
|
172
|
-
elem_decoder = make_engine_value_decoder(
|
173
|
-
field_path + ["[*]"],
|
174
|
-
src_type["element_type"],
|
175
|
-
dst_type_info.elem_type,
|
176
|
-
)
|
177
|
-
return [elem_decoder(v) for v in value]
|
178
|
-
else: # for NDArray vector
|
179
|
-
scalar_dtype = extract_ndarray_scalar_dtype(
|
180
|
-
dst_type_info.np_number_type
|
181
|
-
)
|
182
|
-
_ = DtypeRegistry.validate_dtype_and_get_kind(scalar_dtype)
|
183
|
-
return np.array(value, dtype=scalar_dtype)
|
184
|
-
|
185
|
-
return decode_vector
|
204
|
+
if src_type_kind == "Union":
|
205
|
+
return lambda value: value[1]
|
186
206
|
|
187
207
|
return lambda value: value
|
188
208
|
|
cocoindex/flow.py
CHANGED
@@ -92,6 +92,7 @@ def _spec_kind(spec: Any) -> str:
|
|
92
92
|
|
93
93
|
|
94
94
|
T = TypeVar("T")
|
95
|
+
S = TypeVar("S")
|
95
96
|
|
96
97
|
|
97
98
|
class _DataSliceState:
|
@@ -185,7 +186,7 @@ class DataSlice(Generic[T]):
|
|
185
186
|
|
186
187
|
def transform(
|
187
188
|
self, fn_spec: op.FunctionSpec, *args: Any, **kwargs: Any
|
188
|
-
) -> DataSlice[
|
189
|
+
) -> DataSlice[Any]:
|
189
190
|
"""
|
190
191
|
Apply a function to the data slice.
|
191
192
|
"""
|
@@ -216,7 +217,7 @@ class DataSlice(Generic[T]):
|
|
216
217
|
),
|
217
218
|
)
|
218
219
|
|
219
|
-
def call(self, func: Callable[
|
220
|
+
def call(self, func: Callable[..., S], *args: Any, **kwargs: Any) -> S:
|
220
221
|
"""
|
221
222
|
Call a function with the data slice.
|
222
223
|
"""
|
cocoindex/functions.py
CHANGED
@@ -32,6 +32,16 @@ class SplitRecursively(op.FunctionSpec):
|
|
32
32
|
custom_languages: list[CustomLanguageSpec] = dataclasses.field(default_factory=list)
|
33
33
|
|
34
34
|
|
35
|
+
class EmbedText(op.FunctionSpec):
|
36
|
+
"""Embed a text into a vector space."""
|
37
|
+
|
38
|
+
api_type: llm.LlmApiType
|
39
|
+
model: str
|
40
|
+
address: str | None = None
|
41
|
+
output_dimension: int | None = None
|
42
|
+
task_type: str | None = None
|
43
|
+
|
44
|
+
|
35
45
|
class ExtractByLlm(op.FunctionSpec):
|
36
46
|
"""Extract information from a text using a LLM."""
|
37
47
|
|
cocoindex/llm.py
CHANGED
cocoindex/tests/__init__.py
CHANGED
@@ -1 +0,0 @@
|
|
1
|
-
|
cocoindex/tests/test_convert.py
CHANGED
@@ -91,23 +91,26 @@ def validate_full_roundtrip(
|
|
91
91
|
"""
|
92
92
|
from cocoindex import _engine # type: ignore
|
93
93
|
|
94
|
+
def eq(a: Any, b: Any) -> bool:
|
95
|
+
if isinstance(a, np.ndarray) and isinstance(b, np.ndarray):
|
96
|
+
return np.array_equal(a, b)
|
97
|
+
return type(a) == type(b) and not not (a == b)
|
98
|
+
|
94
99
|
encoded_value = encode_engine_value(value)
|
95
100
|
value_type = value_type or type(value)
|
96
101
|
encoded_output_type = encode_enriched_type(value_type)["type"]
|
97
102
|
value_from_engine = _engine.testutil.seder_roundtrip(
|
98
103
|
encoded_value, encoded_output_type
|
99
104
|
)
|
100
|
-
|
101
|
-
|
102
|
-
)
|
103
|
-
np.testing.assert_array_equal(decoded_value, value)
|
105
|
+
decoder = make_engine_value_decoder([], encoded_output_type, value_type)
|
106
|
+
decoded_value = decoder(value_from_engine)
|
107
|
+
assert eq(decoded_value, value)
|
104
108
|
|
105
109
|
if other_decoded_values is not None:
|
106
110
|
for other_value, other_type in other_decoded_values:
|
107
|
-
|
108
|
-
|
109
|
-
)
|
110
|
-
np.testing.assert_array_equal(other_decoded_value, other_value)
|
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)
|
111
114
|
|
112
115
|
|
113
116
|
def test_encode_engine_value_basic_types() -> None:
|
@@ -215,19 +218,38 @@ def test_encode_engine_value_none() -> None:
|
|
215
218
|
|
216
219
|
|
217
220
|
def test_roundtrip_basic_types() -> None:
|
218
|
-
validate_full_roundtrip(42, int)
|
221
|
+
validate_full_roundtrip(42, int, (42, None))
|
219
222
|
validate_full_roundtrip(3.25, float, (3.25, Float64))
|
220
|
-
validate_full_roundtrip(3.25, Float64, (3.25, float))
|
221
|
-
validate_full_roundtrip(3.25, Float32)
|
222
|
-
validate_full_roundtrip("hello", str)
|
223
|
-
validate_full_roundtrip(True, bool)
|
224
|
-
validate_full_roundtrip(False, bool)
|
225
|
-
validate_full_roundtrip(datetime.date(2025, 1, 1), datetime.date)
|
226
|
-
validate_full_roundtrip(datetime.datetime.now(), cocoindex.LocalDateTime)
|
227
223
|
validate_full_roundtrip(
|
228
|
-
|
224
|
+
3.25, Float64, (3.25, float), (np.float64(3.25), np.float64)
|
225
|
+
)
|
226
|
+
validate_full_roundtrip(
|
227
|
+
3.25, Float32, (3.25, float), (np.float32(3.25), np.float32)
|
228
|
+
)
|
229
|
+
validate_full_roundtrip("hello", str, ("hello", None))
|
230
|
+
validate_full_roundtrip(True, bool, (True, None))
|
231
|
+
validate_full_roundtrip(False, bool, (False, None))
|
232
|
+
validate_full_roundtrip(
|
233
|
+
datetime.date(2025, 1, 1), datetime.date, (datetime.date(2025, 1, 1), None)
|
234
|
+
)
|
235
|
+
|
236
|
+
validate_full_roundtrip(
|
237
|
+
datetime.datetime(2025, 1, 2, 3, 4, 5, 123456),
|
238
|
+
cocoindex.LocalDateTime,
|
239
|
+
(datetime.datetime(2025, 1, 2, 3, 4, 5, 123456), datetime.datetime),
|
240
|
+
)
|
241
|
+
validate_full_roundtrip(
|
242
|
+
datetime.datetime(2025, 1, 2, 3, 4, 5, 123456, datetime.UTC),
|
243
|
+
cocoindex.OffsetDateTime,
|
244
|
+
(
|
245
|
+
datetime.datetime(2025, 1, 2, 3, 4, 5, 123456, datetime.UTC),
|
246
|
+
datetime.datetime,
|
247
|
+
),
|
229
248
|
)
|
230
249
|
|
250
|
+
uuid_value = uuid.uuid4()
|
251
|
+
validate_full_roundtrip(uuid_value, uuid.UUID, (uuid_value, None))
|
252
|
+
|
231
253
|
|
232
254
|
def test_decode_scalar_numpy_values() -> None:
|
233
255
|
test_cases = [
|
@@ -549,6 +571,48 @@ def test_field_position_cases(
|
|
549
571
|
assert decoder(engine_val) == PythonOrder(**expected_dict)
|
550
572
|
|
551
573
|
|
574
|
+
def test_roundtrip_union_simple() -> None:
|
575
|
+
t = int | str | float
|
576
|
+
value = 10.4
|
577
|
+
validate_full_roundtrip(value, t)
|
578
|
+
|
579
|
+
|
580
|
+
def test_roundtrip_union_with_active_uuid() -> None:
|
581
|
+
t = str | uuid.UUID | int
|
582
|
+
value = uuid.uuid4().bytes
|
583
|
+
validate_full_roundtrip(value, t)
|
584
|
+
|
585
|
+
|
586
|
+
def test_roundtrip_union_with_inactive_uuid() -> None:
|
587
|
+
t = str | uuid.UUID | int
|
588
|
+
value = "5a9f8f6a-318f-4f1f-929d-566d7444a62d" # it's a string
|
589
|
+
validate_full_roundtrip(value, t)
|
590
|
+
|
591
|
+
|
592
|
+
def test_roundtrip_union_offset_datetime() -> None:
|
593
|
+
t = str | uuid.UUID | float | int | datetime.datetime
|
594
|
+
value = datetime.datetime.now(datetime.UTC)
|
595
|
+
validate_full_roundtrip(value, t)
|
596
|
+
|
597
|
+
|
598
|
+
def test_roundtrip_union_date() -> None:
|
599
|
+
t = str | uuid.UUID | float | int | datetime.date
|
600
|
+
value = datetime.date.today()
|
601
|
+
validate_full_roundtrip(value, t)
|
602
|
+
|
603
|
+
|
604
|
+
def test_roundtrip_union_time() -> None:
|
605
|
+
t = str | uuid.UUID | float | int | datetime.time
|
606
|
+
value = datetime.time()
|
607
|
+
validate_full_roundtrip(value, t)
|
608
|
+
|
609
|
+
|
610
|
+
def test_roundtrip_union_timedelta() -> None:
|
611
|
+
t = str | uuid.UUID | float | int | datetime.timedelta
|
612
|
+
value = datetime.timedelta(hours=39, minutes=10, seconds=1)
|
613
|
+
validate_full_roundtrip(value, t)
|
614
|
+
|
615
|
+
|
552
616
|
def test_roundtrip_ltable() -> None:
|
553
617
|
t = list[Order]
|
554
618
|
value = [Order("O1", "item1", 10.0), Order("O2", "item2", 20.0)]
|
@@ -807,37 +871,72 @@ def test_dump_vector_type_annotation_no_dim() -> None:
|
|
807
871
|
|
808
872
|
def test_full_roundtrip_vector_numeric_types() -> None:
|
809
873
|
"""Test full roundtrip for numeric vector types using NDArray."""
|
810
|
-
value_f32
|
811
|
-
|
874
|
+
value_f32 = np.array([1.0, 2.0, 3.0], dtype=np.float32)
|
875
|
+
validate_full_roundtrip(
|
876
|
+
value_f32,
|
877
|
+
Vector[np.float32, Literal[3]],
|
878
|
+
([np.float32(1.0), np.float32(2.0), np.float32(3.0)], list[np.float32]),
|
879
|
+
([1.0, 2.0, 3.0], list[cocoindex.Float32]),
|
880
|
+
([1.0, 2.0, 3.0], list[float]),
|
812
881
|
)
|
813
|
-
validate_full_roundtrip(
|
814
|
-
|
815
|
-
|
882
|
+
validate_full_roundtrip(
|
883
|
+
value_f32,
|
884
|
+
np.typing.NDArray[np.float32],
|
885
|
+
([np.float32(1.0), np.float32(2.0), np.float32(3.0)], list[np.float32]),
|
886
|
+
([1.0, 2.0, 3.0], list[cocoindex.Float32]),
|
887
|
+
([1.0, 2.0, 3.0], list[float]),
|
816
888
|
)
|
817
|
-
validate_full_roundtrip(
|
818
|
-
|
819
|
-
|
820
|
-
|
889
|
+
validate_full_roundtrip(
|
890
|
+
value_f32.tolist(),
|
891
|
+
list[np.float32],
|
892
|
+
(value_f32, Vector[np.float32, Literal[3]]),
|
893
|
+
([1.0, 2.0, 3.0], list[cocoindex.Float32]),
|
894
|
+
([1.0, 2.0, 3.0], list[float]),
|
895
|
+
)
|
896
|
+
|
897
|
+
value_f64 = np.array([1.0, 2.0, 3.0], dtype=np.float64)
|
898
|
+
validate_full_roundtrip(
|
899
|
+
value_f64,
|
900
|
+
Vector[np.float64, Literal[3]],
|
901
|
+
([np.float64(1.0), np.float64(2.0), np.float64(3.0)], list[np.float64]),
|
902
|
+
([1.0, 2.0, 3.0], list[cocoindex.Float64]),
|
903
|
+
([1.0, 2.0, 3.0], list[float]),
|
904
|
+
)
|
905
|
+
|
906
|
+
value_i64 = np.array([1, 2, 3], dtype=np.int64)
|
907
|
+
validate_full_roundtrip(
|
908
|
+
value_i64,
|
909
|
+
Vector[np.int64, Literal[3]],
|
910
|
+
([np.int64(1), np.int64(2), np.int64(3)], list[np.int64]),
|
911
|
+
([1, 2, 3], list[int]),
|
912
|
+
)
|
913
|
+
|
914
|
+
value_i32 = np.array([1, 2, 3], dtype=np.int32)
|
821
915
|
with pytest.raises(ValueError, match="Unsupported NumPy dtype"):
|
822
916
|
validate_full_roundtrip(value_i32, Vector[np.int32, Literal[3]])
|
823
|
-
value_u8
|
917
|
+
value_u8 = np.array([1, 2, 3], dtype=np.uint8)
|
824
918
|
with pytest.raises(ValueError, match="Unsupported NumPy dtype"):
|
825
919
|
validate_full_roundtrip(value_u8, Vector[np.uint8, Literal[3]])
|
826
|
-
value_u16
|
920
|
+
value_u16 = np.array([1, 2, 3], dtype=np.uint16)
|
827
921
|
with pytest.raises(ValueError, match="Unsupported NumPy dtype"):
|
828
922
|
validate_full_roundtrip(value_u16, Vector[np.uint16, Literal[3]])
|
829
|
-
value_u32
|
923
|
+
value_u32 = np.array([1, 2, 3], dtype=np.uint32)
|
830
924
|
with pytest.raises(ValueError, match="Unsupported NumPy dtype"):
|
831
925
|
validate_full_roundtrip(value_u32, Vector[np.uint32, Literal[3]])
|
832
|
-
value_u64
|
926
|
+
value_u64 = np.array([1, 2, 3], dtype=np.uint64)
|
833
927
|
with pytest.raises(ValueError, match="Unsupported NumPy dtype"):
|
834
928
|
validate_full_roundtrip(value_u64, Vector[np.uint64, Literal[3]])
|
835
929
|
|
836
930
|
|
837
931
|
def test_roundtrip_vector_no_dimension() -> None:
|
838
932
|
"""Test full roundtrip for vector types without dimension annotation."""
|
839
|
-
value_f64
|
840
|
-
validate_full_roundtrip(
|
933
|
+
value_f64 = np.array([1.0, 2.0, 3.0], dtype=np.float64)
|
934
|
+
validate_full_roundtrip(
|
935
|
+
value_f64,
|
936
|
+
Vector[np.float64],
|
937
|
+
([1.0, 2.0, 3.0], list[float]),
|
938
|
+
(np.array([1.0, 2.0, 3.0], dtype=np.float64), np.typing.NDArray[np.float64]),
|
939
|
+
)
|
841
940
|
|
842
941
|
|
843
942
|
def test_roundtrip_string_vector() -> None:
|
@@ -862,9 +961,9 @@ def test_roundtrip_dimension_mismatch() -> None:
|
|
862
961
|
def test_full_roundtrip_scalar_numeric_types() -> None:
|
863
962
|
"""Test full roundtrip for scalar NumPy numeric types."""
|
864
963
|
# Test supported scalar types
|
865
|
-
validate_full_roundtrip(np.int64(42), np.int64)
|
866
|
-
validate_full_roundtrip(np.float32(3.
|
867
|
-
validate_full_roundtrip(np.float64(
|
964
|
+
validate_full_roundtrip(np.int64(42), np.int64, (42, int))
|
965
|
+
validate_full_roundtrip(np.float32(3.25), np.float32, (3.25, cocoindex.Float32))
|
966
|
+
validate_full_roundtrip(np.float64(3.25), np.float64, (3.25, cocoindex.Float64))
|
868
967
|
|
869
968
|
# Test unsupported scalar types
|
870
969
|
for unsupported_type in [np.int32, np.uint8, np.uint16, np.uint32, np.uint64]:
|
cocoindex/tests/test_typing.py
CHANGED
@@ -2,7 +2,7 @@ import dataclasses
|
|
2
2
|
import datetime
|
3
3
|
import uuid
|
4
4
|
from collections.abc import Mapping, Sequence
|
5
|
-
from typing import Annotated, Any,
|
5
|
+
from typing import Annotated, Any, Literal, NamedTuple, get_args, get_origin
|
6
6
|
|
7
7
|
import numpy as np
|
8
8
|
import pytest
|
@@ -162,10 +162,11 @@ def test_ndarray_any_dtype() -> None:
|
|
162
162
|
|
163
163
|
|
164
164
|
def test_list_of_primitives() -> None:
|
165
|
-
typ =
|
165
|
+
typ = list[str]
|
166
166
|
result = analyze_type_info(typ)
|
167
167
|
assert result == AnalyzedTypeInfo(
|
168
168
|
kind="Vector",
|
169
|
+
core_type=list[str],
|
169
170
|
vector_info=VectorInfo(dim=None),
|
170
171
|
elem_type=str,
|
171
172
|
key_type=None,
|
@@ -177,10 +178,11 @@ def test_list_of_primitives() -> None:
|
|
177
178
|
|
178
179
|
|
179
180
|
def test_list_of_structs() -> None:
|
180
|
-
typ =
|
181
|
+
typ = list[SimpleDataclass]
|
181
182
|
result = analyze_type_info(typ)
|
182
183
|
assert result == AnalyzedTypeInfo(
|
183
184
|
kind="LTable",
|
185
|
+
core_type=list[SimpleDataclass],
|
184
186
|
vector_info=None,
|
185
187
|
elem_type=SimpleDataclass,
|
186
188
|
key_type=None,
|
@@ -196,6 +198,7 @@ def test_sequence_of_int() -> None:
|
|
196
198
|
result = analyze_type_info(typ)
|
197
199
|
assert result == AnalyzedTypeInfo(
|
198
200
|
kind="Vector",
|
201
|
+
core_type=Sequence[int],
|
199
202
|
vector_info=VectorInfo(dim=None),
|
200
203
|
elem_type=int,
|
201
204
|
key_type=None,
|
@@ -207,10 +210,11 @@ def test_sequence_of_int() -> None:
|
|
207
210
|
|
208
211
|
|
209
212
|
def test_list_with_vector_info() -> None:
|
210
|
-
typ = Annotated[
|
213
|
+
typ = Annotated[list[int], VectorInfo(dim=5)]
|
211
214
|
result = analyze_type_info(typ)
|
212
215
|
assert result == AnalyzedTypeInfo(
|
213
216
|
kind="Vector",
|
217
|
+
core_type=list[int],
|
214
218
|
vector_info=VectorInfo(dim=5),
|
215
219
|
elem_type=int,
|
216
220
|
key_type=None,
|
@@ -222,10 +226,11 @@ def test_list_with_vector_info() -> None:
|
|
222
226
|
|
223
227
|
|
224
228
|
def test_dict_str_int() -> None:
|
225
|
-
typ =
|
229
|
+
typ = dict[str, int]
|
226
230
|
result = analyze_type_info(typ)
|
227
231
|
assert result == AnalyzedTypeInfo(
|
228
232
|
kind="KTable",
|
233
|
+
core_type=dict[str, int],
|
229
234
|
vector_info=None,
|
230
235
|
elem_type=(str, int),
|
231
236
|
key_type=None,
|
@@ -241,6 +246,7 @@ def test_mapping_str_dataclass() -> None:
|
|
241
246
|
result = analyze_type_info(typ)
|
242
247
|
assert result == AnalyzedTypeInfo(
|
243
248
|
kind="KTable",
|
249
|
+
core_type=Mapping[str, SimpleDataclass],
|
244
250
|
vector_info=None,
|
245
251
|
elem_type=(str, SimpleDataclass),
|
246
252
|
key_type=None,
|
@@ -256,6 +262,7 @@ def test_dataclass() -> None:
|
|
256
262
|
result = analyze_type_info(typ)
|
257
263
|
assert result == AnalyzedTypeInfo(
|
258
264
|
kind="Struct",
|
265
|
+
core_type=SimpleDataclass,
|
259
266
|
vector_info=None,
|
260
267
|
elem_type=None,
|
261
268
|
key_type=None,
|
@@ -271,6 +278,7 @@ def test_named_tuple() -> None:
|
|
271
278
|
result = analyze_type_info(typ)
|
272
279
|
assert result == AnalyzedTypeInfo(
|
273
280
|
kind="Struct",
|
281
|
+
core_type=SimpleNamedTuple,
|
274
282
|
vector_info=None,
|
275
283
|
elem_type=None,
|
276
284
|
key_type=None,
|
@@ -286,6 +294,7 @@ def test_tuple_key_value() -> None:
|
|
286
294
|
result = analyze_type_info(typ)
|
287
295
|
assert result == AnalyzedTypeInfo(
|
288
296
|
kind="Int64",
|
297
|
+
core_type=int,
|
289
298
|
vector_info=None,
|
290
299
|
elem_type=None,
|
291
300
|
key_type=str,
|
@@ -301,6 +310,7 @@ def test_str() -> None:
|
|
301
310
|
result = analyze_type_info(typ)
|
302
311
|
assert result == AnalyzedTypeInfo(
|
303
312
|
kind="Str",
|
313
|
+
core_type=str,
|
304
314
|
vector_info=None,
|
305
315
|
elem_type=None,
|
306
316
|
key_type=None,
|
@@ -316,6 +326,7 @@ def test_bool() -> None:
|
|
316
326
|
result = analyze_type_info(typ)
|
317
327
|
assert result == AnalyzedTypeInfo(
|
318
328
|
kind="Bool",
|
329
|
+
core_type=bool,
|
319
330
|
vector_info=None,
|
320
331
|
elem_type=None,
|
321
332
|
key_type=None,
|
@@ -331,6 +342,7 @@ def test_bytes() -> None:
|
|
331
342
|
result = analyze_type_info(typ)
|
332
343
|
assert result == AnalyzedTypeInfo(
|
333
344
|
kind="Bytes",
|
345
|
+
core_type=bytes,
|
334
346
|
vector_info=None,
|
335
347
|
elem_type=None,
|
336
348
|
key_type=None,
|
@@ -346,6 +358,7 @@ def test_uuid() -> None:
|
|
346
358
|
result = analyze_type_info(typ)
|
347
359
|
assert result == AnalyzedTypeInfo(
|
348
360
|
kind="Uuid",
|
361
|
+
core_type=uuid.UUID,
|
349
362
|
vector_info=None,
|
350
363
|
elem_type=None,
|
351
364
|
key_type=None,
|
@@ -361,6 +374,7 @@ def test_date() -> None:
|
|
361
374
|
result = analyze_type_info(typ)
|
362
375
|
assert result == AnalyzedTypeInfo(
|
363
376
|
kind="Date",
|
377
|
+
core_type=datetime.date,
|
364
378
|
vector_info=None,
|
365
379
|
elem_type=None,
|
366
380
|
key_type=None,
|
@@ -376,6 +390,7 @@ def test_time() -> None:
|
|
376
390
|
result = analyze_type_info(typ)
|
377
391
|
assert result == AnalyzedTypeInfo(
|
378
392
|
kind="Time",
|
393
|
+
core_type=datetime.time,
|
379
394
|
vector_info=None,
|
380
395
|
elem_type=None,
|
381
396
|
key_type=None,
|
@@ -391,6 +406,7 @@ def test_timedelta() -> None:
|
|
391
406
|
result = analyze_type_info(typ)
|
392
407
|
assert result == AnalyzedTypeInfo(
|
393
408
|
kind="TimeDelta",
|
409
|
+
core_type=datetime.timedelta,
|
394
410
|
vector_info=None,
|
395
411
|
elem_type=None,
|
396
412
|
key_type=None,
|
@@ -406,6 +422,7 @@ def test_float() -> None:
|
|
406
422
|
result = analyze_type_info(typ)
|
407
423
|
assert result == AnalyzedTypeInfo(
|
408
424
|
kind="Float64",
|
425
|
+
core_type=float,
|
409
426
|
vector_info=None,
|
410
427
|
elem_type=None,
|
411
428
|
key_type=None,
|
@@ -421,6 +438,7 @@ def test_int() -> None:
|
|
421
438
|
result = analyze_type_info(typ)
|
422
439
|
assert result == AnalyzedTypeInfo(
|
423
440
|
kind="Int64",
|
441
|
+
core_type=int,
|
424
442
|
vector_info=None,
|
425
443
|
elem_type=None,
|
426
444
|
key_type=None,
|
@@ -436,6 +454,7 @@ def test_type_with_attributes() -> None:
|
|
436
454
|
result = analyze_type_info(typ)
|
437
455
|
assert result == AnalyzedTypeInfo(
|
438
456
|
kind="Str",
|
457
|
+
core_type=str,
|
439
458
|
vector_info=None,
|
440
459
|
elem_type=None,
|
441
460
|
key_type=None,
|
@@ -472,7 +491,7 @@ def test_encode_enriched_type_vector() -> None:
|
|
472
491
|
|
473
492
|
|
474
493
|
def test_encode_enriched_type_ltable() -> None:
|
475
|
-
typ =
|
494
|
+
typ = list[SimpleDataclass]
|
476
495
|
result = encode_enriched_type(typ)
|
477
496
|
assert result["type"]["kind"] == "LTable"
|
478
497
|
assert result["type"]["row"]["kind"] == "Struct"
|
@@ -513,7 +532,7 @@ def test_invalid_struct_kind() -> None:
|
|
513
532
|
|
514
533
|
|
515
534
|
def test_invalid_list_kind() -> None:
|
516
|
-
typ = Annotated[
|
535
|
+
typ = Annotated[list[int], TypeKind("Struct")]
|
517
536
|
with pytest.raises(ValueError, match="Unexpected type kind for list: Struct"):
|
518
537
|
analyze_type_info(typ)
|
519
538
|
|
cocoindex/typing.py
CHANGED
@@ -150,6 +150,7 @@ class AnalyzedTypeInfo:
|
|
150
150
|
"""
|
151
151
|
|
152
152
|
kind: str
|
153
|
+
core_type: Any
|
153
154
|
vector_info: VectorInfo | None # For Vector
|
154
155
|
elem_type: ElementType | None # For Vector and Table
|
155
156
|
|
@@ -161,6 +162,7 @@ class AnalyzedTypeInfo:
|
|
161
162
|
|
162
163
|
attrs: dict[str, Any] | None
|
163
164
|
nullable: bool = False
|
165
|
+
union_variant_types: typing.List[ElementType] | None = None # For Union
|
164
166
|
|
165
167
|
|
166
168
|
def analyze_type_info(t: Any) -> AnalyzedTypeInfo:
|
@@ -181,18 +183,6 @@ def analyze_type_info(t: Any) -> AnalyzedTypeInfo:
|
|
181
183
|
if base_type is Annotated:
|
182
184
|
annotations = t.__metadata__
|
183
185
|
t = t.__origin__
|
184
|
-
elif base_type is types.UnionType:
|
185
|
-
possible_types = typing.get_args(t)
|
186
|
-
non_none_types = [
|
187
|
-
arg for arg in possible_types if arg not in (None, types.NoneType)
|
188
|
-
]
|
189
|
-
if len(non_none_types) != 1:
|
190
|
-
raise ValueError(
|
191
|
-
f"Expect exactly one non-None choice for Union type, but got {len(non_none_types)}: {t}"
|
192
|
-
)
|
193
|
-
t = non_none_types[0]
|
194
|
-
if len(possible_types) > 1:
|
195
|
-
nullable = True
|
196
186
|
else:
|
197
187
|
break
|
198
188
|
|
@@ -211,6 +201,7 @@ def analyze_type_info(t: Any) -> AnalyzedTypeInfo:
|
|
211
201
|
|
212
202
|
struct_type: type | None = None
|
213
203
|
elem_type: ElementType | None = None
|
204
|
+
union_variant_types: typing.List[ElementType] | None = None
|
214
205
|
key_type: type | None = None
|
215
206
|
np_number_type: type | None = None
|
216
207
|
if _is_struct_type(t):
|
@@ -251,6 +242,24 @@ def analyze_type_info(t: Any) -> AnalyzedTypeInfo:
|
|
251
242
|
args = typing.get_args(t)
|
252
243
|
elem_type = (args[0], args[1])
|
253
244
|
kind = "KTable"
|
245
|
+
elif base_type is types.UnionType:
|
246
|
+
possible_types = typing.get_args(t)
|
247
|
+
non_none_types = [
|
248
|
+
arg for arg in possible_types if arg not in (None, types.NoneType)
|
249
|
+
]
|
250
|
+
|
251
|
+
if len(non_none_types) == 0:
|
252
|
+
return analyze_type_info(None)
|
253
|
+
|
254
|
+
nullable = len(non_none_types) < len(possible_types)
|
255
|
+
|
256
|
+
if len(non_none_types) == 1:
|
257
|
+
result = analyze_type_info(non_none_types[0])
|
258
|
+
result.nullable = nullable
|
259
|
+
return result
|
260
|
+
|
261
|
+
kind = "Union"
|
262
|
+
union_variant_types = non_none_types
|
254
263
|
elif kind is None:
|
255
264
|
if t is bytes:
|
256
265
|
kind = "Bytes"
|
@@ -277,8 +286,10 @@ def analyze_type_info(t: Any) -> AnalyzedTypeInfo:
|
|
277
286
|
|
278
287
|
return AnalyzedTypeInfo(
|
279
288
|
kind=kind,
|
289
|
+
core_type=t,
|
280
290
|
vector_info=vector_info,
|
281
291
|
elem_type=elem_type,
|
292
|
+
union_variant_types=union_variant_types,
|
282
293
|
key_type=key_type,
|
283
294
|
struct_type=struct_type,
|
284
295
|
np_number_type=np_number_type,
|
@@ -338,6 +349,14 @@ def _encode_type(type_info: AnalyzedTypeInfo) -> dict[str, Any]:
|
|
338
349
|
encoded_type["element_type"] = _encode_type(elem_type_info)
|
339
350
|
encoded_type["dimension"] = type_info.vector_info.dim
|
340
351
|
|
352
|
+
elif type_info.kind == "Union":
|
353
|
+
if type_info.union_variant_types is None:
|
354
|
+
raise ValueError("Union type must have a variant type list")
|
355
|
+
encoded_type["types"] = [
|
356
|
+
_encode_type(analyze_type_info(typ))
|
357
|
+
for typ in type_info.union_variant_types
|
358
|
+
]
|
359
|
+
|
341
360
|
elif type_info.kind in TABLE_TYPES:
|
342
361
|
if type_info.elem_type is None:
|
343
362
|
raise ValueError(f"{type_info.kind} type must have an element type")
|
@@ -1,12 +1,13 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: cocoindex
|
3
|
-
Version: 0.1.
|
3
|
+
Version: 0.1.54
|
4
4
|
Requires-Dist: sentence-transformers>=3.3.1
|
5
5
|
Requires-Dist: click>=8.1.8
|
6
6
|
Requires-Dist: rich>=14.0.0
|
7
7
|
Requires-Dist: python-dotenv>=1.1.0
|
8
8
|
Requires-Dist: pytest ; extra == 'test'
|
9
9
|
Requires-Dist: ruff ; extra == 'dev'
|
10
|
+
Requires-Dist: pre-commit ; extra == 'dev'
|
10
11
|
Provides-Extra: test
|
11
12
|
Provides-Extra: dev
|
12
13
|
License-File: LICENSE
|
@@ -51,10 +52,10 @@ Unlike a workflow orchestration framework where data is usually opaque, in CocoI
|
|
51
52
|
|
52
53
|
```python
|
53
54
|
# import
|
54
|
-
data['content'] = flow_builder.add_source(...)
|
55
|
+
data['content'] = flow_builder.add_source(...)
|
55
56
|
|
56
57
|
# transform
|
57
|
-
data['out'] = data['content']
|
58
|
+
data['out'] = data['content']
|
58
59
|
.transform(...)
|
59
60
|
.transform(...)
|
60
61
|
|
@@ -75,17 +76,17 @@ As a data framework, CocoIndex takes it to the next level on data freshness. **I
|
|
75
76
|
The frameworks takes care of
|
76
77
|
- Change data capture.
|
77
78
|
- Figure out what exactly needs to be updated, and only updating that without having to recompute everything.
|
78
|
-
|
79
|
+
|
79
80
|
This makes it fast to reflect any source updates to the target store. If you have concerns with surfacing stale data to AI agents and are spending lots of efforts working on infra piece to optimize the latency, the framework actually handles it for you.
|
80
81
|
|
81
82
|
|
82
83
|
## Quick Start:
|
83
|
-
If you're new to CocoIndex, we recommend checking out
|
84
|
+
If you're new to CocoIndex, we recommend checking out
|
84
85
|
- 📖 [Documentation](https://cocoindex.io/docs)
|
85
86
|
- ⚡ [Quick Start Guide](https://cocoindex.io/docs/getting_started/quickstart)
|
86
|
-
- 🎬 [Quick Start Video Tutorial](https://youtu.be/gv5R8nOXsWU?si=9ioeKYkMEnYevTXT)
|
87
|
+
- 🎬 [Quick Start Video Tutorial](https://youtu.be/gv5R8nOXsWU?si=9ioeKYkMEnYevTXT)
|
87
88
|
|
88
|
-
### Setup
|
89
|
+
### Setup
|
89
90
|
|
90
91
|
1. Install CocoIndex Python library
|
91
92
|
|
@@ -155,8 +156,8 @@ It defines an index flow like this:
|
|
155
156
|
| [Google Drive Text Embedding](examples/gdrive_text_embedding) | Index text documents from Google Drive |
|
156
157
|
| [Docs to Knowledge Graph](examples/docs_to_knowledge_graph) | Extract relationships from Markdown documents and build a knowledge graph |
|
157
158
|
| [Embeddings to Qdrant](examples/text_embedding_qdrant) | Index documents in a Qdrant collection for semantic search |
|
158
|
-
| [FastAPI Server with Docker](examples/fastapi_server_docker) | Run the semantic search server in a Dockerized FastAPI setup |
|
159
|
-
| [Product Recommendation](examples/product_recommendation) | Build real-time product recommendations with LLM and graph database|
|
159
|
+
| [FastAPI Server with Docker](examples/fastapi_server_docker) | Run the semantic search server in a Dockerized FastAPI setup |
|
160
|
+
| [Product Recommendation](examples/product_recommendation) | Build real-time product recommendations with LLM and graph database|
|
160
161
|
| [Image Search with Vision API](examples/image_search) | Generates detailed captions for images using a vision model, embeds them, enables live-updating semantic search via FastAPI and served on a React frontend|
|
161
162
|
|
162
163
|
More coming and stay tuned 👀!
|
@@ -178,7 +179,7 @@ Join our community here:
|
|
178
179
|
- 📜 [Read our blog posts](https://cocoindex.io/blogs/)
|
179
180
|
|
180
181
|
## Support us:
|
181
|
-
We are constantly improving, and more features and examples are coming soon. If you love this project, please drop us a star ⭐ at GitHub repo [](https://github.com/cocoindex-io/cocoindex) to stay tuned and help us grow.
|
182
|
+
We are constantly improving, and more features and examples are coming soon. If you love this project, please drop us a star ⭐ at GitHub repo [](https://github.com/cocoindex-io/cocoindex) to stay tuned and help us grow.
|
182
183
|
|
183
184
|
## License
|
184
185
|
CocoIndex is Apache 2.0 licensed.
|
@@ -0,0 +1,28 @@
|
|
1
|
+
cocoindex-0.1.54.dist-info/METADATA,sha256=YhrfcjAPuh3OkyFCVB_tkaT_dY9NV7HMhOHIQVBqnCk,9907
|
2
|
+
cocoindex-0.1.54.dist-info/WHEEL,sha256=YLLGMgiebwxzWB63F0KVTBu1H1ad3TdbsHYfFKfk6fc,104
|
3
|
+
cocoindex-0.1.54.dist-info/entry_points.txt,sha256=_NretjYVzBdNTn7dK-zgwr7YfG2afz1u1uSE-5bZXF8,46
|
4
|
+
cocoindex-0.1.54.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
5
|
+
cocoindex/__init__.py,sha256=3potlGouaGAznMTEqU5QKuB934qpD1xR6ZH6EL3YMWw,1782
|
6
|
+
cocoindex/_engine.cpython-313-darwin.so,sha256=VwEk8aK1CW5YXpFr2tv46tLcD1DRCYamkYLrrBseNK0,57458240
|
7
|
+
cocoindex/auth_registry.py,sha256=1XqO7ibjmBBd8i11XSJTvTgdz8p1ptW-ZpuSgo_5zzk,716
|
8
|
+
cocoindex/cli.py,sha256=yXlUZqJuB9baofnpHFOu3S-0x0xGglmJ88nd9_T-fEs,18223
|
9
|
+
cocoindex/convert.py,sha256=4-a0uWLOfQ_e2OOwHjIYAsBMZIDRnGbK01Ye1E2ybIQ,10377
|
10
|
+
cocoindex/flow.py,sha256=djpGsQlSZV10OCS_81GY9k8q_0l-6MeismLnoF9XteE,30023
|
11
|
+
cocoindex/functions.py,sha256=Lh1aSovd6HaikAWvDi6dX0poyma1MqBX5S9FAzIR8c4,2622
|
12
|
+
cocoindex/index.py,sha256=j93B9jEvvLXHtpzKWL88SY6wCGEoPgpsQhEGHlyYGFg,540
|
13
|
+
cocoindex/lib.py,sha256=BeRUn3RqE_wSsVtsgCzbFFKe1LXgRyRmMOcmwWBuEXo,2940
|
14
|
+
cocoindex/llm.py,sha256=hpwvHjWiLkoV018TkC191rztq62NQeewwF3kDsHUols,430
|
15
|
+
cocoindex/op.py,sha256=Z7V9Fdz4qeTeozzKmp1Dk1lPUP0GBgVgD_vBEhTJS5Y,11810
|
16
|
+
cocoindex/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
17
|
+
cocoindex/runtime.py,sha256=bAdHYaXFWiiUWyAgzmKTeaAaRR0D_AmaqVCIdPO-v00,1056
|
18
|
+
cocoindex/setting.py,sha256=Zl8K86r8RVvG9c3pCsH0Ot8BHhDAQAQCjoBp7TnXMLQ,3590
|
19
|
+
cocoindex/setup.py,sha256=u5dYZFKfz4yZLiGHD0guNaR0s4zY9JAoZWrWHpAHw_0,773
|
20
|
+
cocoindex/sources.py,sha256=JCnOhv1w4o28e03i7yvo4ESicWYAhckkBg5bQlxNH4U,1330
|
21
|
+
cocoindex/targets.py,sha256=Nfh_tpFd1goTnS_cxBjIs4j9zl3Z4Z1JomAQ1dl3Sic,2796
|
22
|
+
cocoindex/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
23
|
+
cocoindex/tests/test_convert.py,sha256=RxbCmW3cSZQVJtAWZBBH9YNAViWVSi7u0JO8JGJl7M8,36174
|
24
|
+
cocoindex/tests/test_optional_database.py,sha256=snAmkNa6wtOSaxoZE1HgjvL5v_ylitt3Jt_9df4Cgdc,8506
|
25
|
+
cocoindex/tests/test_typing.py,sha256=t6UCYShcfonTfjBlGRWPiFGMZ8DGFfABXo6idekPoJE,14757
|
26
|
+
cocoindex/typing.py,sha256=kPMFVKs2i4SCLzW1Tn5NP_Ev9DAc-2qW6eJ68gpLexU,12580
|
27
|
+
cocoindex/utils.py,sha256=hUhX-XV6XGCtJSEIpBOuDv6VvqImwPlgBxztBTw7u0U,598
|
28
|
+
cocoindex-0.1.54.dist-info/RECORD,,
|
@@ -1,28 +0,0 @@
|
|
1
|
-
cocoindex-0.1.53.dist-info/METADATA,sha256=HQKpE-cc_Dgi2zpIZOAX8aVCl5Zt8hd__egLbAdlOSU,9874
|
2
|
-
cocoindex-0.1.53.dist-info/WHEEL,sha256=YLLGMgiebwxzWB63F0KVTBu1H1ad3TdbsHYfFKfk6fc,104
|
3
|
-
cocoindex-0.1.53.dist-info/entry_points.txt,sha256=_NretjYVzBdNTn7dK-zgwr7YfG2afz1u1uSE-5bZXF8,46
|
4
|
-
cocoindex-0.1.53.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
5
|
-
cocoindex/__init__.py,sha256=3potlGouaGAznMTEqU5QKuB934qpD1xR6ZH6EL3YMWw,1782
|
6
|
-
cocoindex/_engine.cpython-313-darwin.so,sha256=RNI4THwgDUk7SquPLUz81q0MH73WqAYDkESTApebEFU,57345008
|
7
|
-
cocoindex/auth_registry.py,sha256=1XqO7ibjmBBd8i11XSJTvTgdz8p1ptW-ZpuSgo_5zzk,716
|
8
|
-
cocoindex/cli.py,sha256=joSucqLibjZHs27fwNPzuMPGLeVJJZqaUbeSM-OnEyA,18223
|
9
|
-
cocoindex/convert.py,sha256=qP_LRTg_B8YPEeHprnX4kl-QV4ks0oqQzH7A1totZRA,9787
|
10
|
-
cocoindex/flow.py,sha256=uQKvIyWSysSdhNFI87QD6f2kbF-2R6zFMLZWBEk4rZU,30015
|
11
|
-
cocoindex/functions.py,sha256=9A61Jj5a3vQoI2MIAhjXvJrDxSzDhe6VncQWbiVtwcg,2393
|
12
|
-
cocoindex/index.py,sha256=j93B9jEvvLXHtpzKWL88SY6wCGEoPgpsQhEGHlyYGFg,540
|
13
|
-
cocoindex/lib.py,sha256=BeRUn3RqE_wSsVtsgCzbFFKe1LXgRyRmMOcmwWBuEXo,2940
|
14
|
-
cocoindex/llm.py,sha256=gbjAsD8Y9QZyICCQfSDZYQU2pIA6GqG4jKbRpbnQniA,408
|
15
|
-
cocoindex/op.py,sha256=Z7V9Fdz4qeTeozzKmp1Dk1lPUP0GBgVgD_vBEhTJS5Y,11810
|
16
|
-
cocoindex/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
17
|
-
cocoindex/runtime.py,sha256=bAdHYaXFWiiUWyAgzmKTeaAaRR0D_AmaqVCIdPO-v00,1056
|
18
|
-
cocoindex/setting.py,sha256=Zl8K86r8RVvG9c3pCsH0Ot8BHhDAQAQCjoBp7TnXMLQ,3590
|
19
|
-
cocoindex/setup.py,sha256=u5dYZFKfz4yZLiGHD0guNaR0s4zY9JAoZWrWHpAHw_0,773
|
20
|
-
cocoindex/sources.py,sha256=JCnOhv1w4o28e03i7yvo4ESicWYAhckkBg5bQlxNH4U,1330
|
21
|
-
cocoindex/targets.py,sha256=Nfh_tpFd1goTnS_cxBjIs4j9zl3Z4Z1JomAQ1dl3Sic,2796
|
22
|
-
cocoindex/tests/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
23
|
-
cocoindex/tests/test_convert.py,sha256=iDA4j-X_r1KeJgaa3osU7SyY8rBc57R0YVW8G4Z83YI,33235
|
24
|
-
cocoindex/tests/test_optional_database.py,sha256=snAmkNa6wtOSaxoZE1HgjvL5v_ylitt3Jt_9df4Cgdc,8506
|
25
|
-
cocoindex/tests/test_typing.py,sha256=jeZFUyzUTC6hdyo1uERhlKaKAiBKeKCrZ20OLGBkluo,14184
|
26
|
-
cocoindex/typing.py,sha256=yLtXdXEF0sYe3cMxTR__g39Gi286CnOKGI0T-hjaCrw,11999
|
27
|
-
cocoindex/utils.py,sha256=hUhX-XV6XGCtJSEIpBOuDv6VvqImwPlgBxztBTw7u0U,598
|
28
|
-
cocoindex-0.1.53.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|