diff --git a/pyproject.toml b/pyproject.toml index 00ba526..a58f948 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -42,5 +42,5 @@ asyncio_default_fixture_loop_scope = "function" extend-exclude = ["tests"] [tool.ruff.lint] -extend-select = ["I", "D", "ERA", "UP"] +extend-select = ["I", "D", "ERA", "UP", "FURB", "TRY", "PERF"] ignore = ["D203", "D213"] diff --git a/src/vector_search_mcp/engine/__init__.py b/src/vector_search_mcp/engine/__init__.py index 0019cdb..842ced7 100644 --- a/src/vector_search_mcp/engine/__init__.py +++ b/src/vector_search_mcp/engine/__init__.py @@ -28,6 +28,14 @@ from typing import Literal, overload from .qdrant_engine import QdrantEngine +class UnknownEngineError(Exception): + """Exception raised when an unknown engine is requested.""" + + def __init__(self, backend: str): + """Initialize the exception with the unknown backend.""" + super().__init__(f"Unknown engine type: {backend}") + + class Backend(StrEnum): """Enumeration of supported vector database backends. @@ -96,4 +104,4 @@ def get_engine(backend: Backend): elif backend == Backend.COSMOS: raise NotImplementedError("Cosmos engine is not implemented yet") else: - raise ValueError(f"Unknown engine type: {backend}") + raise UnknownEngineError(backend) diff --git a/src/vector_search_mcp/engine/base_engine.py b/src/vector_search_mcp/engine/base_engine.py index beb8b2c..b9c4a07 100644 --- a/src/vector_search_mcp/engine/base_engine.py +++ b/src/vector_search_mcp/engine/base_engine.py @@ -12,7 +12,7 @@ maintaining a consistent interface for the semantic search workflow. """ from abc import ABC, abstractmethod -from typing import Generic, TypeVar +from typing import TypeVar from ..models import Condition, SearchRow @@ -22,7 +22,7 @@ ConditionType = TypeVar("ConditionType") __all__ = ["BaseEngine"] -class BaseEngine(ABC, Generic[ResponseType, ConditionType]): +class BaseEngine[ResponseType, ConditionType](ABC): """Abstract base class for vector search engines. This class defines the interface that all vector search engine implementations diff --git a/tests/test_engine/test_factory.py b/tests/test_engine/test_factory.py index 74e5629..c7c64cc 100644 --- a/tests/test_engine/test_factory.py +++ b/tests/test_engine/test_factory.py @@ -2,7 +2,7 @@ from unittest.mock import MagicMock, patch import pytest -from vector_search_mcp.engine import Backend, get_engine +from vector_search_mcp.engine import Backend, get_engine, UnknownEngineError from vector_search_mcp.engine.base_engine import BaseEngine from vector_search_mcp.engine.qdrant_engine import QdrantEngine @@ -52,7 +52,7 @@ class TestEngineFactory: # Create an invalid engine type (bypassing enum validation) invalid_type = "invalid_engine" - with pytest.raises(ValueError, match="Unknown engine type: invalid_engine"): + with pytest.raises(UnknownEngineError, match="Unknown engine type: invalid_engine"): # We need to cast to bypass type checking get_engine(invalid_type) # type: ignore @@ -234,22 +234,22 @@ class TestEngineFactoryErrorHandling: def test_none_backend_type(self): """Test get_engine with None raises appropriate error""" - with pytest.raises((TypeError, ValueError)): + with pytest.raises((TypeError, UnknownEngineError)): get_engine(None) # type: ignore def test_empty_string_backend_type(self): """Test get_engine with empty string""" - with pytest.raises(ValueError, match="Unknown engine type"): + with pytest.raises(UnknownEngineError, match="Unknown engine type"): get_engine("") # type: ignore def test_numeric_backend_type(self): """Test get_engine with numeric input""" - with pytest.raises((TypeError, ValueError)): + with pytest.raises((TypeError, UnknownEngineError)): get_engine(123) # type: ignore def test_boolean_backend_type(self): """Test get_engine with boolean input""" - with pytest.raises((TypeError, ValueError)): + with pytest.raises((TypeError, UnknownEngineError)): get_engine(True) # type: ignore def test_get_engine_cosmos_not_implemented(self): @@ -273,16 +273,16 @@ class TestEngineFactoryErrorHandling: def test_case_sensitive_backend_type(self): """Test that backend type matching is case sensitive""" - with pytest.raises(ValueError, match="Unknown engine type"): + with pytest.raises(UnknownEngineError, match="Unknown engine type"): get_engine("QDRANT") # type: ignore - with pytest.raises(ValueError, match="Unknown engine type"): + with pytest.raises(UnknownEngineError, match="Unknown engine type"): get_engine("Qdrant") # type: ignore def test_whitespace_backend_type(self): """Test backend type with whitespace""" - with pytest.raises(ValueError, match="Unknown engine type"): + with pytest.raises(UnknownEngineError, match="Unknown engine type"): get_engine(" qdrant ") # type: ignore - with pytest.raises(ValueError, match="Unknown engine type"): + with pytest.raises(UnknownEngineError, match="Unknown engine type"): get_engine("\tqdrant\n") # type: ignore