cocoindex 0.1.28__cp312-cp312-win_amd64.whl → 0.1.30__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.
Binary file
@@ -3,16 +3,19 @@ Auth registry is used to register and reference auth entries.
3
3
  """
4
4
 
5
5
  from dataclasses import dataclass
6
+ from typing import Generic, TypeVar
6
7
 
7
8
  from . import _engine
8
9
  from .convert import dump_engine_object
9
10
 
11
+ T = TypeVar("T")
12
+
10
13
  @dataclass
11
- class AuthEntryReference:
14
+ class AuthEntryReference(Generic[T]):
12
15
  """Reference an auth entry by its key."""
13
16
  key: str
14
17
 
15
- def add_auth_entry(key: str, value) -> AuthEntryReference:
18
+ def add_auth_entry(key: str, value: T) -> AuthEntryReference[T]:
16
19
  """Add an auth entry to the registry. Returns its reference."""
17
20
  _engine.add_auth_entry(key, dump_engine_object(value))
18
21
  return AuthEntryReference(key)
cocoindex/cli.py CHANGED
@@ -1,8 +1,9 @@
1
- import asyncio
2
1
  import click
3
2
  import datetime
4
3
 
5
- from . import flow, lib
4
+ from rich.console import Console
5
+
6
+ from . import flow, lib, setting
6
7
  from .setup import sync_setup, drop_setup, flow_names_with_setup, apply_setup_changes
7
8
  from .runtime import execution_context
8
9
 
@@ -20,7 +21,7 @@ def ls(show_all: bool):
20
21
  """
21
22
  List all flows.
22
23
  """
23
- current_flow_names = [fl.name for fl in flow.flows()]
24
+ current_flow_names = flow.flow_names()
24
25
  persisted_flow_names = flow_names_with_setup()
25
26
  remaining_persisted_flow_names = set(persisted_flow_names)
26
27
 
@@ -52,11 +53,14 @@ def ls(show_all: bool):
52
53
 
53
54
  @cli.command()
54
55
  @click.argument("flow_name", type=str, required=False)
55
- def show(flow_name: str | None):
56
+ @click.option("--color/--no-color", default=True)
57
+ def show(flow_name: str | None, color: bool):
56
58
  """
57
- Show the flow spec.
59
+ Show the flow spec in a readable format with colored output.
58
60
  """
59
- click.echo(str(_flow_by_name(flow_name)))
61
+ fl = _flow_by_name(flow_name)
62
+ console = Console(no_color=not color)
63
+ console.print(fl._render_text())
60
64
 
61
65
  @cli.command()
62
66
  def setup():
@@ -145,32 +149,59 @@ def evaluate(flow_name: str | None, output_dir: str | None, cache: bool = True):
145
149
  options = flow.EvaluateAndDumpOptions(output_dir=output_dir, use_cache=cache)
146
150
  fl.evaluate_and_dump(options)
147
151
 
148
- _default_server_settings = lib.ServerSettings.from_env()
152
+ # Create ServerSettings lazily upon first call, as environment variables may be loaded from files, etc.
153
+ COCOINDEX_HOST = 'https://cocoindex.io'
149
154
 
150
155
  @cli.command()
151
156
  @click.option(
152
- "-a", "--address", type=str, default=_default_server_settings.address,
153
- help="The address to bind the server to, in the format of IP:PORT.")
157
+ "-a", "--address", type=str,
158
+ help="The address to bind the server to, in the format of IP:PORT. "
159
+ "If unspecified, the address specified in COCOINDEX_SERVER_ADDRESS will be used.")
160
+ @click.option(
161
+ "-c", "--cors-origin", type=str,
162
+ help="The origins of the clients (e.g. CocoInsight UI) to allow CORS from. "
163
+ "Multiple origins can be specified as a comma-separated list. "
164
+ "e.g. `https://cocoindex.io,http://localhost:3000`. "
165
+ "Origins specified in COCOINDEX_SERVER_CORS_ORIGINS will also be included.")
166
+ @click.option(
167
+ "-ci", "--cors-cocoindex", is_flag=True, show_default=True, default=False,
168
+ help=f"Allow {COCOINDEX_HOST} to access the server.")
154
169
  @click.option(
155
- "-c", "--cors-origin", type=str, default=_default_server_settings.cors_origin,
156
- help="The origin of the client (e.g. CocoInsight UI) to allow CORS from. "
157
- "e.g. `http://cocoindex.io` if you want to allow CocoInsight to access the server.")
170
+ "-cl", "--cors-local", type=int,
171
+ help="Allow http://localhost:<port> to access the server.")
158
172
  @click.option(
159
173
  "-L", "--live-update", is_flag=True, show_default=True, default=False,
160
174
  help="Continuously watch changes from data sources and apply to the target index.")
161
175
  @click.option(
162
176
  "-q", "--quiet", is_flag=True, show_default=True, default=False,
163
177
  help="Avoid printing anything to the standard output, e.g. statistics.")
164
- def server(address: str, live_update: bool, quiet: bool, cors_origin: str | None):
178
+ def server(address: str | None, live_update: bool, quiet: bool, cors_origin: str | None,
179
+ cors_cocoindex: bool, cors_local: int | None):
165
180
  """
