cocoindex 0.1.21__cp311-cp311-macosx_11_0_arm64.whl → 0.1.23__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.
- cocoindex/_engine.cpython-311-darwin.so +0 -0
- cocoindex/convert.py +4 -1
- cocoindex/functions.py +3 -0
- cocoindex/storages.py +24 -10
- cocoindex/tests/__init__.py +1 -0
- cocoindex/tests/test_convert.py +69 -0
- cocoindex/typing.py +1 -5
- {cocoindex-0.1.21.dist-info → cocoindex-0.1.23.dist-info}/METADATA +3 -1
- {cocoindex-0.1.21.dist-info → cocoindex-0.1.23.dist-info}/RECORD +11 -9
- {cocoindex-0.1.21.dist-info → cocoindex-0.1.23.dist-info}/WHEEL +0 -0
- {cocoindex-0.1.21.dist-info → cocoindex-0.1.23.dist-info}/licenses/LICENSE +0 -0
Binary file
|
cocoindex/convert.py
CHANGED
@@ -117,7 +117,10 @@ def dump_engine_object(v: Any) -> Any:
|
|
117
117
|
nanos = int((total_secs - secs) * 1e9)
|
118
118
|
return {'secs': secs, 'nanos': nanos}
|
119
119
|
elif hasattr(v, '__dict__'):
|
120
|
-
|
120
|
+
s = {k: dump_engine_object(v) for k, v in v.__dict__.items()}
|
121
|
+
if hasattr(v, 'kind') and 'kind' not in s:
|
122
|
+
s['kind'] = v.kind
|
123
|
+
return s
|
121
124
|
elif isinstance(v, (list, tuple)):
|
122
125
|
return [dump_engine_object(item) for item in v]
|
123
126
|
elif isinstance(v, dict):
|
cocoindex/functions.py
CHANGED
@@ -5,6 +5,9 @@ import sentence_transformers
|
|
5
5
|
from .typing import Float32, Vector, TypeAttr
|
6
6
|
from . import op, llm
|
7
7
|
|
8
|
+
class ParseJson(op.FunctionSpec):
|
9
|
+
"""Parse a text into a JSON object."""
|
10
|
+
|
8
11
|
class SplitRecursively(op.FunctionSpec):
|
9
12
|
"""Split a document (in string) recursively."""
|
10
13
|
|
cocoindex/storages.py
CHANGED
@@ -21,7 +21,7 @@ class Qdrant(op.StorageSpec):
|
|
21
21
|
api_key: str | None = None
|
22
22
|
|
23
23
|
@dataclass
|
24
|
-
class
|
24
|
+
class Neo4jConnection:
|
25
25
|
"""Connection spec for Neo4j."""
|
26
26
|
uri: str
|
27
27
|
user: str
|
@@ -29,7 +29,7 @@ class Neo4jConnectionSpec:
|
|
29
29
|
db: str | None = None
|
30
30
|
|
31
31
|
@dataclass
|
32
|
-
class
|
32
|
+
class GraphFieldMapping:
|
33
33
|
"""Mapping for a Neo4j field."""
|
34
34
|
field_name: str
|
35
35
|
# Field name for the node in the Knowledge Graph.
|
@@ -37,22 +37,36 @@ class Neo4jFieldMapping:
|
|
37
37
|
node_field_name: str | None = None
|
38
38
|
|
39
39
|
@dataclass
|
40
|
-
class
|
40
|
+
class GraphRelationshipEnd:
|
41
41
|
"""Spec for a Neo4j node type."""
|
42
42
|
label: str
|
43
|
-
fields: list[
|
43
|
+
fields: list[GraphFieldMapping]
|
44
44
|
|
45
45
|
@dataclass
|
46
|
-
class
|
46
|
+
class GraphRelationshipNode:
|
47
47
|
"""Spec for a Neo4j node type."""
|
48
48
|
primary_key_fields: Sequence[str]
|
49
49
|
vector_indexes: Sequence[index.VectorIndexDef] = ()
|
50
50
|
|
51
|
-
|
51
|
+
@dataclass
|
52
|
+
class GraphNode:
|
53
|
+
"""Spec for a Neo4j node type."""
|
54
|
+
kind = "Node"
|
55
|
+
|
56
|
+
label: str
|
57
|
+
|
58
|
+
@dataclass
|
59
|
+
class GraphRelationship:
|
60
|
+
"""Spec for a Neo4j relationship."""
|
61
|
+
kind = "Relationship"
|
62
|
+
|
63
|
+
rel_type: str
|
64
|
+
source: GraphRelationshipEnd
|
65
|
+
target: GraphRelationshipEnd
|
66
|
+
nodes: dict[str, GraphRelationshipNode] | None = None
|
67
|
+
|
68
|
+
class Neo4j(op.StorageSpec):
|
52
69
|
"""Graph storage powered by Neo4j."""
|
53
70
|
|
54
71
|
connection: AuthEntryReference
|
55
|
-
|
56
|
-
source: Neo4jRelationshipEndSpec
|
57
|
-
target: Neo4jRelationshipEndSpec
|
58
|
-
nodes: dict[str, Neo4jRelationshipNodeSpec]
|
72
|
+
mapping: GraphNode | GraphRelationship
|
@@ -0,0 +1 @@
|
|
1
|
+
|
@@ -0,0 +1,69 @@
|
|
1
|
+
import dataclasses
|
2
|
+
import uuid
|
3
|
+
import datetime
|
4
|
+
from dataclasses import dataclass
|
5
|
+
import pytest
|
6
|
+
from cocoindex.convert import to_engine_value
|
7
|
+
|
8
|
+
@dataclass
|
9
|
+
class Order:
|
10
|
+
order_id: str
|
11
|
+
name: str
|
12
|
+
price: float
|
13
|
+
|
14
|
+
@dataclass
|
15
|
+
class Basket:
|
16
|
+
items: list
|
17
|
+
|
18
|
+
@dataclass
|
19
|
+
class Customer:
|
20
|
+
name: str
|
21
|
+
order: Order
|
22
|
+
|
23
|
+
def test_to_engine_value_basic_types():
|
24
|
+
assert to_engine_value(123) == 123
|
25
|
+
assert to_engine_value(3.14) == 3.14
|
26
|
+
assert to_engine_value("hello") == "hello"
|
27
|
+
assert to_engine_value(True) is True
|
28
|
+
|
29
|
+
def test_to_engine_value_uuid():
|
30
|
+
u = uuid.uuid4()
|
31
|
+
assert to_engine_value(u) == u.bytes
|
32
|
+
|
33
|
+
def test_to_engine_value_date_time_types():
|
34
|
+
d = datetime.date(2024, 1, 1)
|
35
|
+
assert to_engine_value(d) == d
|
36
|
+
t = datetime.time(12, 30)
|
37
|
+
assert to_engine_value(t) == t
|
38
|
+
dt = datetime.datetime(2024, 1, 1, 12, 30)
|
39
|
+
assert to_engine_value(dt) == dt
|
40
|
+
|
41
|
+
def test_to_engine_value_struct():
|
42
|
+
order = Order(order_id="O123", name="mixed nuts", price=25.0)
|
43
|
+
assert to_engine_value(order) == ["O123", "mixed nuts", 25.0]
|
44
|
+
|
45
|
+
def test_to_engine_value_list_of_structs():
|
46
|
+
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]]
|
48
|
+
|
49
|
+
def test_to_engine_value_struct_with_list():
|
50
|
+
basket = Basket(items=["apple", "banana"])
|
51
|
+
assert to_engine_value(basket) == [["apple", "banana"]]
|
52
|
+
|
53
|
+
def test_to_engine_value_nested_struct():
|
54
|
+
customer = Customer(name="Alice", order=Order("O1", "item1", 10.0))
|
55
|
+
assert to_engine_value(customer) == ["Alice", ["O1", "item1", 10.0]]
|
56
|
+
|
57
|
+
def test_to_engine_value_empty_list():
|
58
|
+
assert to_engine_value([]) == []
|
59
|
+
assert to_engine_value([[]]) == [[]]
|
60
|
+
|
61
|
+
def test_to_engine_value_tuple():
|
62
|
+
assert to_engine_value(()) == []
|
63
|
+
assert to_engine_value((1, 2, 3)) == [1, 2, 3]
|
64
|
+
assert to_engine_value(((1, 2), (3, 4))) == [[1, 2], [3, 4]]
|
65
|
+
assert to_engine_value(([],)) == [[]]
|
66
|
+
assert to_engine_value(((),)) == [[]]
|
67
|
+
|
68
|
+
def test_to_engine_value_none():
|
69
|
+
assert to_engine_value(None) is None
|
cocoindex/typing.py
CHANGED
@@ -183,11 +183,7 @@ def _encode_type(type_info: AnalyzedTypeInfo) -> dict[str, Any]:
|
|
183
183
|
if type_info.elem_type is None:
|
184
184
|
raise ValueError(f"{type_info.kind} type must have an element type")
|
185
185
|
row_type_info = analyze_type_info(type_info.elem_type)
|
186
|
-
|
187
|
-
raise ValueError(f"{type_info.kind} type must have a dataclass type")
|
188
|
-
encoded_type['row'] = {
|
189
|
-
'fields': _encode_fields_schema(row_type_info.dataclass_type),
|
190
|
-
}
|
186
|
+
encoded_type['row'] = _encode_type(row_type_info)
|
191
187
|
|
192
188
|
return encoded_type
|
193
189
|
|
@@ -1,8 +1,10 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: cocoindex
|
3
|
-
Version: 0.1.
|
3
|
+
Version: 0.1.23
|
4
4
|
Requires-Dist: sentence-transformers>=3.3.1
|
5
5
|
Requires-Dist: click>=8.1.8
|
6
|
+
Requires-Dist: pytest ; extra == 'test'
|
7
|
+
Provides-Extra: test
|
6
8
|
License-File: LICENSE
|
7
9
|
Summary: With CocoIndex, users declare the transformation, CocoIndex creates & maintains an index, and keeps the derived index up to date based on source update, with minimal computation and changes.
|
8
10
|
Author-email: CocoIndex <cocoindex.io@gmail.com>
|
@@ -1,12 +1,14 @@
|
|
1
|
-
cocoindex-0.1.
|
2
|
-
cocoindex-0.1.
|
3
|
-
cocoindex-0.1.
|
4
|
-
cocoindex/functions.py,sha256=
|
1
|
+
cocoindex-0.1.23.dist-info/METADATA,sha256=IcyNWcJi0ycAqXknL1KbV-tsNRQqNf3a097Xrpbe4g8,8066
|
2
|
+
cocoindex-0.1.23.dist-info/WHEEL,sha256=wsVBlw9xyAuHecZeOYqJ_tA7emUKfXYOn-_180uZRi4,104
|
3
|
+
cocoindex-0.1.23.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
4
|
+
cocoindex/functions.py,sha256=xcAeRQTy9JObfxpjyMn-dPY2y7XhVWjB7759xVyup6o,1657
|
5
5
|
cocoindex/query.py,sha256=XsVY5cBJJ3a70qazkcCHjWZLE1zBqzMQ4HVSulicGMA,3273
|
6
6
|
cocoindex/index.py,sha256=LssEOuZi6AqhwKtZM3QFeQpa9T-0ELi8G5DsrYKECvc,534
|
7
7
|
cocoindex/lib.py,sha256=kyfzkaanrMHVwWjd2UWgLr8ArS_vjlK64qb4TbNTbbs,3464
|
8
8
|
cocoindex/auth_registry.py,sha256=lZ2rD5_9aC_UpGk7t4TmSYal_rjN7eHgO4_sU7FR0Zw,620
|
9
|
-
cocoindex/convert.py,sha256=
|
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
|
10
12
|
cocoindex/__init__.py,sha256=f4LTPg4db7Wm3QO9HirvhsT11OVykiFxGbt1JK6taFA,572
|
11
13
|
cocoindex/flow.py,sha256=HwngOKZyF60pUE_LGjt02yVNWh-haoMWH1Si0w5rYqY,19856
|
12
14
|
cocoindex/llm.py,sha256=uHXub9AWTOtxNyTaefHY-VuY_yzo6ikM1kUxHsQn-zw,298
|
@@ -15,7 +17,7 @@ cocoindex/sources.py,sha256=wZFU8lwSXjyofJR-syySH9fTyPnBlAPJ6-1hQNX8fGA,936
|
|
15
17
|
cocoindex/setup.py,sha256=W1HshwYk_K2aeLOVn_e62ZOXBO9yWsoUboRiH4SjF48,496
|
16
18
|
cocoindex/cli.py,sha256=jRwGCPuqkBz_cIp7LKARCRAiDsPm91bsduKzfYJohJ4,6931
|
17
19
|
cocoindex/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
18
|
-
cocoindex/typing.py,sha256=
|
19
|
-
cocoindex/storages.py,sha256=
|
20
|
-
cocoindex/_engine.cpython-311-darwin.so,sha256
|
21
|
-
cocoindex-0.1.
|
20
|
+
cocoindex/typing.py,sha256=4mP9VXS75s3VMfF1LDc1LXsBng7uGdR5aD73N8iaeSM,7282
|
21
|
+
cocoindex/storages.py,sha256=ZWpQABuUWTs6BdPcTBWDOiRXVGxS87Uh2i_C1wtkXYQ,1718
|
22
|
+
cocoindex/_engine.cpython-311-darwin.so,sha256=-77UYSsQnHih4BKXk7xE4vaSgd8yOejNQXY1GMI69FU,59047776
|
23
|
+
cocoindex-0.1.23.dist-info/RECORD,,
|
File without changes
|
File without changes
|