Skip to content

Commit 6e098a2

Browse files
committed
fix(schema): add schema_mode to create_edge_type, pin Dockerfile, health checks
- create_edge_type(): add schema_mode parameter (strict/validated/flexible) matching create_label() — both async and sync variants - create_text_index(): use `language or "english"` in fallback TextIndexInfo so empty-string language resolves to the server default correctly - demo/Dockerfile.jupyter: pin base image from :latest to :python-3.11.6 - demo/install-sdk.sh: track untracked install script - notebooks 00, 02: add client.health() after CoordinodeClient() construction to surface connection errors early before running queries
1 parent bc24c8d commit 6e098a2

5 files changed

Lines changed: 42 additions & 4 deletions

File tree

coordinode/coordinode/client.py

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -471,6 +471,8 @@ def _build_property_definitions(
471471
}
472472
if properties is None:
473473
return []
474+
# list | tuple union syntax is valid in isinstance() for Python ≥3.10 (PEP 604).
475+
# This project targets Python ≥3.11 (pyproject.toml: requires-python = ">=3.11").
474476
if not isinstance(properties, list | tuple):
475477
raise ValueError(f"'properties' must be a list of property dicts or None; got {type(properties).__name__}")
476478
result = []
@@ -542,6 +544,8 @@ async def create_edge_type(
542544
self,
543545
name: str,
544546
properties: list[dict[str, Any]] | None = None,
547+
*,
548+
schema_mode: str = "strict",
545549
) -> EdgeTypeInfo:
546550
"""Create an edge type in the schema registry.
547551
@@ -550,15 +554,35 @@ async def create_edge_type(
550554
properties: Optional list of property dicts with keys
551555
``name`` (str), ``type`` (str), ``required`` (bool),
552556
``unique`` (bool). Same type strings as :meth:`create_label`.
557+
schema_mode: ``"strict"`` (default — reject undeclared props),
558+
``"validated"`` (warn on extras), or ``"flexible"`` (allow any
559+
prop without declaration). Case-insensitive; leading/trailing
560+
whitespace is stripped.
553561
"""
554562
from coordinode._proto.coordinode.v1.graph.schema_pb2 import ( # type: ignore[import]
555563
CreateEdgeTypeRequest,
556564
PropertyDefinition,
557565
PropertyType,
566+
SchemaMode,
558567
)
559568

569+
_mode_map = {
570+
"strict": SchemaMode.SCHEMA_MODE_STRICT,
571+
"validated": SchemaMode.SCHEMA_MODE_VALIDATED,
572+
"flexible": SchemaMode.SCHEMA_MODE_FLEXIBLE,
573+
}
574+
if not isinstance(schema_mode, str):
575+
raise ValueError(f"schema_mode must be a str, got {type(schema_mode).__name__!r}")
576+
schema_mode_normalized = schema_mode.strip().lower()
577+
if schema_mode_normalized not in _mode_map:
578+
raise ValueError(f"schema_mode must be one of {list(_mode_map)}, got {schema_mode!r}")
579+
560580
proto_props = self._build_property_definitions(properties, PropertyType, PropertyDefinition)
561-
req = CreateEdgeTypeRequest(name=name, properties=proto_props)
581+
req = CreateEdgeTypeRequest(
582+
name=name,
583+
properties=proto_props,
584+
schema_mode=_mode_map[schema_mode_normalized],
585+
)
562586
et = await self._schema_stub.CreateEdgeType(req, timeout=self._timeout)
563587
return EdgeTypeInfo(et)
564588

@@ -613,8 +637,9 @@ async def create_text_index(
613637
rows = await self.cypher(cypher)
614638
if rows:
615639
return TextIndexInfo(rows[0])
640+
effective_language = language or "english"
616641
return TextIndexInfo(
617-
{"index": name, "label": label, "properties": ", ".join(prop_list), "default_language": language}
642+
{"index": name, "label": label, "properties": ", ".join(prop_list), "default_language": effective_language}
618643
)
619644

620645
async def drop_text_index(self, name: str) -> None:
@@ -918,9 +943,11 @@ def create_edge_type(
918943
self,
919944
name: str,
920945
properties: list[dict[str, Any]] | None = None,
946+
*,
947+
schema_mode: str = "strict",
921948
) -> EdgeTypeInfo:
922949
"""Create an edge type in the schema registry."""
923-
return self._run(self._async.create_edge_type(name, properties))
950+
return self._run(self._async.create_edge_type(name, properties, schema_mode=schema_mode))
924951

925952
def create_text_index(
926953
self,

demo/Dockerfile.jupyter

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
FROM jupyter/scipy-notebook:latest
1+
FROM jupyter/scipy-notebook:python-3.11.6
22

33
USER root
44
RUN apt-get update && apt-get install -y --no-install-recommends gcc git && rm -rf /var/lib/apt/lists/*

demo/install-sdk.sh

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#!/usr/bin/env bash
2+
# Install coordinode SDK packages from mounted /sdk source.
3+
# Run once inside the container after /sdk is mounted.
4+
set -e
5+
pip install --no-cache-dir -e /sdk/coordinode
6+
pip install --no-cache-dir -e /sdk/llama-index-coordinode
7+
pip install --no-cache-dir -e /sdk/langchain-coordinode

demo/notebooks/00_seed_data.ipynb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@
151151
" from coordinode import CoordinodeClient\n",
152152
"\n",
153153
" client = CoordinodeClient(COORDINODE_ADDR)\n",
154+
" client.health()\n",
154155
" print(f\"Connected to {COORDINODE_ADDR}\")\n",
155156
"else:\n",
156157
" try:\n",
@@ -163,6 +164,7 @@
163164
" from coordinode import CoordinodeClient\n",
164165
"\n",
165166
" client = CoordinodeClient(COORDINODE_ADDR)\n",
167+
" client.health()\n",
166168
" print(f\"Connected to {COORDINODE_ADDR}\")\n",
167169
" else:\n",
168170
" # No server available — use the embedded in-process engine.\n",

demo/notebooks/02_langchain_graph_chain.ipynb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@
170170
" from coordinode import CoordinodeClient\n",
171171
"\n",
172172
" client = CoordinodeClient(COORDINODE_ADDR)\n",
173+
" client.health()\n",
173174
" print(f\"Connected to {COORDINODE_ADDR}\")\n",
174175
"else:\n",
175176
" try:\n",
@@ -182,6 +183,7 @@
182183
" from coordinode import CoordinodeClient\n",
183184
"\n",
184185
" client = CoordinodeClient(COORDINODE_ADDR)\n",
186+
" client.health()\n",
185187
" print(f\"Connected to {COORDINODE_ADDR}\")\n",
186188
" else:\n",
187189
" # No server available — use the embedded in-process engine.\n",

0 commit comments

Comments
 (0)