Skip to content

Commit afc7e8b

Browse files
committed
fix: correct API usage across SDK, tests, and integrations
- client: support "host:port" string in AsyncCoordinodeClient constructor - test_types: fix _FakePV vector kind "vector" → "vector_value" - test_basic: fix health() (bool not dict), cypher() (List[Dict] not .columns/.rows) - langchain graph.py: query() — cypher() already returns List[Dict], no manual parse - llama-index base.py: fix get/get_triplets/get_rel_map (dict row access), vector_query (r.node.id, r.node.properties, r.distance), structured_query (direct return) - lint: remove unused imports and dead variable Closes #1
1 parent a95c513 commit afc7e8b

6 files changed

Lines changed: 56 additions & 55 deletions

File tree

coordinode/_types.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"""
44
from __future__ import annotations
55

6-
from typing import Any, Dict, List, Sequence, Union
6+
from typing import Any, Dict, List, Union
77

88
# We import proto types lazily to avoid hard-fail when stubs aren't generated yet.
99

coordinode/client.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
dict_to_props,
1616
from_property_value,
1717
props_to_dict,
18-
to_property_value,
1918
)
2019

2120

@@ -82,8 +81,12 @@ class AsyncCoordinodeClient:
8281
8382
Usage::
8483
85-
async with AsyncCoordinodeClient("localhost") as client:
84+
async with AsyncCoordinodeClient("localhost:7080") as client:
8685
rows = await client.cypher("MATCH (n:Person) RETURN n.name LIMIT 5")
86+
87+
# Also accepts separate host and port:
88+
async with AsyncCoordinodeClient("localhost", port=7080) as client:
89+
...
8790
"""
8891