166
181
  Start a HTTP server providing REST APIs.
167
182
 
168
183
  It will allow tools like CocoInsight to access the server.
169
184
  """
170
- lib.start_server(lib.ServerSettings(address=address, cors_origin=cors_origin))
185
+ server_settings = setting.ServerSettings.from_env()
186
+ cors_origins: set[str] = set(server_settings.cors_origins or [])
187
+ if cors_origin is not None:
188
+ cors_origins.update(setting.ServerSettings.parse_cors_origins(cors_origin))
189
+ if cors_cocoindex:
190
+ cors_origins.add(COCOINDEX_HOST)
191
+ if cors_local is not None:
192
+ cors_origins.add(f"http://localhost:{cors_local}")
193
+ server_settings.cors_origins = list(cors_origins)
194
+
195
+ if address is not None:
196
+ server_settings.address = address
197
+
198
+ lib.start_server(server_settings)
199
+
171
200
  if live_update:
172
201
  options = flow.FlowLiveUpdaterOptions(live_mode=True, print_stats=not quiet)
173
202
  execution_context.run(flow.update_all_flows(options))
203
+ if COCOINDEX_HOST in cors_origins:
204
+ click.echo(f"Open CocoInsight at: {COCOINDEX_HOST}/cocoinsight")
174
205
  input("Press Enter to stop...")
175
206
 
176
207
 
cocoindex/flow.py CHANGED
@@ -8,11 +8,14 @@ import asyncio
8
8
  import re
9
9
  import inspect
10
10
  import datetime
11
+ import json
11
12
 
12
13
  from typing import Any, Callable, Sequence, TypeVar
13
14
  from threading import Lock
14
15
  from enum import Enum
15
16
  from dataclasses import dataclass
17
+ from rich.text import Text
18
+ from rich.console import Console
16
19
 
17
20
  from . import _engine
18
21
  from . import index
@@ -451,8 +454,58 @@ class Flow:
451
454
  return engine_flow
452
455
  self._lazy_engine_flow = _lazy_engine_flow
453
456
 
457
+ def _format_flow(self, flow_dict: dict) -> Text:
458
+ output = Text()
459
+
460
+ def add_line(content, indent=0, style=None, end="\n"):
461
+ output.append(" " * indent)
462
+ output.append(content, style=style)
463
+ output.append(end)
464
+
465
+ def format_key_value(key, value, indent):
466
+ if isinstance(value, (dict, list)):
467
+ add_line(f"- {key}:", indent, style="green")
468
+ format_data(value, indent + 2)
469
+ else:
470
+ add_line(f"- {key}:", indent, style="green", end="")
471
+ add_line(f" {value}", style="yellow")
472
+
473
+ def format_data(data, indent=0):
474
+ if isinstance(data, dict):
475
+ for key, value in data.items():
476
+ format_key_value(key, value, indent)
477
+ elif isinstance(data, list):
478
+ for i, item in enumerate(data):
479
+ format_key_value(f"[{i}]", item, indent)
480
+ else:
481
+ add_line(str(data), indent, style="yellow")
482
+
483
+ # Header
484
+ flow_name = flow_dict.get("name", "Unnamed")
485
+ add_line(f"Flow: {flow_name}", style="bold cyan")
486
+
487
+ # Section
488
+ for section_title, section_key in [
489
+ ("Sources:", "import_ops"),
490
+ ("Processing:", "reactive_ops"),
491
+ ("Targets:", "export_ops"),
492
+ ]:
493
+ add_line("")
494
+ add_line(section_title, style="bold cyan")
495
+ format_data(flow_dict.get(section_key, []), indent=0)
496
+
497
+ return output
498
+
499
+ def _render_text(self) -> Text:
500
+ flow_spec_str = str(self._lazy_engine_flow())
501
+ try:
502
+ flow_dict = json.loads(flow_spec_str)
503
+ return self._format_flow(flow_dict)
504
+ except json.JSONDecodeError:
505
+ return Text(flow_spec_str)
506
+
454
507
  def __str__(self):
455
- return str(self._lazy_engine_flow())
508
+ return str(self._render_text())
456
509
 
457
510
  def __repr__(self):
458
511
  return repr(self._lazy_engine_flow())
cocoindex/functions.py CHANGED
@@ -1,10 +1,13 @@
1
1
  """All builtin functions."""
2
- from typing import Annotated, Any
2
+ from typing import Annotated, Any, TYPE_CHECKING
3
3
 
4
- import sentence_transformers
5
4
  from .typing import Float32, Vector, TypeAttr
6
5
  from . import op, llm
7
6
 
7
+ # Libraries that are heavy to import. Lazily import them later.
8
+ if TYPE_CHECKING:
9
+ import sentence_transformers
10
+
8
11
  class ParseJson(op.FunctionSpec):
9
12
  """Parse a text into a JSON object."""
10
13
 
@@ -35,9 +38,10 @@ class SentenceTransformerEmbedExecutor:
35
38
  """Executor for SentenceTransformerEmbed."""
36
39
 
37
40
  spec: SentenceTransformerEmbed
38
- _model: sentence_transformers.SentenceTransformer
41
+ _model: "sentence_transformers.SentenceTransformer"
39
42
 
40
43
  def analyze(self, text):
44
+ import sentence_transformers # pylint: disable=import-outside-toplevel
41
45
  args = self.spec.args or {}
42
46
  self._model = sentence_transformers.SentenceTransformer(self.spec.model, **args)
43
47
  dim = self._model.get_sentence_embedding_dimension()
cocoindex/lib.py CHANGED
@@ -1,76 +1,23 @@
1
1
  """
