Skip to content

Commit 6b427b1

Browse files
authored
fix: avoid cyclic import (#65)
* fix: avoid cyclic import Signed-off-by: Keming <kemingyang@tensorchord.ai> * fix comments Signed-off-by: Keming <kemingyang@tensorchord.ai> --------- Signed-off-by: Keming <kemingyang@tensorchord.ai>
1 parent 4f1999f commit 6b427b1

3 files changed

Lines changed: 51 additions & 78 deletions

File tree

vechord/__init__.py

Lines changed: 0 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,5 @@
1-
from vechord.augment import GeminiAugmenter
2-
from vechord.chunk import GeminiChunker, RegexChunker, SpacyChunker
31
from vechord.client import VechordClient
4-
from vechord.embedding import (
5-
GeminiDenseEmbedding,
6-
OpenAIDenseEmbedding,
7-
SpacyDenseEmbedding,
8-
)
9-
from vechord.evaluate import GeminiEvaluator
10-
from vechord.extract import GeminiExtractor, SimpleExtractor
11-
from vechord.load import LocalLoader
12-
from vechord.model import Document
132
from vechord.registry import VechordPipeline, VechordRegistry
14-
from vechord.rerank import CohereReranker
15-
from vechord.service import create_web_app
163
from vechord.spec import (
174
DefaultDocument,
185
ForeignKey,
@@ -29,33 +16,19 @@
2916
)
3017

3118
__all__ = [
32-
"CohereReranker",
3319
"DefaultDocument",
34-
"Document",
3520
"ForeignKey",
36-
"GeminiAugmenter",
37-
"GeminiChunker",
38-
"GeminiDenseEmbedding",
39-
"GeminiEvaluator",
40-
"GeminiExtractor",
4121
"IndexColumn",
4222
"Keyword",
4323
"KeywordIndex",
44-
"LocalLoader",
4524
"MultiVectorIndex",
46-
"OpenAIDenseEmbedding",
4725
"PrimaryKeyAutoIncrease",
4826
"PrimaryKeyUUID",
49-
"RegexChunker",
50-
"SimpleExtractor",
51-
"SpacyChunker",
52-
"SpacyDenseEmbedding",
5327
"Table",
5428
"VechordClient",
5529
"VechordPipeline",
5630
"VechordRegistry",
5731
"Vector",
5832
"VectorIndex",
5933
"create_chunk_with_dim",
60-
"create_web_app",
6134
]

vechord/pipeline.py

Lines changed: 8 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,15 @@
11
import base64
22
import itertools
3-
from collections.abc import Callable, Iterable
3+
from collections.abc import Iterable
44
from contextlib import contextmanager
55
from os import environ
6-
from typing import TYPE_CHECKING, Annotated, Any, Optional
6+
from typing import Annotated, Any, Optional
77
from uuid import UUID
88

99
import msgspec
1010

1111
from vechord.chunk import BaseChunker, GeminiChunker, RegexChunker
1212
from vechord.client import (
13-
VechordClient,
14-
limit_to_transaction_buffer_conn,
1513
set_namespace,
1614
)
1715
from vechord.embedding import (
@@ -37,6 +35,7 @@
3735
RunRequest,
3836
RunSearchResponse,
3937
)
38+
from vechord.registry import VechordRegistry
4039
from vechord.rerank import BaseReranker, CohereReranker, JinaReranker
4140
from vechord.spec import (
4241
AnyOf,
@@ -51,9 +50,6 @@
5150
)
5251
from vechord.typing import Self
5352

54-
if TYPE_CHECKING:
55-
from vechord.registry import VechordRegistry
56-
5753

5854
class GraphIndex(msgspec.Struct):
5955
"""Graph index for entities and relations extracted from the text/image."""
@@ -208,7 +204,7 @@ def from_steps(cls, steps: list[ResourceRequest]) -> Self:
208204
return msgspec.convert(calls, DynamicPipeline)
209205

210206
async def run(
211-
self, request: RunRequest, vr: "VechordRegistry"
207+
self, request: RunRequest, vr: VechordRegistry
212208
) -> RunIngestAck | RunSearchResponse:
213209
"""Run the dynamic pipeline with the given request."""
214210
async with set_namespace(request.name):
@@ -249,7 +245,7 @@ def _convert_from_extracted_graph(
249245
return converted_ents, converted_rels
250246

251247
async def run_index( # noqa: PLR0912
252-
self, request: RunRequest, vr: "VechordRegistry"
248+
self, request: RunRequest, vr: VechordRegistry
253249
) -> RunIngestAck:
254250
dim = (
255251
self.text_emb.get_dim() if self.text_emb else self.multimodal_emb.get_dim()
@@ -345,7 +341,7 @@ async def graph_insert(
345341
rels: list[_Relation],
346342
ent_cls: type[Table],
347343
rel_cls: type[Table],
348-
vr: "VechordRegistry",
344+
vr: VechordRegistry,
349345
):
350346
"""Insert entities and relations into the graph index."""
351347
ent_map: dict[str, _Entity] = {}
@@ -393,7 +389,7 @@ async def graph_insert(
393389
await vr.insert(rel)
394390

395391
async def run_search(
396-
self, request: RunRequest, vr: "VechordRegistry"
392+
self, request: RunRequest, vr: VechordRegistry
397393
) -> RunSearchResponse:
398394
query = request.data.decode("utf-8")
399395

@@ -451,7 +447,7 @@ async def graph_search(
451447
chunk_cls: type[Table],
452448
ent_cls: type[Table],
453449
rel_cls: type[Table],
454-
vr: "VechordRegistry",
450+
vr: VechordRegistry,
455451
):
456452
ents, rels = await self.graph.recognize_with_relations(query)
457453
emb_func = (
@@ -499,40 +495,3 @@ def deduplicate_uid(uuids: Iterable[UUID], limit: Optional[int] = None) -> list[
499495
"""Maintain the order of the occurrence of UUIDs and deduplicate them."""
500496
uuids = {uid: None for uid in uuids}
501497
return list(uuids.keys())[:limit]
502-
503-
504-
class VechordPipeline:
505-
"""Set up the pipeline to run multiple functions in a transaction.
506-
507-
Args:
508-
client: :class:`VectorChordClient` to be used for the transaction.
509-
steps: a list of functions to be run in the pipeline. The first function
510-
will be used to accept the input, and the last function will be used
511-
to return the output. The rest of the functions will be used to
512-
process the data in between. The functions will be run in the order
513-
they are defined in the list.
514-
"""
515-
516-
def __init__(self, client: VechordClient, steps: list[Callable]):
517-
self.client = client
518-
self.steps = steps
519-
520-
async def run(self, *args, **kwargs) -> Any:
521-
"""Execute the pipeline in a transactional manner.
522-
523-
All the `args` and `kwargs` will be passed to the first function in the
524-
pipeline. The pipeline will run in *one* transaction, and all the `inject`
525-
can only see the data inserted in this transaction (to guarantee only the
526-
new inserted data will be processed in this pipeline).
527-
528-
This will also return the final result of the last function in the pipeline.
529-
"""
530-
async with (
531-
self.client.get_connection() as conn,
532-
limit_to_transaction_buffer_conn(conn),
533-
):
534-
# only the 1st one can accept input (could be empty)
535-
await self.steps[0](*args, **kwargs)
536-
for func in self.steps[1:-1]:
537-
await func()
538-
return await self.steps[-1]()

vechord/registry.py

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from functools import wraps
44
from inspect import isasyncgenfunction, iscoroutinefunction
55
from typing import (
6+
Any,
67
Callable,
78
Optional,
89
Sequence,
@@ -13,9 +14,12 @@
1314

1415
import numpy as np
1516

16-
from vechord.client import VechordClient, select_transaction_buffer_conn
17+
from vechord.client import (
18+
VechordClient,
19+
limit_to_transaction_buffer_conn,
20+
select_transaction_buffer_conn,
21+
)
1722
from vechord.log import logger
18-
from vechord.pipeline import VechordPipeline
1923
from vechord.spec import Table, Vector
2024

2125
T = TypeVar("T", bound=Table)
@@ -34,6 +38,43 @@ def get_iterator_type(typ) -> type:
3438
return get_iterator_type(typ.__args__[0])
3539

3640

41+
class VechordPipeline:
42+
"""Set up the pipeline to run multiple functions in a transaction.
43+
44+
Args:
45+
client: :class:`VechordClient` to be used for the transaction.
46+
steps: a list of functions to be run in the pipeline. The first function
47+
will be used to accept the input, and the last function will be used
48+
to return the output. The rest of the functions will be used to
49+
process the data in between. The functions will be run in the order
50+
they are defined in the list.
51+
"""
52+
53+
def __init__(self, client: VechordClient, steps: list[Callable]):
54+
self.client = client
55+
self.steps = steps
56+
57+
async def run(self, *args, **kwargs) -> Any:
58+
"""Execute the pipeline in a transactional manner.
59+
60+
All the `args` and `kwargs` will be passed to the first function in the
61+
pipeline. The pipeline will run in *one* transaction, and all the `inject`
62+
can only see the data inserted in this transaction (to guarantee only the
63+
new inserted data will be processed in this pipeline).
64+
65+
This will also return the final result of the last function in the pipeline.
66+
"""
67+
async with (
68+
self.client.get_connection() as conn,
69+
limit_to_transaction_buffer_conn(conn),
70+
):
71+
# only the 1st one can accept input (could be empty)
72+
await self.steps[0](*args, **kwargs)
73+
for func in self.steps[1:-1]:
74+
await func()
75+
return await self.steps[-1]()
76+
77+
3778
class VechordRegistry:
3879
"""Create a registry for the given namespace and PostgreSQL URL.
3980

0 commit comments

Comments
 (0)