8992
def __init__(
@@ -94,6 +97,10 @@ def __init__(
9497
tls: bool = False,
9598
timeout: float = 30.0,
9699
) -> None:
100+
# Support "host:port" as a single string (common gRPC convention).
101+
if ":" in host and port == 7080:
102+
_h, _p = host.rsplit(":", 1)
103+
host, port = _h, int(_p)
97104
self._host = host
98105
self._port = port
99106
self._tls = tls
@@ -307,7 +314,7 @@ class CoordinodeClient:
307314
308315
Usage::
309316
310-
with CoordinodeClient("localhost") as client:
317+
with CoordinodeClient("localhost:7080") as client:
311318
rows = client.cypher("MATCH (n:Person) RETURN n.name LIMIT 5")
312319
print(rows) # [{"n.name": "Alice"}, ...]
313320
"""

langchain-coordinode/langchain_coordinode/graph.py

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -83,12 +83,8 @@ def query(
8383
Returns:
8484
List of row dicts (column name → value).
8585
"""
86-
result = self._client.cypher(query, params=params or {})
87-
rows: List[Dict[str, Any]] = []
88-
columns = list(result.columns)
89-
for row in result.rows:
90-
rows.append(dict(zip(columns, row)))
91-
return rows
86+
# cypher() returns List[Dict[str, Any]] directly — column name → value.
87+
return self._client.cypher(query, params=params or {})
9288

9389
# ── Lifecycle ─────────────────────────────────────────────────────────
9490

llama-index-coordinode/llama_index/graph_stores/coordinode/base.py

Lines changed: 29 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,11 @@
22

33
from __future__ import annotations
44

5-
from typing import Any, Dict, List, Optional, Sequence
5+
from typing import Any, Dict, List, Optional
66

77
from llama_index.core.graph_stores.types import (
88
ChunkNode,
99
EntityNode,
10-
KG_NODES_KEY,
11-
KG_RELATIONS_KEY,
1210
LabelledNode,
1311
PropertyGraphStore,
1412
Relation,
@@ -73,9 +71,9 @@ def get(
7371
)
7472
cypher = f"MATCH (n) WHERE {where_clauses} RETURN n, id(n) AS _id LIMIT 1000"
7573
result = self._client.cypher(cypher, params=properties)
76-
for row in result.rows:
77-
node_data = row[0] if row else {}
78-
node_id = str(row[1]) if len(row) > 1 else ""
74+
for row in result:
75+
node_data = row.get("n", {})
76+
node_id = str(row.get("_id", ""))
7977
nodes.append(_node_result_to_labelled(node_id, node_data))
8078

8179
return nodes
@@ -104,22 +102,20 @@ def get_triplets(
104102
where = f"WHERE {' AND '.join(conditions)}" if conditions else ""
105103
cypher = (
106104
f"MATCH (n)-{rel_pattern}->(m) {where} "
107-
"RETURN n, type(r), m, id(n) AS _src_id, id(m) AS _dst_id "
105+
"RETURN n, type(r) AS rel_type, m, id(n) AS _src_id, id(m) AS _dst_id "
108106
"LIMIT 1000"
109107
)
110108
result = self._client.cypher(cypher, params=params)
111109

112110
triplets: List[List[LabelledNode]] = []
113-
for row in result.rows:
114-
src_data, rel_type, dst_data, src_id, dst_id = (
115-
row[0], row[1], row[2], str(row[3]), str(row[4])
116-
)
111+
for row in result:
112+
src_data = row.get("n", {})
113+
rel_type = row.get("rel_type", "RELATED")
114+
dst_data = row.get("m", {})
115+
src_id = str(row.get("_src_id", ""))
116+
dst_id = str(row.get("_dst_id", ""))
117117
src = _node_result_to_labelled(src_id, src_data)
118-
rel = Relation(
119-
label=str(rel_type),
120-
source_id=src_id,
121-
target_id=dst_id,
122-
)
118+
rel = Relation(label=str(rel_type), source_id=src_id, target_id=dst_id)
123119
dst = _node_result_to_labelled(dst_id, dst_data)
124120
triplets.append([src, rel, dst])
125121

@@ -137,10 +133,8 @@ def get_rel_map(
137133
return []
138134

139135
ids = [n.id for n in graph_nodes]
140-
rel_filter = ""
141-
if ignore_rels:
142-
# We can't dynamically exclude types in OpenCypher without WHERE
143-
pass
136+
# ignore_rels: OpenCypher doesn't support dynamic type exclusion in patterns;
137+
# would require WHERE NOT type(r) IN $ignore_rels — added when needed.
144138

145139
cypher = (
146140
f"MATCH (n)-[r*1..{depth}]->(m) "
@@ -151,13 +145,16 @@ def get_rel_map(
151145
result = self._client.cypher(cypher, params={"ids": ids})
152146

153147
triplets: List[List[LabelledNode]] = []
154-
for row in result.rows:
155-
src_data, rels, dst_data, src_id, dst_id = (
156-
row[0], row[1], row[2], str(row[3]), str(row[4])
157-
)
148+
for row in result:
149+
src_data = row.get("n", {})
150+
dst_data = row.get("m", {})
151+
src_id = str(row.get("_src_id", ""))
152+
dst_id = str(row.get("_dst_id", ""))
153+
# Variable-length path r returns a list; take first rel type as label.
154+
rels = row.get("r", [])
155+
rel_label = str(rels[0]) if isinstance(rels, list) and rels else "RELATED"
158156
src = _node_result_to_labelled(src_id, src_data)
159157
dst = _node_result_to_labelled(dst_id, dst_data)
160-
rel_label = str(rels[0]) if isinstance(rels, list) and rels else "RELATED"
161158
rel = Relation(label=rel_label, source_id=src_id, target_id=dst_id)
162159
triplets.append([src, rel, dst])
163160

@@ -228,13 +225,14 @@ def vector_query(
228225
nodes: List[LabelledNode] = []
229226
scores: List[float] = []
230227
for r in results:
228+
# VectorResult has .node (NodeResult with .id/.properties) and .distance
231229
node = ChunkNode(
232-
id_=str(r.node_id),
233-
text=r.properties.get("text", ""),
234-
properties=r.properties,
230+
id_=str(r.node.id),
231+
text=r.node.properties.get("text", ""),
232+
properties=r.node.properties,
235233
)
236234
nodes.append(node)
237-
scores.append(r.score)
235+
scores.append(r.distance)
238236

239237
return nodes, scores
240238

@@ -264,12 +262,8 @@ def structured_query(
264262
param_map: Optional[Dict[str, Any]] = None,
265263
) -> Any:
266264
"""Execute a raw Cypher query."""
267-
result = self._client.cypher(query, params=param_map or {})
268-
rows = []
269-
columns = list(result.columns)
270-
for row in result.rows:
271-
rows.append(dict(zip(columns, row)))
272-
return rows
265+
# cypher() returns List[Dict[str, Any]] — column name → value.
266+
return self._client.cypher(query, params=param_map or {})
273267

274268

275269
# ── Helpers ───────────────────────────────────────────────────────────────

tests/integration/test_basic.py

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,24 +22,25 @@ def client():
2222

2323

2424
def test_health(client):
25-
h = client.health()
26-
assert h.get("status") in ("ok", "serving", "SERVING")
25+
# health() returns bool — True when server reports SERVING
26+
assert client.health() is True
2727

2828

2929
def test_cypher_return_literal(client):
30+
# cypher() returns List[Dict[str, Any]] — one row per result row
3031
result = client.cypher("RETURN 1 AS n")
31-
assert result.columns == ["n"] or "n" in result.columns
32-
assert len(result.rows) == 1
32+
assert len(result) == 1
33+
assert result[0]["n"] == 1
3334

3435

3536
def test_create_and_get_node(client):
3637
result = client.cypher(
3738
"CREATE (n:IntegrationTest {name: $name}) RETURN id(n) AS node_id",
3839
params={"name": "sdk-test-node"},
3940
)
40-
assert result.rows, "CREATE returned no rows"
41-
node_id = str(result.rows[0][0])
42-
assert node_id
41+
assert result, "CREATE returned no rows"
42+
node_id = result[0]["node_id"]
43+
assert node_id is not None
4344

4445
# Clean up
4546
client.cypher(
@@ -49,7 +50,8 @@ def test_create_and_get_node(client):
4950

5051

5152
def test_vector_search(client):
52-
# Insert a node with an embedding, then search for it
53+
# Insert a node with an embedding, then search for it.
54+
# VectorResult has .node (NodeResult) and .distance (float).
5355
vec = [0.1] * 16
5456
client.cypher(
5557
"CREATE (d:VecTestDoc {id: 'vs-test', embedding: $vec})",
@@ -63,5 +65,7 @@ def test_vector_search(client):
6365
top_k=1,
6466
)
6567
assert len(results) >= 1
68+
assert hasattr(results[0], "distance")
69+
assert hasattr(results[0], "node")
6670
finally:
6771
client.cypher("MATCH (d:VecTestDoc {id: 'vs-test'}) DELETE d")

tests/unit/test_types.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ def bytes_value(self):
5353
return self._value
5454

5555
@property
56-
def vector(self):
56+
def vector_value(self):
5757
return self._value
5858

5959
@property
@@ -135,7 +135,7 @@ def test_bytes_value(self):
135135

136136
def test_vector(self):
137137
vec = _FakeVec([0.1, 0.2])
138-
pv = _FakePV("vector", vec)
138+
pv = _FakePV("vector_value", vec)
139139
result = from_property_value(pv)
140140
assert result == pytest.approx([0.1, 0.2])
141141

0 commit comments

Comments
 (0)