2
2
  Library level functions and states.
3
3
  """
4
- import os
5
4
  import sys
6
5
  import functools
7
6
  import inspect
8
7
 
9
- from typing import Callable, Self
10
- from dataclasses import dataclass
8
+ from typing import Callable
11
9
 
12
10
  from . import _engine
13
- from . import flow, query, cli
11
+ from . import flow, query, cli, setting
14
12
  from .convert import dump_engine_object
15
13
 
16
14
 
17
- def _load_field(target: dict[str, str], name: str, env_name: str, required: bool = False):
18
- value = os.getenv(env_name)
19
- if value is None:
20
- if required:
21
- raise ValueError(f"{env_name} is not set")
22
- else:
23
- target[name] = value
24
-
25
- @dataclass
26
- class DatabaseConnectionSpec:
27
- url: str
28
- user: str | None = None
29
- password: str | None = None
30
-
31
- @dataclass
32
- class Settings:
33
- """Settings for the cocoindex library."""
34
- database: DatabaseConnectionSpec
35
-
36
- @classmethod
37
- def from_env(cls) -> Self:
38
- """Load settings from environment variables."""
39
-
40
- db_kwargs: dict[str, str] = dict()
41
- _load_field(db_kwargs, "url", "COCOINDEX_DATABASE_URL", required=True)
42
- _load_field(db_kwargs, "user", "COCOINDEX_DATABASE_USER")
43
- _load_field(db_kwargs, "password", "COCOINDEX_DATABASE_PASSWORD")
44
- database = DatabaseConnectionSpec(**db_kwargs)
45
- return cls(database=database)
46
-
47
-
48
- def init(settings: Settings):
15
+ def init(settings: setting.Settings):
49
16
  """Initialize the cocoindex library."""
50
17
  _engine.init(dump_engine_object(settings))
51
18
 
52
- @dataclass
53
- class ServerSettings:
54
- """Settings for the cocoindex server."""
55
-
56
- # The address to bind the server to.
57
- address: str = "127.0.0.1:8080"
58
-
59
- # The origin of the client (e.g. CocoInsight UI) to allow CORS from.
60
- cors_origin: str | None = None
61
-
62
- @classmethod
63
- def from_env(cls) -> Self:
64
- """Load settings from environment variables."""
65
-
66
- kwargs: dict[str, str] = dict()
67
- _load_field(kwargs, "address", "COCOINDEX_SERVER_ADDRESS")
68
- _load_field(kwargs, "cors_origin", "COCOINDEX_SERVER_CORS_ORIGIN")
69
-
70
- return cls(**kwargs)
71
-
72
19
 
73
- def start_server(settings: ServerSettings):
20
+ def start_server(settings: setting.ServerSettings):
74
21
  """Start the cocoindex server."""
75
22
  flow.ensure_all_flows_built()
76
23
  query.ensure_all_handlers_built()
@@ -81,7 +28,7 @@ def stop():
81
28
  _engine.stop()
82
29
 
83
30
  def main_fn(
84
- settings: Settings | None = None,
31
+ settings: setting.Settings | None = None,
85
32
  cocoindex_cmd: str = 'cocoindex',
86
33
  ) -> Callable[[Callable], Callable]:
87
34
  """
