cocoindex 0.1.25__cp311-cp311-macosx_11_0_arm64.whl → 0.1.26__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.
Binary file
cocoindex/cli.py CHANGED
@@ -4,6 +4,7 @@ import datetime
4
4
 
5
5
  from . import flow, lib
6
6
  from .setup import sync_setup, drop_setup, flow_names_with_setup, apply_setup_changes
7
+ from .runtime import execution_context
7
8
 
8
9
  @click.group()
9
10
  def cli():
@@ -113,11 +114,13 @@ def update(flow_name: str | None, live: bool, quiet: bool):
113
114
  Update the index to reflect the latest data from data sources.
114
115
  """
115
116
  options = flow.FlowLiveUpdaterOptions(live_mode=live, print_stats=not quiet)
116
- if flow_name is None:
117
- asyncio.run(flow.update_all_flows(options))
118
- else:
119
- updater = flow.FlowLiveUpdater(_flow_by_name(flow_name), options)
120
- asyncio.run(updater.wait())
117
+ async def _update():
118
+ if flow_name is None:
119
+ await flow.update_all_flows(options)
120
+ else:
121
+ updater = await flow.FlowLiveUpdater.create(_flow_by_name(flow_name), options)
122
+ await updater.wait()
123
+ execution_context.run(_update())
121
124
 
122
125
  @cli.command()
123
126
  @click.argument("flow_name", type=str, required=False)
@@ -167,7 +170,7 @@ def server(address: str, live_update: bool, quiet: bool, cors_origin: str | None
167
170
  lib.start_server(lib.ServerSettings(address=address, cors_origin=cors_origin))
168
171
  if live_update:
169
172
  options = flow.FlowLiveUpdaterOptions(live_mode=True, print_stats=not quiet)
170
- asyncio.run(flow.update_all_flows(options))
173
+ execution_context.run(flow.update_all_flows(options))
171
174
  input("Press Enter to stop...")
172
175
 
173
176
 
cocoindex/flow.py CHANGED
@@ -19,7 +19,7 @@ from . import index
19
19
  from . import op
20
20
  from .convert import dump_engine_object
21
21
  from .typing import encode_enriched_type
22
- from .runtime import op_execution_context
22
+ from .runtime import execution_context
23
23
 
24
24
  class _NameBuilder:
25
25
  _existing_names: set[str]
@@ -355,6 +355,12 @@ class FlowBuilder:
355
355
  name
356
356
  )
357
357
 
358
+ def declare(self, spec: op.DeclarationSpec):
359
+ """
360
+ Add a declaration to the flow.
361
+ """
362
+ self._state.engine_flow_builder.declare(dump_engine_object(spec))
363
+
358
364
  @dataclass
359
365
  class FlowLiveUpdaterOptions:
360
366
  """
@@ -369,16 +375,29 @@ class FlowLiveUpdater:
369
375
  """
370
376
  _engine_live_updater: _engine.FlowLiveUpdater
371
377
 
372
- def __init__(self, fl: Flow, options: FlowLiveUpdaterOptions | None = None):
373
- self._engine_live_updater = _engine.FlowLiveUpdater(
374
- fl._lazy_engine_flow(), dump_engine_object(options or FlowLiveUpdaterOptions()))
378
+ def __init__(self, arg: Flow | _engine.FlowLiveUpdater, options: FlowLiveUpdaterOptions | None = None):
379
+ if isinstance(arg, _engine.FlowLiveUpdater):
380
+ self._engine_live_updater = arg
381
+ else:
382
+ self._engine_live_updater = execution_context.run(_engine.FlowLiveUpdater(
383
+ arg.internal_flow(), dump_engine_object(options or FlowLiveUpdaterOptions())))
384
+
385
+ @staticmethod
386
+ async def create(fl: Flow, options: FlowLiveUpdaterOptions | None = None) -> FlowLiveUpdater:
387
+ """
388
+ Create a live updater for a flow.
389
+ """
390
+ engine_live_updater = await _engine.FlowLiveUpdater.create(
391
+ await fl.ainternal_flow(),
392
+ dump_engine_object(options or FlowLiveUpdaterOptions()))
393
+ return FlowLiveUpdater(engine_live_updater)
375
394
 
376
395
  def __enter__(self) -> FlowLiveUpdater:
377
396
  return self
378
397
 
379
398
  def __exit__(self, exc_type, exc_value, traceback):
380
399
  self.abort()
381
- asyncio.run(self.wait())
400
+ execution_context.run(self.wait())
382
401
 
383
402
  async def __aenter__(self) -> FlowLiveUpdater:
384
403
  return self
@@ -450,7 +469,7 @@ class Flow:
450
469
  Update the index defined by the flow.
451
470
  Once the function returns, the indice is fresh up to the moment when the function is called.
452
471
  """
