refactor(api): enable strict typing for RAG keyword and vector base tests (#43895)

This commit is contained in:
Eddy ZHANG authored and GitHub committed 2026-10-12 03:50:52 +00:00
1 parent 1759587078
commit fa40cb8bbb
6 files changed
+56 -60

No files matched your search

@@ -1,7 +1,7 @@
from core.rag.datasource.keyword.jieba.stopwords import STOPWORDS
def test_stopwords_loaded():
def test_stopwords_loaded() -> None:
assert isinstance(STOPWORDS, frozenset)
assert "during" in STOPWORDS
assert "the" in STOPWORDS
@@ -1,4 +1,3 @@
from types import SimpleNamespace
from typing import override
import pytest
@@ -16,61 +15,61 @@ def _dataset() -> Dataset:
class _KeywordThatRaises(BaseKeyword):
@override
def create(self, texts: list[Document], session, **kwargs):
def create(self, texts: list[Document], session: Session, **kwargs: object) -> BaseKeyword:
return super().create(texts, session, **kwargs)
@override
def add_texts(self, texts: list[Document], session, **kwargs):
def add_texts(self, texts: list[Document], session: Session, **kwargs: object) -> None:
return super().add_texts(texts, session, **kwargs)
@override
def text_exists(self, id: str, *, session) -> bool:
def text_exists(self, id: str, *, session: Session) -> bool:
return super().text_exists(id, session=session)
@override
def delete_by_ids(self, ids: list[str], session, **kwargs):
def delete_by_ids(self, ids: list[str], session: Session, **kwargs: object) -> None:
return super().delete_by_ids(ids, session, **kwargs)
@override
def delete(self, *, session):
def delete(self, *, session: Session) -> None:
return super().delete(session=session)
@override
def search(self, query: str, *, session, **kwargs):
def search(self, query: str, *, session: Session, **kwargs: object) -> list[Document]:
return super().search(query, session=session, **kwargs)
class _KeywordForHelpers(BaseKeyword):
def __init__(self, dataset, existing_ids: set[str] | None = None):
def __init__(self, dataset: Dataset, existing_ids: set[str] | None = None) -> None:
super().__init__(dataset)
self._existing_ids = existing_ids or set()
@override
def create(self, texts: list[Document], session, **kwargs):
def create(self, texts: list[Document], session: Session, **kwargs: object) -> BaseKeyword:
return self
@override
def add_texts(self, texts: list[Document], session, **kwargs):
def add_texts(self, texts: list[Document], session: Session, **kwargs: object) -> None:
return None
@override
def text_exists(self, id: str, *, session) -> bool:
def text_exists(self, id: str, *, session: Session) -> bool:
return id in self._existing_ids
@override
def delete_by_ids(self, ids: list[str], session, **kwargs):
def delete_by_ids(self, ids: list[str], session: Session, **kwargs: object) -> None:
return None
@override
def delete(self, *, session):
def delete(self, *, session: Session) -> None:
return None
@override
def search(self, query: str, *, session, **kwargs):
def search(self, query: str, *, session: Session, **kwargs: object) -> list[Document]:
return []
def test_abstract_methods_raise_not_implemented(unbound_session: Session):
def test_abstract_methods_raise_not_implemented(unbound_session: Session) -> None:
keyword = _KeywordThatRaises(_dataset())
session = unbound_session
@@ -93,12 +92,12 @@ def test_abstract_methods_raise_not_implemented(unbound_session: Session):
keyword.search("query", session=session)
def test_filter_duplicate_texts_removes_existing_doc_ids(unbound_session: Session):
def test_filter_duplicate_texts_removes_existing_doc_ids(unbound_session: Session) -> None:
keyword = _KeywordForHelpers(_dataset(), existing_ids={"duplicate"})
texts = [
Document(page_content="keep", metadata={"doc_id": "keep"}),
Document(page_content="duplicate", metadata={"doc_id": "duplicate"}),
SimpleNamespace(page_content="without-metadata", metadata=None),
Document.model_construct(page_content="without-metadata", metadata=None),
]
filtered = keyword._filter_duplicate_texts(texts, session=unbound_session)
@@ -107,12 +106,12 @@ def test_filter_duplicate_texts_removes_existing_doc_ids(unbound_session: Sessio
assert any(text.metadata is None for text in filtered)
def test_get_uuids_returns_only_docs_with_metadata():
def test_get_uuids_returns_only_docs_with_metadata() -> None:
keyword = _KeywordForHelpers(_dataset())
texts = [
Document(page_content="doc-1", metadata={"doc_id": "doc-1"}),
Document(page_content="doc-2", metadata={"doc_id": "doc-2"}),
SimpleNamespace(page_content="doc-3", metadata=None),
Document.model_construct(page_content="doc-3", metadata=None),
]
assert keyword._get_uuids(texts) == ["doc-1", "doc-2"]
@@ -12,24 +12,24 @@ from models.dataset import Dataset
from tests.unit_tests.config_override import apply_config_overrides
def test_get_keyword_factory_returns_jieba_factory(monkeypatch: pytest.MonkeyPatch):
def test_get_keyword_factory_returns_jieba_factory(monkeypatch: pytest.MonkeyPatch) -> None:
fake_module = types.ModuleType("core.rag.datasource.keyword.jieba.jieba")
class FakeJieba:
pass
fake_module.Jieba = FakeJieba
vars(fake_module)["Jieba"] = FakeJieba
monkeypatch.setitem(sys.modules, "core.rag.datasource.keyword.jieba.jieba", fake_module)
assert Keyword.get_keyword_factory(KeyWordType.JIEBA) is FakeJieba
def test_get_keyword_factory_raises_for_unsupported_type():
def test_get_keyword_factory_raises_for_unsupported_type() -> None:
with pytest.raises(ValueError, match="Keyword store unsupported is not supported"):
Keyword.get_keyword_factory("unsupported")
def test_keyword_initialization_uses_configured_factory(monkeypatch: pytest.MonkeyPatch):
def test_keyword_initialization_uses_configured_factory(monkeypatch: pytest.MonkeyPatch) -> None:
dataset = Dataset(
id="dataset-1",
tenant_id="tenant-1",
@@ -47,7 +47,7 @@ def test_keyword_initialization_uses_configured_factory(monkeypatch: pytest.Monk
assert keyword._keyword_processor is fake_processor
def test_keyword_methods_forward_to_processor(unbound_session: Session):
def test_keyword_methods_forward_to_processor(unbound_session: Session) -> None:
processor = MagicMock()
processor.text_exists.return_value = True
processor.search.return_value = [Document(page_content="matched", metadata={"doc_id": "doc-1"})]
@@ -72,22 +72,22 @@ def test_keyword_methods_forward_to_processor(unbound_session: Session):
processor.search.assert_called_once_with("query", session=session, top_k=1)
def test_keyword_getattr_returns_callable_and_raises_for_invalid_attributes():
def test_keyword_getattr_returns_callable_and_raises_for_invalid_attributes() -> None:
class Processor:
value = 1
@staticmethod
def custom():
def custom() -> str:
return "ok"
keyword = Keyword.__new__(Keyword)
keyword._keyword_processor = Processor()
keyword._keyword_processor = Processor() # pyrefly: ignore[bad-assignment]
assert keyword.custom() == "ok"
with pytest.raises(AttributeError):
_ = keyword.value
keyword._keyword_processor = None
keyword._keyword_processor = None # pyrefly: ignore[bad-assignment]
with pytest.raises(AttributeError):
_ = keyword.missing_method
@@ -4,42 +4,42 @@ from core.rag.datasource.vdb.field import parse_metadata_json
class TestParseMetadataJson:
def test_none_returns_empty_dict(self):
def test_none_returns_empty_dict(self) -> None:
assert parse_metadata_json(None) == {}
def test_empty_string_returns_empty_dict(self):
def test_empty_string_returns_empty_dict(self) -> None:
assert parse_metadata_json("") == {}
def test_valid_json_string(self):
def test_valid_json_string(self) -> None:
result = parse_metadata_json('{"doc_id": "abc", "score": 0.9}')
assert result == {"doc_id": "abc", "score": 0.9}
def test_dict_passthrough(self):
def test_dict_passthrough(self) -> None:
original = {"doc_id": "abc", "document_id": "123"}
result = parse_metadata_json(original)
assert result == original
def test_empty_json_object(self):
def test_empty_json_object(self) -> None:
assert parse_metadata_json("{}") == {}
def test_invalid_json_raises_value_error(self):
def test_invalid_json_raises_value_error(self) -> None:
with pytest.raises(ValueError):
parse_metadata_json("{invalid json")
def test_nested_metadata(self):
def test_nested_metadata(self) -> None:
result = parse_metadata_json('{"doc_id": "1", "extra": {"nested": true}}')
assert result["extra"]["nested"] is True
def test_non_str_non_dict_returns_empty_dict(self):
def test_non_str_non_dict_returns_empty_dict(self) -> None:
assert parse_metadata_json(123) == {}
assert parse_metadata_json([1, 2]) == {}
def test_bytes_input(self):
def test_bytes_input(self) -> None:
result = parse_metadata_json(b'{"key": "value"}')
assert result == {"key": "value"}
def test_empty_bytes_returns_empty_dict(self):
def test_empty_bytes_returns_empty_dict(self) -> None:
assert parse_metadata_json(b"") == {}
def test_empty_bytearray_returns_empty_dict(self):
def test_empty_bytearray_returns_empty_dict(self) -> None:
assert parse_metadata_json(bytearray(b"")) == {}
@@ -1,4 +1,4 @@
from types import SimpleNamespace
from collections.abc import Callable
from typing import override
import pytest
@@ -8,7 +8,7 @@ from core.rag.models.document import Document
class _DummyVector(BaseVector):
def __init__(self, collection_name: str, existing_ids: set[str] | None = None):
def __init__(self, collection_name: str, existing_ids: set[str] | None = None) -> None:
super().__init__(collection_name)
self._existing_ids = existing_ids or set()
@@ -17,35 +17,35 @@ class _DummyVector(BaseVector):
return "dummy"
@override
def create(self, texts: list[Document], embeddings: list[list[float]], **kwargs):
def create(self, texts: list[Document], embeddings: list[list[float]], **kwargs: object) -> None:
return None
@override
def add_texts(self, documents: list[Document], embeddings: list[list[float]], **kwargs):
return None
def add_texts(self, documents: list[Document], embeddings: list[list[float]], **kwargs: object) -> list[str]:
return []
@override
def text_exists(self, id: str) -> bool:
return id in self._existing_ids
@override
def delete_by_ids(self, ids: list[str]):
def delete_by_ids(self, ids: list[str]) -> None:
return None
@override
def delete_by_metadata_field(self, key: str, value: str):
def delete_by_metadata_field(self, key: str, value: str) -> None:
return None
@override
def search_by_vector(self, query_vector: list[float], **kwargs):
def search_by_vector(self, query_vector: list[float], **kwargs: object) -> list[Document]:
return []
@override
def search_by_full_text(self, query: str, **kwargs):
def search_by_full_text(self, query: str, **kwargs: object) -> list[Document]:
return []
@override
def delete(self):
def delete(self) -> None:
return None
@@ -64,17 +64,19 @@ class _DummyVector(BaseVector):
(BaseVector.delete, ()),
],
)
def test_base_vector_default_methods_raise_not_implemented(base_method, args):
def test_base_vector_default_methods_raise_not_implemented(
base_method: Callable[..., object], args: tuple[object, ...]
) -> None:
vector = _DummyVector("collection_1")
with pytest.raises(NotImplementedError):
base_method(vector, *args)
def test_filter_duplicate_texts_removes_existing_docs():
def test_filter_duplicate_texts_removes_existing_docs() -> None:
vector = _DummyVector("collection_1", existing_ids={"dup"})
docs = [
SimpleNamespace(page_content="keep-no-meta", metadata=None),
Document.model_construct(page_content="keep-no-meta", metadata=None),
Document(page_content="keep-no-doc-id", metadata={"document_id": "d1"}),
Document(page_content="remove-dup", metadata={"doc_id": "dup"}),
Document(page_content="keep-unique", metadata={"doc_id": "unique"}),
@@ -85,11 +87,11 @@ def test_filter_duplicate_texts_removes_existing_docs():
assert [d.page_content for d in filtered] == ["keep-no-meta", "keep-no-doc-id", "keep-unique"]
def test_get_uuids_and_collection_name_property():
def test_get_uuids_and_collection_name_property() -> None:
vector = _DummyVector("collection_1")
docs = [
Document(page_content="a", metadata={"doc_id": "id-1"}),
SimpleNamespace(page_content="b", metadata=None),
Document.model_construct(page_content="b", metadata=None),
Document(page_content="c", metadata={"document_id": "d-1"}),
Document(page_content="d", metadata={"doc_id": "id-2"}),
]
-5
View File
@@ -393,12 +393,7 @@ project-excludes = [
"core/rag/data_post_processor/test_data_post_processor.py",
"core/rag/datasource/keyword/jieba/test_jieba.py",
"core/rag/datasource/keyword/jieba/test_jieba_keyword_table_handler.py",
"core/rag/datasource/keyword/jieba/test_stopwords.py",
"core/rag/datasource/keyword/test_keyword_base.py",
"core/rag/datasource/keyword/test_keyword_factory.py",
"core/rag/datasource/test_datasource_retrieval.py",
"core/rag/datasource/vdb/test_field.py",
"core/rag/datasource/vdb/test_vector_base.py",
"core/rag/datasource/vdb/test_vector_factory.py",
"core/rag/embedding/test_embedding_base.py",
"core/rag/embedding/test_embedding_service.py",