@@ -92,7 +39,7 @@ def main_fn(
92
39
  """
93
40
 
94
41
  def _pre_init() -> None:
95
- effective_settings = settings or Settings.from_env()
42
+ effective_settings = settings or setting.Settings.from_env()
96
43
  init(effective_settings)
97
44
 
98
45
  def _should_run_cli() -> bool:
cocoindex/op.py CHANGED
@@ -5,10 +5,10 @@ import asyncio
5
5
  import dataclasses
6
6
  import inspect
7
7
 
8
- from typing import get_type_hints, Protocol, Any, Callable, Awaitable, dataclass_transform
8
+ from typing import Protocol, Any, Callable, Awaitable, dataclass_transform
9
9
  from enum import Enum
10
10
 
11
- from .typing import encode_enriched_type
11
+ from .typing import encode_enriched_type, resolve_forward_ref
12
12
  from .convert import encode_engine_value, make_engine_value_decoder
13
13
  from . import _engine
14
14
 
@@ -214,10 +214,11 @@ def executor_class(**args) -> Callable[[type], type]:
214
214
  """
215
215
  Decorate a class to provide an executor for an op.
216
216
  """
217
- type_hints = get_type_hints(cls)
217
+ # Use `__annotations__` instead of `get_type_hints`, to avoid resolving forward references.
218
+ type_hints = cls.__annotations__
218
219
  if 'spec' not in type_hints:
219
220
  raise TypeError("Expect a `spec` field with type hint")
220
- spec_cls = type_hints['spec']
221
+ spec_cls = resolve_forward_ref(type_hints['spec'])
221
222
  sig = inspect.signature(cls.__call__)
222
223
  return _register_op_factory(
223
224
  category=spec_cls._op_category,
cocoindex/setting.py ADDED
@@ -0,0 +1,77 @@
1
+ """
2
+ Data types for settings of the cocoindex library.
3
+ """
4
+ import os
5
+
6
+ from typing import Callable, Self, Any, overload
7
+ from dataclasses import dataclass
8
+
9
+
10
+ @dataclass
11
+ class DatabaseConnectionSpec:
12
+ """
13
+ Connection spec for relational database.
14
+ Used by both internal and target storage.
15
+ """
16
+ url: str
17
+ user: str | None = None
18
+ password: str | None = None
19
+
20
+ def _load_field(target: dict[str, Any], name: str, env_name: str, required: bool = False,
21
+ parse: Callable[[str], Any] | None = None):
22
+ value = os.getenv(env_name)
23
+ if value is None:
24
+ if required:
25
+ raise ValueError(f"{env_name} is not set")
26
+ else:
27
+ target[name] = value if parse is None else parse(value)
28
+
29
+ @dataclass
30
+ class Settings:
31
+ """Settings for the cocoindex library."""
32
+ database: DatabaseConnectionSpec
33
+
34
+ @classmethod
35
+ def from_env(cls) -> Self:
36
+ """Load settings from environment variables."""
37
+
38
+ db_kwargs: dict[str, str] = dict()
39
+ _load_field(db_kwargs, "url", "COCOINDEX_DATABASE_URL", required=True)
40
+ _load_field(db_kwargs, "user", "COCOINDEX_DATABASE_USER")
41
+ _load_field(db_kwargs, "password", "COCOINDEX_DATABASE_PASSWORD")
42
+ database = DatabaseConnectionSpec(**db_kwargs)
43
+ return cls(database=database)
44
+
45
+ @dataclass
46
+ class ServerSettings:
47
+ """Settings for the cocoindex server."""
48
+
49
+ # The address to bind the server to.
50
+ address: str = "127.0.0.1:8080"
51
+
52
+ # The origins of the clients (e.g. CocoInsight UI) to allow CORS from.
53
+ cors_origins: list[str] | None = None
54
+
55
+ @classmethod
56
+ def from_env(cls) -> Self:
57
+ """Load settings from environment variables."""
58
+ kwargs: dict[str, Any] = dict()
59
+ _load_field(kwargs, "address", "COCOINDEX_SERVER_ADDRESS")
60
+ _load_field(kwargs, "cors_origins", "COCOINDEX_SERVER_CORS_ORIGINS",
61
+ parse=ServerSettings.parse_cors_origins)
62
+ return cls(**kwargs)
63
+
64
+ @overload
65
+ @staticmethod
66
+ def parse_cors_origins(s: str) -> list[str]: ...
67
+
68
+ @overload
69
+ @staticmethod
70
+ def parse_cors_origins(s: str | None) -> list[str] | None: ...
71
+
72
+ @staticmethod
73
+ def parse_cors_origins(s):
74
+ """
75
+ Parse the CORS origins from a string.
76
+ """
77
+ return [o for e in s.split(",") if (o := e.strip()) != ""] if s is not None else None
cocoindex/storages.py CHANGED
@@ -5,11 +5,11 @@ from typing import Sequence
5
5
  from . import op
6
6
  from . import index
7
7
  from .auth_registry import AuthEntryReference
8
+ from .setting import DatabaseConnectionSpec
8
9
 
9
10
  class Postgres(op.StorageSpec):
10
11
  """Storage powered by Postgres and pgvector."""
11
-
12
- database: AuthEntryReference | None = None
12
+ database: AuthEntryReference[DatabaseConnectionSpec] | None = None
13
13
  table_name: str | None = None
14
14
 
15
15
  @dataclass
@@ -37,7 +37,7 @@ class TargetFieldMapping:
37
37
  target: str | None = None
38
38
 
39
39
  @dataclass
40
- class NodeReferenceMapping:
40
+ class NodeFromFields:
41
41
  """Spec for a referenced graph node, usually as part of a relationship."""
42
42
  label: str
43
43
  fields: list[TargetFieldMapping]
@@ -50,30 +50,36 @@ class ReferencedNode:
50
50
  vector_indexes: Sequence[index.VectorIndexDef] = ()
51
51
 
52
52
  @dataclass
53
- class NodeMapping:
53
+ class Nodes:
54
54
  """Spec to map a row to a graph node."""
55
55
  kind = "Node"
56
56
 
57
57
  label: str
58
58
 
59
59
  @dataclass
60
- class RelationshipMapping:
60
+ class Relationships:
61
61
  """Spec to map a row to a graph relationship."""
62
62
  kind = "Relationship"
63
63
 
64
64
  rel_type: str
65
- source: NodeReferenceMapping
66
- target: NodeReferenceMapping
65
+ source: NodeFromFields
66
+ target: NodeFromFields
67
+
68
+ # For backwards compatibility only
69
+ NodeMapping = Nodes
70
+ RelationshipMapping = Relationships
71
+ NodeReferenceMapping = NodeFromFields
67
72
 
68
73
  class Neo4j(op.StorageSpec):
69
74
  """Graph storage powered by Neo4j."""
75
+ connection: AuthEntryReference[Neo4jConnection]
76
+ mapping: Nodes | Relationships
70
77
 
71
- connection: AuthEntryReference
72
- mapping: NodeMapping | RelationshipMapping
73
-
74
- class Neo4jDeclarations(op.DeclarationSpec):
78
+ class Neo4jDeclaration(op.DeclarationSpec):
75
79
  """Declarations for Neo4j."""
76
80
 
77
81
  kind = "Neo4j"
78
- connection: AuthEntryReference
79
- referenced_nodes: Sequence[ReferencedNode] = ()
82
+ connection: AuthEntryReference[Neo4jConnection]
83
+ nodes_label: str
84
+ primary_key_fields: Sequence[str]
85
+ vector_indexes: Sequence[index.VectorIndexDef] = ()
cocoindex/typing.py CHANGED
@@ -245,3 +245,8 @@ def encode_enriched_type(t) -> dict[str, Any] | None:
245
245
  return None
246
246
 
247
247
  return encode_enriched_type_info(analyze_type_info(t))
248
+
249
+ def resolve_forward_ref(t):
250
+ if t is str:
251
+ return eval(t) # pylint: disable=eval-used
252
+ return t
@@ -1,8 +1,9 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cocoindex
3
- Version: 0.1.28
3
+ Version: 0.1.30
4
4
  Requires-Dist: sentence-transformers>=3.3.1
5
5
  Requires-Dist: click>=8.1.8
6
+ Requires-Dist: rich>=14.0.0
6
7
  Requires-Dist: pytest ; extra == 'test'
7
8
  Provides-Extra: test
8
9
  License-File: LICENSE
@@ -0,0 +1,25 @@
1
+ cocoindex-0.1.30.dist-info/METADATA,sha256=ISVp8Ocpqg9n4IdI4pIugzjX6ALux71KBNeVOo8vx3o,8237
2
+ cocoindex-0.1.30.dist-info/WHEEL,sha256=jABKVkLC9kJr8mi_er5jOqpiQUjARSLXDUIIxDqsS50,96
3
+ cocoindex-0.1.30.dist-info/licenses/LICENSE,sha256=HrhfyXIkWY2tGFK11kg7vPCqhgh5DcxleloqdhrpyMY,11558
4
+ cocoindex/auth_registry.py,sha256=-EhwmyIwJLPZthPOvEK21TfMbxQtndRbogk8q7y4XuU,716
5
+ cocoindex/cli.py,sha256=A0Si5GrByQ-4JQcvFZjCX3QU4bvFdmHxxMmoylw-xms,8609
6
+ cocoindex/convert.py,sha256=M8wRr38AgPpd43eklyWpNMaAvKHsIEyy_L3IlU7Q0oA,6095
7
+ cocoindex/flow.py,sha256=W3qKuKHd_XIfSXZNSDhxUSAQFCalXTx-pVPudTCX1Uo,23590
8
+ cocoindex/functions.py,sha256=m7R8gNVK5RcavPY37d2lkRXwLBdMblZexCJ0JYcruss,1881
9
+ cocoindex/index.py,sha256=32iiQI60VKhRRHle17rpoEVa_tsAHnyXXXnrLaX68uQ,557
10
+ cocoindex/lib.py,sha256=w0SumLvn2xfuQOgzLZDnQLur_GZ9DMAKOFo9NKF8q1k,2406
11
+ cocoindex/llm.py,sha256=POMdB-huMvPkRDpvcaBeOgXfbm0YZa0swNOdD2s4TRc,364
12
+ cocoindex/op.py,sha256=PeoBddukU5vOBvUrFPC6fYH35L59THy9ZXVm_Vc2ng0,10998
13
+ cocoindex/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
14
+ cocoindex/query.py,sha256=GU3V8AoSK--xOU2yX0Ao-Rz1t3mlrsJ4JIhzsLVwFH8,3297
15
+ cocoindex/runtime.py,sha256=WwyDSpJhvaHjnxH4q6r2MVftJB-QkNVH_TxZLxuDtFw,1009
16
+ cocoindex/setting.py,sha256=eHi1h3M6bSgG-7OMm_DDJ_MMY3X-PVL0S5IzxnhjjGQ,2431
17
+ cocoindex/setup.py,sha256=euHPZ9-7a68DV4PbdK2A0cZ9ECa6vT4qBraY3WKZk4s,512
18
+ cocoindex/sources.py,sha256=4JWsW7sjFuiizaxOkxXJpZgVmVgF9ys9ATvvRY-SBjE,966
19
+ cocoindex/storages.py,sha256=oJcY_zZx1wXjoJ_gitSvaFTUqhL6lUJihZQivvMMZ5U,2292
20
+ cocoindex/tests/test_convert.py,sha256=l5VpBgDw8F-0eMT_kEitUQTyI5newGnxqsm3gb6c2XA,11516
21
+ cocoindex/tests/__init__.py,sha256=frcCV1k9oG9oKj3dpUqdJg1PxRT2RSN_XKdLCPjaYaY,2
22
+ cocoindex/typing.py,sha256=WAmrgFwKRcoGB0aqRl2yk1cUey08HHQPgXyRRzmfN8c,8820
23
+ cocoindex/__init__.py,sha256=FZo8bM7rmJ3Ppg_ysAjjlWxiHPQPrNNwyHb4V-onXT0,673
24
+ cocoindex/_engine.cp312-win_amd64.pyd,sha256=oJ0slwF77wDR2dJjEt2My8sIrxBLvoG6lXC4MZHvZBg,58830848
25
+ cocoindex-0.1.30.dist-info/RECORD,,
@@ -1,24 +0,0 @@
1
- cocoindex-0.1.28.dist-info/METADATA,sha256=psGxDHsRMOTUeDNw66T-yrqKODptBFOVjTnvYR10Ofk,8209
2
- cocoindex-0.1.28.dist-info/WHEEL,sha256=jABKVkLC9kJr8mi_er5jOqpiQUjARSLXDUIIxDqsS50,96
3
- cocoindex-0.1.28.dist-info/licenses/LICENSE,sha256=HrhfyXIkWY2tGFK11kg7vPCqhgh5DcxleloqdhrpyMY,11558
4
- cocoindex/auth_registry.py,sha256=QQI8P7NMvA_NFIHXzV-yS94wVaZuXaIjY992Vrcii1E,641
5
- cocoindex/cli.py,sha256=kX2PQx7MJYX9UBGvyzIMqpzZSJfZA-NQJl9QI3m1ICU,7252
6
- cocoindex/convert.py,sha256=M8wRr38AgPpd43eklyWpNMaAvKHsIEyy_L3IlU7Q0oA,6095
7
- cocoindex/flow.py,sha256=Gu9uwDtoNz7IWnQFX6GtaSgee1NpODT1_4qS90OxqaE,21672
8
- cocoindex/functions.py,sha256=2yPL_s908AFxb6vVleFOVs8-6SCyT5cO-M7JLDqVFzA,1694
9
- cocoindex/index.py,sha256=32iiQI60VKhRRHle17rpoEVa_tsAHnyXXXnrLaX68uQ,557
10
- cocoindex/lib.py,sha256=V1bNKH6lpb1WT4f4F_4qD7e4Uarq-sS-donKXH5PjFo,4001
11
- cocoindex/llm.py,sha256=POMdB-huMvPkRDpvcaBeOgXfbm0YZa0swNOdD2s4TRc,364
12
- cocoindex/op.py,sha256=SYjXRlMxi304OcuOLPGlovv3CYa_DeQUunx4YJjmRc0,10871
13
- cocoindex/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
14
- cocoindex/query.py,sha256=GU3V8AoSK--xOU2yX0Ao-Rz1t3mlrsJ4JIhzsLVwFH8,3297
15
- cocoindex/runtime.py,sha256=WwyDSpJhvaHjnxH4q6r2MVftJB-QkNVH_TxZLxuDtFw,1009
16
- cocoindex/setup.py,sha256=euHPZ9-7a68DV4PbdK2A0cZ9ECa6vT4qBraY3WKZk4s,512
17
- cocoindex/sources.py,sha256=4JWsW7sjFuiizaxOkxXJpZgVmVgF9ys9ATvvRY-SBjE,966
18
- cocoindex/storages.py,sha256=AYYua_rzDUyvYb2ou3YFjO3jvRUcJKUTQlIYZzoTDnE,2036
19
- cocoindex/tests/test_convert.py,sha256=l5VpBgDw8F-0eMT_kEitUQTyI5newGnxqsm3gb6c2XA,11516
20
- cocoindex/tests/__init__.py,sha256=frcCV1k9oG9oKj3dpUqdJg1PxRT2RSN_XKdLCPjaYaY,2
21
- cocoindex/typing.py,sha256=RP322ATJqGkHkC7ht0s0tuRMg39CeNKUhk3cR_f78EY,8705
22
- cocoindex/__init__.py,sha256=FZo8bM7rmJ3Ppg_ysAjjlWxiHPQPrNNwyHb4V-onXT0,673
23
- cocoindex/_engine.cp312-win_amd64.pyd,sha256=w4pOYk17rBjpIzUX50rnJ-XLnrQCaoFj9fC3lKFG9nk,58877952
24
- cocoindex-0.1.28.dist-info/RECORD,,