diff --git a/pyproject.toml b/pyproject.toml index ac0dab296..c7e5977fd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,7 +9,12 @@ description = "With CocoIndex, users declare the transformation, CocoIndex creat authors = [{ name = "CocoIndex", email = "cocoindex.io@gmail.com" }] readme = "README.md" requires-python = ">=3.11" -dependencies = ["sentence-transformers>=3.3.1", "click>=8.1.8", "rich>=14.0.0", "python-dotenv>=1.1.0"] +dependencies = [ + "sentence-transformers>=3.3.1", + "click>=8.1.8", + "rich>=14.0.0", + "python-dotenv>=1.1.0", +] license = "Apache-2.0" urls = { Homepage = "https://cocoindex.io/" } @@ -23,4 +28,9 @@ module-name = "cocoindex._engine" features = ["pyo3/extension-module"] [project.optional-dependencies] -test = ["pytest"] \ No newline at end of file +test = ["pytest"] + +[tool.mypy] +python_version = "3.11" +# Disable for not as we have missing type annotations. See https://github.com/cocoindex-io/cocoindex/issues/539 +# strict = true diff --git a/python/cocoindex/auth_registry.py b/python/cocoindex/auth_registry.py index 477b5a65c..9b1a20738 100644 --- a/python/cocoindex/auth_registry.py +++ b/python/cocoindex/auth_registry.py @@ -5,7 +5,7 @@ from dataclasses import dataclass from typing import Generic, TypeVar -from . import _engine +from . import _engine # type: ignore from .convert import dump_engine_object T = TypeVar("T") diff --git a/python/cocoindex/cli.py b/python/cocoindex/cli.py index 5990c83a5..01ce9f09b 100644 --- a/python/cocoindex/cli.py +++ b/python/cocoindex/cli.py @@ -90,6 +90,8 @@ def _load_user_app(app_target: str) -> types.ModuleType: raise ImportError(f"Could not create spec for file: {app_path}") module = importlib.util.module_from_spec(spec) sys.modules[spec.name] = module + if spec.loader is None: + raise ImportError(f"Could not create loader for file: {app_path}") spec.loader.exec_module(module) return module except (ImportError, FileNotFoundError, PermissionError) as e: @@ -145,20 +147,21 @@ def ls(app_target: str | None): If APP_TARGET is omitted, lists all flows that have a persisted setup in the backend. """ + persisted_flow_names = flow_names_with_setup() if app_target: app_ref = _get_app_ref_from_specifier(app_target) _load_user_app(app_ref) current_flow_names = set(flow.flow_names()) - persisted_flow_names = set(flow_names_with_setup()) if not current_flow_names: click.echo(f"No flows are defined in '{app_ref}'.") return has_missing = False + persisted_flow_names_set = set(persisted_flow_names) for name in sorted(current_flow_names): - if name in persisted_flow_names: + if name in persisted_flow_names_set: click.echo(name) else: click.echo(f"{name} [+]") @@ -170,13 +173,11 @@ def ls(app_target: str | None): click.echo(' [+]: Flows present in the current process, but missing setup.') else: - persisted_flow_names = sorted(flow_names_with_setup()) - if not persisted_flow_names: click.echo("No persisted flow setups found in the backend.") return - for name in persisted_flow_names: + for name in sorted(persisted_flow_names): click.echo(name) @cli.command() diff --git a/python/cocoindex/convert.py b/python/cocoindex/convert.py index 646e5bae2..54817e31a 100644 --- a/python/cocoindex/convert.py +++ b/python/cocoindex/convert.py @@ -7,7 +7,7 @@ import uuid from enum import Enum -from typing import Any, Callable, get_origin +from typing import Any, Callable, get_origin, Mapping from .typing import analyze_type_info, encode_enriched_type, is_namedtuple_type, TABLE_TYPES, KEY_FIELD_NAME @@ -104,13 +104,12 @@ def _make_engine_struct_value_decoder( src_name_to_idx = {f['name']: i for i, f in enumerate(src_fields)} - is_dataclass = dataclasses.is_dataclass(dst_struct_type) - is_namedtuple = is_namedtuple_type(dst_struct_type) - - if is_dataclass: + parameters: Mapping[str, inspect.Parameter] + if dataclasses.is_dataclass(dst_struct_type): parameters = inspect.signature(dst_struct_type).parameters - elif is_namedtuple: + elif is_namedtuple_type(dst_struct_type): defaults = getattr(dst_struct_type, '_field_defaults', {}) + fields = getattr(dst_struct_type, '_fields', ()) parameters = { name: inspect.Parameter( name=name, @@ -118,7 +117,7 @@ def _make_engine_struct_value_decoder( default=defaults.get(name, inspect.Parameter.empty), annotation=dst_struct_type.__annotations__.get(name, inspect.Parameter.empty) ) - for name in dst_struct_type._fields + for name in fields } else: raise ValueError(f"Unsupported struct type: {dst_struct_type}") diff --git a/python/cocoindex/flow.py b/python/cocoindex/flow.py index 4bb6b71e7..d02735a1e 100644 --- a/python/cocoindex/flow.py +++ b/python/cocoindex/flow.py @@ -17,7 +17,7 @@ from rich.text import Text from rich.tree import Tree -from . import _engine +from . import _engine # type: ignore from . import index from . import op from . import setting diff --git a/python/cocoindex/lib.py b/python/cocoindex/lib.py index c9333e779..6254fe6ac 100644 --- a/python/cocoindex/lib.py +++ b/python/cocoindex/lib.py @@ -4,7 +4,8 @@ import warnings from typing import Callable, Any -from . import _engine, flow, query, setting +from . import _engine # type: ignore +from . import flow, query, setting from .convert import dump_engine_object diff --git a/python/cocoindex/op.py b/python/cocoindex/op.py index 886c3ae48..495a27e4a 100644 --- a/python/cocoindex/op.py +++ b/python/cocoindex/op.py @@ -10,7 +10,7 @@ from .typing import encode_enriched_type, resolve_forward_ref from .convert import encode_engine_value, make_engine_value_decoder -from . import _engine +from . import _engine # type: ignore class OpCategory(Enum): """The category of the operation.""" @@ -101,7 +101,7 @@ def behavior_version(self): class _WrappedClass(executor_cls, _Fallback): _args_decoders: list[Callable[[Any], Any]] - _kwargs_decoders: dict[str, Callable[[str, Any], Any]] + _kwargs_decoders: dict[str, Callable[[Any], Any]] _acall: Callable def __init__(self, spec): @@ -247,13 +247,13 @@ def __call__(self, *args, **kwargs): return fn(*args, **kwargs) class _Spec(FunctionSpec): - pass + def __call__(self, *args, **kwargs): + return fn(*args, **kwargs) _Spec.__name__ = op_name _Spec.__doc__ = fn.__doc__ _Spec.__module__ = fn.__module__ _Spec.__qualname__ = fn.__qualname__ - _Spec.__wrapped__ = fn _register_op_factory( category=OpCategory.FUNCTION, diff --git a/python/cocoindex/query.py b/python/cocoindex/query.py index 7e2c51978..73624b790 100644 --- a/python/cocoindex/query.py +++ b/python/cocoindex/query.py @@ -4,7 +4,7 @@ from . import flow as fl from . import index -from . import _engine +from . import _engine # type: ignore _handlers_lock = Lock() _handlers: dict[str, _engine.SimpleSemanticsQueryHandler] = {} diff --git a/python/cocoindex/setup.py b/python/cocoindex/setup.py index 9c8e5e621..fe019e912 100644 --- a/python/cocoindex/setup.py +++ b/python/cocoindex/setup.py @@ -1,6 +1,6 @@ from . import flow from . import setting -from . import _engine +from . import _engine # type: ignore def sync_setup() -> _engine.SetupStatus: flow.ensure_all_flows_built() diff --git a/python/cocoindex/typing.py b/python/cocoindex/typing.py index dca0d19a0..d1dd6ccdb 100644 --- a/python/cocoindex/typing.py +++ b/python/cocoindex/typing.py @@ -5,7 +5,7 @@ import types import inspect import uuid -from typing import Annotated, NamedTuple, Any, TypeVar, TYPE_CHECKING, overload, Sequence, Protocol, Generic, Literal +from typing import Annotated, NamedTuple, Any, TypeVar, TYPE_CHECKING, overload, Sequence, Generic, Literal, Protocol class VectorInfo(NamedTuple): dim: int | None @@ -34,8 +34,11 @@ def __init__(self, key: str, value: Any): T_co = TypeVar('T_co', covariant=True) Dim_co = TypeVar('Dim_co', bound=int, covariant=True) - class Vector(Sequence[T_co], Generic[T_co, Dim_co], Protocol): + class Vector(Protocol, Generic[T_co, Dim_co]): """Vector[T, Dim] is a special typing alias for a list[T] with optional dimension info""" + def __getitem__(self, index: int) -> T_co: ... + def __len__(self) -> int: ... + else: class Vector: # type: ignore[unreachable] """ A special typing alias for a list[T] with optional dimension info """