Skip to content

Commit cd193b7

Browse files
authored
perf: avoid all heavy operations for cocoindex ls (#415)
* fix(cli): `ls` only needs flow names, flows don't need to be built * perf(ops): lazily import `sentence_transformer` as it's slow
1 parent 0f80d15 commit cd193b7

File tree

4 files changed

+18
-9
lines changed

4 files changed

+18
-9
lines changed

python/cocoindex/cli.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import asyncio
21
import click
32
import datetime
43
from rich.console import Console
@@ -21,7 +20,7 @@ def ls(show_all: bool):
2120
"""
2221
List all flows.
2322
"""
24-
current_flow_names = [fl.name for fl in flow.flows()]
23+
current_flow_names = flow.flow_names()
2524
persisted_flow_names = flow_names_with_setup()
2625
remaining_persisted_flow_names = set(persisted_flow_names)
2726

python/cocoindex/functions.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
"""All builtin functions."""
2-
from typing import Annotated, Any
2+
from typing import Annotated, Any, TYPE_CHECKING
33

4-
import sentence_transformers
54
from .typing import Float32, Vector, TypeAttr
65
from . import op, llm
76

7+
# Libraries that are heavy to import. Lazily import them later.
8+
if TYPE_CHECKING:
9+
import sentence_transformers
10+
811
class ParseJson(op.FunctionSpec):
912
"""Parse a text into a JSON object."""
1013

@@ -35,9 +38,10 @@ class SentenceTransformerEmbedExecutor:
3538
"""Executor for SentenceTransformerEmbed."""
3639

3740
spec: SentenceTransformerEmbed
38-
_model: sentence_transformers.SentenceTransformer
41+
_model: "sentence_transformers.SentenceTransformer"
3942

4043
def analyze(self, text):
44+
import sentence_transformers # pylint: disable=import-outside-toplevel
4145
args = self.spec.args or {}
4246
self._model = sentence_transformers.SentenceTransformer(self.spec.model, **args)
4347
dim = self._model.get_sentence_embedding_dimension()

python/cocoindex/op.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@
55
import dataclasses
66
import inspect
77

8-
from typing import get_type_hints, Protocol, Any, Callable, Awaitable, dataclass_transform
8+
from typing import Protocol, Any, Callable, Awaitable, dataclass_transform
99
from enum import Enum
1010

11-
from .typing import encode_enriched_type
11+
from .typing import encode_enriched_type, resolve_forward_ref
1212
from .convert import encode_engine_value, make_engine_value_decoder
1313
from . import _engine
1414

@@ -214,10 +214,11 @@ def _inner(cls: type[Executor]) -> type:
214214
"""
215215
Decorate a class to provide an executor for an op.
216216
"""
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__
218219
if 'spec' not in type_hints:
219220
raise TypeError("Expect a `spec` field with type hint")
220-
spec_cls = type_hints['spec']
221+
spec_cls = resolve_forward_ref(type_hints['spec'])
221222
sig = inspect.signature(cls.__call__)
222223
return _register_op_factory(
223224
category=spec_cls._op_category,

python/cocoindex/typing.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,3 +245,8 @@ def encode_enriched_type(t) -> dict[str, Any] | None:
245245
return None
246246

247247
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

0 commit comments

Comments
 (0)