453
- updater = FlowLiveUpdater(self, FlowLiveUpdaterOptions(live_mode=False))
472
+ updater = await FlowLiveUpdater.create(self, FlowLiveUpdaterOptions(live_mode=False))
454
473
  await updater.wait()
455
474
  return updater.update_stats()
456
475
 
@@ -466,6 +485,12 @@ class Flow:
466
485
  """
467
486
  return self._lazy_engine_flow()
468
487
 
488
+ async def ainternal_flow(self) -> _engine.Flow:
489
+ """
490
+ Get the engine flow. The async version.
491
+ """
492
+ return await asyncio.to_thread(self.internal_flow)
493
+
469
494
  def _create_lazy_flow(name: str | None, fl_def: Callable[[FlowBuilder, DataScope], None]) -> Flow:
470
495
  """
471
496
  Create a flow without really building it yet.
@@ -476,7 +501,7 @@ def _create_lazy_flow(name: str | None, fl_def: Callable[[FlowBuilder, DataScope
476
501
  root_scope = DataScope(
477
502
  flow_builder_state, flow_builder_state.engine_flow_builder.root_scope())
478
503
  fl_def(FlowBuilder(flow_builder_state), root_scope)
479
- return flow_builder_state.engine_flow_builder.build_flow(op_execution_context.event_loop)
504
+ return flow_builder_state.engine_flow_builder.build_flow(execution_context.event_loop)
480
505
 
481
506
  return Flow(_create_engine_flow)
482
507
 
@@ -523,17 +548,23 @@ def ensure_all_flows_built() -> None:
523
548
  """
524
549
  Ensure all flows are built.
525
550
  """
526
- with _flows_lock:
527
- for fl in _flows.values():
528
- fl.internal_flow()
551
+ for fl in flows():
552
+ fl.internal_flow()
553
+
554
+ async def aensure_all_flows_built() -> None:
555
+ """
556
+ Ensure all flows are built.
557
+ """
558
+ for fl in flows():
559
+ await fl.ainternal_flow()
529
560
 
530
561
  async def update_all_flows(options: FlowLiveUpdaterOptions) -> dict[str, _engine.IndexUpdateInfo]:
531
562
  """
532
563
  Update all flows.
533
564
  """
534
- ensure_all_flows_built()
565
+ await aensure_all_flows_built()
535
566
  async def _update_flow(fl: Flow) -> _engine.IndexUpdateInfo:
536
- updater = FlowLiveUpdater(fl, options)
567
+ updater = await FlowLiveUpdater.create(fl, options)
537
568
  await updater.wait()
538
569
  return updater.update_stats()
539
570
  fls = flows()
@@ -572,7 +603,7 @@ class TransientFlow:
572
603
  flow_builder_state.engine_flow_builder.set_direct_output(
573
604
  _data_slice_state(output).engine_data_slice)
574
605
  self._engine_flow = flow_builder_state.engine_flow_builder.build_transient_flow(
575
- op_execution_context.event_loop)
606
+ execution_context.event_loop)
576
607
 
577
608
  def __str__(self):
578
609
  return str(self._engine_flow)
cocoindex/lib.py CHANGED
@@ -101,7 +101,8 @@ def main_fn(
101
101
  try:
102
102
  if _should_run_cli():
103
103
  # Schedule to a separate thread as it invokes nested event loop.
104
- return await asyncio.to_thread(_run_cli)
104
+ # return await asyncio.to_thread(_run_cli)
105
+ return _run_cli()
105
106
  return await fn(*args, **kwargs)
106
107
  finally:
107
108
  stop()
cocoindex/llm.py CHANGED
@@ -5,6 +5,7 @@ class LlmApiType(Enum):
5
5
  """The type of LLM API to use."""
6
6
  OPENAI = "OpenAi"
7
7
  OLLAMA = "Ollama"
8
+ GEMINI = "Gemini"
8
9
 
9
10
  @dataclass
10
11
  class LlmSpec:
cocoindex/op.py CHANGED
@@ -7,7 +7,6 @@ import inspect
7
7
 
8
8
  from typing import get_type_hints, Protocol, Any, Callable, Awaitable, dataclass_transform
9
9
  from enum import Enum
10
- from functools import partial
11
10
 
12
11
  from .typing import encode_enriched_type
13
12
  from .convert import to_engine_value, make_engine_value_converter
@@ -18,7 +17,7 @@ class OpCategory(Enum):
18
17
  FUNCTION = "function"
19
18
  SOURCE = "source"
20
19
  STORAGE = "storage"
21
-
20
+ DECLARATION = "declaration"
22
21
  @dataclass_transform()
23
22
  class SpecMeta(type):
24
23
  """Meta class for spec classes."""
@@ -41,6 +40,8 @@ class FunctionSpec(metaclass=SpecMeta, category=OpCategory.FUNCTION): # pylint:
41
40
  class StorageSpec(metaclass=SpecMeta, category=OpCategory.STORAGE): # pylint: disable=too-few-public-methods
42
41
  """A storage spec. All its subclass can be instantiated similar to a dataclass, i.e. ClassName(field1=value1, field2=value2, ...)"""
43
42
 
43
+ class DeclarationSpec(metaclass=SpecMeta, category=OpCategory.DECLARATION): # pylint: disable=too-few-public-methods
44
+ """A declaration spec. All its subclass can be instantiated similar to a dataclass, i.e. ClassName(field1=value1, field2=value2, ...)"""
44
45
  class Executor(Protocol):
45
46
  """An executor for an operation."""
46
47
  op_category: OpCategory
cocoindex/runtime.py CHANGED
@@ -1,7 +1,12 @@
1
+ """
2
+ This module provides a standalone execution runtime for executing coroutines in a thread-safe
3
+ manner.
4
+ """
5
+
1
6
  import threading
2
7
  import asyncio
3
-
4
- class _OpExecutionContext:
8
+ from typing import Coroutine
9
+ class _ExecutionContext:
5
10
  _lock: threading.Lock
6
11
  _event_loop: asyncio.AbstractEventLoop | None = None
7
12
 
@@ -14,8 +19,11 @@ class _OpExecutionContext:
14
19
  with self._lock:
15
20
  if self._event_loop is None:
16
21
  self._event_loop = asyncio.new_event_loop()
17
- asyncio.set_event_loop(self._event_loop)
18
22
  threading.Thread(target=self._event_loop.run_forever, daemon=True).start()
19
23
  return self._event_loop
20
24
 
21
- op_execution_context = _OpExecutionContext()
25
+ def run(self, coro: Coroutine):
26
+ """Run a coroutine in the event loop, blocking until it finishes. Return its result."""
27
+ return asyncio.run_coroutine_threadsafe(coro, self.event_loop).result()
28
+
29
+ execution_context = _ExecutionContext()
cocoindex/storages.py CHANGED
@@ -43,8 +43,9 @@ class NodeReferenceMapping:
43
43
  fields: list[TargetFieldMapping]
44
44
 
45
45
  @dataclass
46
- class NodeStorageSpec:
46
+ class ReferencedNode:
47
47
  """Storage spec for a graph node."""
48
+ label: str
48
49
  primary_key_fields: Sequence[str]
49
50
  vector_indexes: Sequence[index.VectorIndexDef] = ()
50
51
 
@@ -63,10 +64,16 @@ class RelationshipMapping:
63
64
  rel_type: str
64
65
  source: NodeReferenceMapping
65
66
  target: NodeReferenceMapping
66
- nodes_storage_spec: dict[str, NodeStorageSpec] | None = None
67
67
 
68
68
  class Neo4j(op.StorageSpec):
69
69
  """Graph storage powered by Neo4j."""
70
70
 
71
71
  connection: AuthEntryReference
72
72
  mapping: NodeMapping | RelationshipMapping
73
+
74
+ class Neo4jDeclarations(op.DeclarationSpec):
75
+ """Declarations for Neo4j."""
76
+
77
+ kind = "Neo4j"
78
+ connection: AuthEntryReference
79
+ referenced_nodes: Sequence[ReferencedNode] = ()
@@ -1,15 +1,22 @@
1
1
  import dataclasses
2
2
  import uuid
3
3
  import datetime
4
- from dataclasses import dataclass
4
+ from dataclasses import dataclass, make_dataclass
5
5
  import pytest
6
+ from cocoindex.typing import encode_enriched_type
6
7
  from cocoindex.convert import to_engine_value
8
+ from cocoindex.convert import make_engine_value_converter
7
9
 
8
10
  @dataclass
9
11
  class Order:
10
12
  order_id: str
11
13
  name: str
12
14
  price: float
15
+ extra_field: str = "default_extra"
16
+
17
+ @dataclass
18
+ class Tag:
19
+ name: str
13
20
 
14
21
  @dataclass
15
22
  class Basket:
@@ -19,6 +26,21 @@ class Basket:
19
26
  class Customer:
20
27
  name: str
21
28
  order: Order
29
+ tags: list[Tag] = None
30
+
31
+ @dataclass
32
+ class NestedStruct:
33
+ customer: Customer
34
+ orders: list[Order]
35
+ count: int = 0
36
+
37
+ def build_engine_value_converter(engine_type_in_py, python_type=None):
38
+ """
39
+ Helper to build a converter for the given engine-side type (as represented in Python).
40
+ If python_type is not specified, uses engine_type_in_py as the target.
41
+ """
42
+ engine_type = encode_enriched_type(engine_type_in_py)["type"]
43
+ return make_engine_value_converter([], engine_type, python_type or engine_type_in_py)
22
44
 
23
45
  def test_to_engine_value_basic_types():
24
46
  assert to_engine_value(123) == 123
@@ -40,11 +62,11 @@ def test_to_engine_value_date_time_types():
40
62
 
41
63
  def test_to_engine_value_struct():
42
64
  order = Order(order_id="O123", name="mixed nuts", price=25.0)
43
- assert to_engine_value(order) == ["O123", "mixed nuts", 25.0]
65
+ assert to_engine_value(order) == ["O123", "mixed nuts", 25.0, "default_extra"]
44
66
 
45
67
  def test_to_engine_value_list_of_structs():
46
68
  orders = [Order("O1", "item1", 10.0), Order("O2", "item2", 20.0)]
47
- assert to_engine_value(orders) == [["O1", "item1", 10.0], ["O2", "item2", 20.0]]
69
+ assert to_engine_value(orders) == [["O1", "item1", 10.0, "default_extra"], ["O2", "item2", 20.0, "default_extra"]]
48
70
 
49
71
  def test_to_engine_value_struct_with_list():
50
72
  basket = Basket(items=["apple", "banana"])
@@ -52,7 +74,7 @@ def test_to_engine_value_struct_with_list():
52
74
 
53
75
  def test_to_engine_value_nested_struct():
54
76
  customer = Customer(name="Alice", order=Order("O1", "item1", 10.0))
55
- assert to_engine_value(customer) == ["Alice", ["O1", "item1", 10.0]]
77
+ assert to_engine_value(customer) == ["Alice", ["O1", "item1", 10.0, "default_extra"], None]
56
78
 
57
79
  def test_to_engine_value_empty_list():
58
80
  assert to_engine_value([]) == []
@@ -67,3 +89,146 @@ def test_to_engine_value_tuple():
67
89
 
68
90
  def test_to_engine_value_none():
69
91
  assert to_engine_value(None) is None
92
+
93
+ def test_make_engine_value_converter_basic_types():
94
+ for engine_type_in_py, value in [
95
+ (int, 42),
96
+ (float, 3.14),
97
+ (str, "hello"),
98
+ (bool, True),
99
+ # (type(None), None), # Removed unsupported NoneType
100
+ ]:
101
+ converter = build_engine_value_converter(engine_type_in_py)
102
+ assert converter(value) == value
103
+
104
+ @pytest.mark.parametrize(
105
+ "converter_type, engine_val, expected",
106
+ [
107
+ # All fields match
108
+ (Order, ["O123", "mixed nuts", 25.0, "default_extra"], Order("O123", "mixed nuts", 25.0, "default_extra")),
109
+ # Extra field in engine value (should ignore extra)
110
+ (Order, ["O123", "mixed nuts", 25.0, "default_extra", "unexpected"], Order("O123", "mixed nuts", 25.0, "default_extra")),
111
+ # Fewer fields in engine value (should fill with default)
112
+ (Order, ["O123", "mixed nuts", 0.0, "default_extra"], Order("O123", "mixed nuts", 0.0, "default_extra")),
113
+ # More fields in engine value (should ignore extra)
114
+ (Order, ["O123", "mixed nuts", 25.0, "unexpected"], Order("O123", "mixed nuts", 25.0, "unexpected")),
115
+ # Truly extra field (should ignore the fifth field)
116
+ (Order, ["O123", "mixed nuts", 25.0, "default_extra", "ignored"], Order("O123", "mixed nuts", 25.0, "default_extra")),
117
+ # Missing optional field in engine value (tags=None)
118
+ (Customer, ["Alice", ["O1", "item1", 10.0, "default_extra"], None], Customer("Alice", Order("O1", "item1", 10.0, "default_extra"), None)),
119
+ # Extra field in engine value for Customer (should ignore)
120
+ (Customer, ["Alice", ["O1", "item1", 10.0, "default_extra"], [["vip"]], "extra"], Customer("Alice", Order("O1", "item1", 10.0, "default_extra"), [Tag("vip")])),
121
+ ]
122
+ )
123
+ def test_struct_conversion_cases(converter_type, engine_val, expected):
124
+ converter = build_engine_value_converter(converter_type)
125
+ assert converter(engine_val) == expected
126
+
127
+ def test_make_engine_value_converter_collections():
128
+ # List of structs
129
+ converter = build_engine_value_converter(list[Order])
130
+ engine_val = [
131
+ ["O1", "item1", 10.0, "default_extra"],
132
+ ["O2", "item2", 20.0, "default_extra"]
133
+ ]
134
+ assert converter(engine_val) == [Order("O1", "item1", 10.0, "default_extra"), Order("O2", "item2", 20.0, "default_extra")]
135
+ # Struct with list field
136
+ converter = build_engine_value_converter(Customer)
137
+ engine_val = ["Alice", ["O1", "item1", 10.0, "default_extra"], [["vip"], ["premium"]]]
138
+ assert converter(engine_val) == Customer("Alice", Order("O1", "item1", 10.0, "default_extra"), [Tag("vip"), Tag("premium")])
139
+ # Struct with struct field
140
+ converter = build_engine_value_converter(NestedStruct)
141
+ engine_val = [
142
+ ["Alice", ["O1", "item1", 10.0, "default_extra"], [["vip"]]],
143
+ [["O1", "item1", 10.0, "default_extra"], ["O2", "item2", 20.0, "default_extra"]],
144
+ 2
145
+ ]
146
+ assert converter(engine_val) == NestedStruct(
147
+ Customer("Alice", Order("O1", "item1", 10.0, "default_extra"), [Tag("vip")]),
148
+ [Order("O1", "item1", 10.0, "default_extra"), Order("O2", "item2", 20.0, "default_extra")],
149
+ 2
150
+ )
151
+
152
+ def make_engine_order(fields):
153
+ return make_dataclass('EngineOrder', fields)
154
+
155
+ def make_python_order(fields, defaults=None):
156
+ if defaults is None:
157
+ defaults = {}
158
+ # Move all fields with defaults to the end (Python dataclass requirement)
159
+ non_default_fields = [(n, t) for n, t in fields if n not in defaults]
160
+ default_fields = [(n, t) for n, t in fields if n in defaults]
161
+ ordered_fields = non_default_fields + default_fields
162
+ # Prepare the namespace for defaults (only for fields at the end)
163
+ namespace = {k: defaults[k] for k, _ in default_fields}
164
+ return make_dataclass('PythonOrder', ordered_fields, namespace=namespace)
165
+
166
+ @pytest.mark.parametrize(
167
+ "engine_fields, python_fields, python_defaults, engine_val, expected_python_val",
168
+ [
169
+ # Extra field in Python (middle)
170
+ (
171
+ [("id", str), ("name", str)],
172
+ [("id", str), ("price", float), ("name", str)],
173
+ {"price": 0.0},
174
+ ["O123", "mixed nuts"],
175
+ ("O123", 0.0, "mixed nuts"),
176
+ ),
177
+ # Missing field in Python (middle)
178
+ (
179
+ [("id", str), ("price", float), ("name", str)],
180
+ [("id", str), ("name", str)],
181
+ {},
182
+ ["O123", 25.0, "mixed nuts"],
183
+ ("O123", "mixed nuts"),
184
+ ),
185
+ # Extra field in Python (start)
186
+ (
187
+ [("name", str), ("price", float)],
188
+ [("extra", str), ("name", str), ("price", float)],
189
+ {"extra": "default"},
190
+ ["mixed nuts", 25.0],
191
+ ("default", "mixed nuts", 25.0),
192
+ ),
193
+ # Missing field in Python (start)
194
+ (
195
+ [("extra", str), ("name", str), ("price", float)],
196
+ [("name", str), ("price", float)],
197
+ {},
198
+ ["unexpected", "mixed nuts", 25.0],
199
+ ("mixed nuts", 25.0),
200
+ ),
201
+ # Field order difference (should map by name)
202
+ (
203
+ [("id", str), ("name", str), ("price", float)],
204
+ [("name", str), ("id", str), ("price", float), ("extra", str)],
205
+ {"extra": "default"},
206
+ ["O123", "mixed nuts", 25.0],
207
+ ("mixed nuts", "O123", 25.0, "default"),
208
+ ),
209
+ # Extra field (Python has extra field with default)
210
+ (
211
+ [("id", str), ("name", str)],
212
+ [("id", str), ("name", str), ("price", float)],
213
+ {"price": 0.0},
214
+ ["O123", "mixed nuts"],
215
+ ("O123", "mixed nuts", 0.0),
216
+ ),
217
+ # Missing field (Engine has extra field)
218
+ (
219
+ [("id", str), ("name", str), ("price", float)],
220
+ [("id", str), ("name", str)],
221
+ {},
222
+ ["O123", "mixed nuts", 25.0],
223
+ ("O123", "mixed nuts"),
224
+ ),
225
+ ]
226
+ )
227
+ def test_field_position_cases(engine_fields, python_fields, python_defaults, engine_val, expected_python_val):
228
+ EngineOrder = make_engine_order(engine_fields)
229
+ PythonOrder = make_python_order(python_fields, python_defaults)
230
+ converter = build_engine_value_converter(EngineOrder, PythonOrder)
231
+ # Map field names to expected values
232
+ expected_dict = dict(zip([f[0] for f in python_fields], expected_python_val))
233
+ # Instantiate using keyword arguments (order doesn't matter)
234
+ assert converter(engine_val) == PythonOrder(**expected_dict)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cocoindex
3
- Version: 0.1.25
3
+ Version: 0.1.26
4
4
  Requires-Dist: sentence-transformers>=3.3.1
5
5
  Requires-Dist: click>=8.1.8
6
6
  Requires-Dist: pytest ; extra == 'test'
@@ -117,7 +117,7 @@ Go to the [examples directory](examples) to try out with any of the examples, fo
117
117
  | [PDF Embedding](examples/pdf_embedding) | Parse PDF and index text embeddings for semantic search |
118
118
  | [Manuals LLM Extraction](examples/manuals_llm_extraction) | Extract structured information from a manual using LLM |
119
119
  | [Google Drive Text Embedding](examples/gdrive_text_embedding) | Index text documents from Google Drive |
120
- | [Docs to Knowledge Graph](examples/docs_to_kg) | Extract relationships from Markdown documents and build a knowledge graph |
120
+ | [Docs to Knowledge Graph](examples/docs_to_knowledge_graph) | Extract relationships from Markdown documents and build a knowledge graph |
121
121
  | [Embeddings to Qdrant](examples/text_embedding_qdrant) | Index documents in a Qdrant collection for semantic search |
122
122
 
123
123
  More coming and stay tuned! If there's any specific examples you would like to see, please let us know in our [Discord community](https://discord.com/invite/zpA9S2DR7s) 🌱.
@@ -0,0 +1,24 @@
1
+ cocoindex-0.1.26.dist-info/METADATA,sha256=BwpB45xAUpYFZugav3l9u1uJ_0s4Kdrnp-Y2FnSJZ0A,8079
2
+ cocoindex-0.1.26.dist-info/WHEEL,sha256=wsVBlw9xyAuHecZeOYqJ_tA7emUKfXYOn-_180uZRi4,104
3
+ cocoindex-0.1.26.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
4
+ cocoindex/functions.py,sha256=xcAeRQTy9JObfxpjyMn-dPY2y7XhVWjB7759xVyup6o,1657
5
+ cocoindex/query.py,sha256=XsVY5cBJJ3a70qazkcCHjWZLE1zBqzMQ4HVSulicGMA,3273
6
+ cocoindex/index.py,sha256=LssEOuZi6AqhwKtZM3QFeQpa9T-0ELi8G5DsrYKECvc,534
7
+ cocoindex/lib.py,sha256=48nfWSg5IMzTSkVxdrWF8d9Hi-Bw8in_2rs7rQRwAs8,3505
8
+ cocoindex/auth_registry.py,sha256=lZ2rD5_9aC_UpGk7t4TmSYal_rjN7eHgO4_sU7FR0Zw,620
9
+ cocoindex/convert.py,sha256=tzlHadc-SaZCRBWxZEp08T4clJQPab_eXt6mUub0iQQ,5017
10
+ cocoindex/tests/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
11
+ cocoindex/tests/test_convert.py,sha256=mT_7HhXRu1PzGFbdmPmrq3O5-bPyDDG7mbr-mHaa2i0,9339
12
+ cocoindex/__init__.py,sha256=f4LTPg4db7Wm3QO9HirvhsT11OVykiFxGbt1JK6taFA,572
13
+ cocoindex/flow.py,sha256=1Mx-rYBzPIlFLNsiNVGhPtJKy2u6stZT1xjyPzERbFI,21068
14
+ cocoindex/llm.py,sha256=4b20wpSHcgfDM7tdxRm1KIo_7C30nT7h0gCsWvs686I,320
15
+ cocoindex/runtime.py,sha256=jqRnWkkIlAhE04gi4y0Y5bzuq9FX4j0aVNU-nengLJk,980
16
+ cocoindex/op.py,sha256=zOQzgnVDvET8LtUt7TW8PfHMhaA0eAXoZ3c_EsL6jtU,10602
17
+ cocoindex/sources.py,sha256=wZFU8lwSXjyofJR-syySH9fTyPnBlAPJ6-1hQNX8fGA,936
18
+ cocoindex/setup.py,sha256=W1HshwYk_K2aeLOVn_e62ZOXBO9yWsoUboRiH4SjF48,496
19
+ cocoindex/cli.py,sha256=MvEUbQVrJy-sYbGQNsqIaMJvcQXQn1OQVNues22Hph0,7061
20
+ cocoindex/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
21
+ cocoindex/typing.py,sha256=4mP9VXS75s3VMfF1LDc1LXsBng7uGdR5aD73N8iaeSM,7282
22
+ cocoindex/storages.py,sha256=GRHkmwuSAU7neF3H0pjAPfeEkmtXv-DJc7CKYjcATvE,1946
23
+ cocoindex/_engine.cpython-311-darwin.so,sha256=dE-o616jWjBbhjVm5UV-OzqI24h-IDitUp9io_ys29s,59305536
24
+ cocoindex-0.1.26.dist-info/RECORD,,
@@ -1,24 +0,0 @@
1
- cocoindex-0.1.25.dist-info/METADATA,sha256=PX5VOu90kauphEVYmZz8mKL5zzC_9pkdpLCCTU-0RmE,8066
2
- cocoindex-0.1.25.dist-info/WHEEL,sha256=wsVBlw9xyAuHecZeOYqJ_tA7emUKfXYOn-_180uZRi4,104
3
- cocoindex-0.1.25.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
4
- cocoindex/functions.py,sha256=xcAeRQTy9JObfxpjyMn-dPY2y7XhVWjB7759xVyup6o,1657
5
- cocoindex/query.py,sha256=XsVY5cBJJ3a70qazkcCHjWZLE1zBqzMQ4HVSulicGMA,3273
6
- cocoindex/index.py,sha256=LssEOuZi6AqhwKtZM3QFeQpa9T-0ELi8G5DsrYKECvc,534
7
- cocoindex/lib.py,sha256=GwSsbUCTTzikQRQSIRCDEpgYk6FBjbjmsy3NtQpeOl0,3461
8
- cocoindex/auth_registry.py,sha256=lZ2rD5_9aC_UpGk7t4TmSYal_rjN7eHgO4_sU7FR0Zw,620
9
- cocoindex/convert.py,sha256=tzlHadc-SaZCRBWxZEp08T4clJQPab_eXt6mUub0iQQ,5017
10
- cocoindex/tests/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
11
- cocoindex/tests/test_convert.py,sha256=wSAiskmBgBM5UZussbNXmCxt47hHGlSEEQVgDZaY4TE,2058
12
- cocoindex/__init__.py,sha256=f4LTPg4db7Wm3QO9HirvhsT11OVykiFxGbt1JK6taFA,572
13
- cocoindex/flow.py,sha256=pxLUWayN1hIJvxlrPJmJToUwGZAuV9it7DzhURGqDco,19973
14
- cocoindex/llm.py,sha256=uHXub9AWTOtxNyTaefHY-VuY_yzo6ikM1kUxHsQn-zw,298
15
- cocoindex/runtime.py,sha256=cByhaMWiOsejdsVa2WQ-79hlKLKqlDGJtcsDivKGGfY,692
16
- cocoindex/op.py,sha256=UXaurZrykiViu0p05wjzDuPvK0q6_Mu71zbcuYu2U8s,10343
17
- cocoindex/sources.py,sha256=wZFU8lwSXjyofJR-syySH9fTyPnBlAPJ6-1hQNX8fGA,936
18
- cocoindex/setup.py,sha256=W1HshwYk_K2aeLOVn_e62ZOXBO9yWsoUboRiH4SjF48,496
19
- cocoindex/cli.py,sha256=jRwGCPuqkBz_cIp7LKARCRAiDsPm91bsduKzfYJohJ4,6931
20
- cocoindex/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
21
- cocoindex/typing.py,sha256=4mP9VXS75s3VMfF1LDc1LXsBng7uGdR5aD73N8iaeSM,7282
22
- cocoindex/storages.py,sha256=fj8YJPEYSVmHc5DLQ-UpR0lfxFXD-rUBQF3RVlb1NcY,1810
23
- cocoindex/_engine.cpython-311-darwin.so,sha256=RaGHeVL1ILG-B5qwijOH4EJNYQLv3Wp2-zxPr2eBHyU,59012720
24
- cocoindex-0.1.25.dist-info/RECORD,,