chore(api): clear ruff debt in strict core unit tests (#44042)

This commit is contained in:
Eddy ZHANG authored and GitHub committed 2026-10-14 04:44:53 +00:00
1 parent 2ef9277e13
commit ba5532ace0
15 files changed
+47 -76

No files matched your search

-14
View File
@@ -131,15 +131,12 @@ extend-select = ["ANN401", "ARG"]
"core/callback_handler/test_workflow_tool_callback_handler.py" = ["ARG002"]
"core/datasource/__base/test_datasource_provider.py" = ["ARG002"]
"core/datasource/test_website_crawl.py" = ["ARG002"]
"core/datasource/utils/test_message_transformer.py" = ["ARG002"]
"core/entities/test_entities_mcp_provider.py" = ["ARG001"]
"core/entities/test_entities_provider_configuration.py" = ["ANN401", "ARG001", "ARG005", "TID251"]
"core/extension/test_extensible.py" = ["ARG002", "ARG005"]
"core/external_data_tool/api/test_api.py" = ["ARG001"]
"core/external_data_tool/test_base.py" = ["TID251"]
"core/external_data_tool/test_external_data_fetch.py" = ["ARG001"]
"core/helper/code_executor/test_code_executor.py" = ["TID251"]
"core/helper/code_executor/test_template_transformer.py" = ["ANN401", "TID251"]
"core/llm_generator/test_llm_generator.py" = ["ARG002"]
"core/mcp/auth/test_auth_flow.py" = ["ARG002"]
"core/mcp/client/test_session.py" = ["ARG001", "TID251"]
@@ -149,8 +146,6 @@ extend-select = ["ANN401", "ARG"]
"core/mcp/session/test_client_session.py" = ["ARG005"]
"core/mcp/test_mcp_client.py" = ["ARG002"]
"core/memory/test_token_buffer_memory.py" = ["ARG002"]
"core/moderation/test_content_moderation.py" = ["TID251"]
"core/moderation/test_output_moderation.py" = ["ARG001", "ARG002"]
"core/ops/test_base_trace_instance.py" = ["ARG001"]
"core/ops/test_lookup_helpers.py" = ["ARG002"]
"core/ops/test_ops_trace_manager.py" = ["ARG001", "ARG002", "ARG005"]
@@ -168,28 +163,21 @@ extend-select = ["ANN401", "ARG"]
"core/prompt/test_prompt_transform.py" = ["ARG005"]
"core/rag/datasource/keyword/jieba/test_jieba.py" = ["ARG001", "TID251"]
"core/rag/datasource/keyword/jieba/test_jieba_keyword_table_handler.py" = ["ARG004"]
"core/rag/datasource/keyword/test_keyword_factory.py" = ["ARG005"]
"core/rag/datasource/test_datasource_retrieval.py" = ["ARG001", "ARG002", "ARG005", "TID251"]
"core/rag/datasource/test_retrieval_attachment_access.py" = ["ARG005"]
"core/rag/datasource/vdb/test_vector_factory.py" = ["ARG002"]
"core/rag/embedding/test_embedding_base.py" = ["TID251"]
"core/rag/embedding/test_embedding_service.py" = ["ARG001"]
"core/rag/extractor/firecrawl/test_firecrawl.py" = ["TID251"]
"core/rag/extractor/test_csv_extractor.py" = ["ARG001", "ARG005"]
"core/rag/extractor/test_excel_extractor.py" = ["ARG002", "ARG005"]
"core/rag/extractor/test_extract_processor.py" = ["ARG001", "ARG005"]
"core/rag/extractor/test_helpers.py" = ["ARG002"]
"core/rag/extractor/test_markdown_extractor.py" = ["ARG001"]
"core/rag/extractor/test_pdf_extractor.py" = ["ARG001", "ARG005"]
"core/rag/extractor/test_text_extractor.py" = ["ARG001"]
"core/rag/extractor/test_word_extractor.py" = ["ARG001", "ARG002", "ARG005"]
"core/rag/extractor/unstructured/test_unstructured_extractors.py" = ["ARG001", "ARG005"]
"core/rag/extractor/watercrawl/test_watercrawl.py" = ["ARG001", "ARG005", "TID251"]
"core/rag/indexing/processor/conftest.py" = ["ANN401", "ARG002", "TID251"]
"core/rag/indexing/processor/test_paragraph_index_processor.py" = ["ARG002", "TID251"]
"core/rag/indexing/processor/test_qa_index_processor.py" = ["ARG001", "TID251"]
"core/rag/indexing/test_index_processor.py" = ["ARG005"]
"core/rag/pipeline/test_queue.py" = ["ARG002"]
"core/rag/retrieval/test_dataset_retrieval.py" = ["ARG001", "ARG002", "ARG005", "TID251"]
"core/rag/splitter/test_text_splitter.py" = ["ARG002", "ARG005"]
"core/repositories/test_celery_workflow_execution_repository.py" = ["ARG002"]
@@ -224,8 +212,6 @@ extend-select = ["ANN401", "ARG"]
"core/tools/utils/test_web_reader_tool.py" = ["ARG001", "ARG002", "ARG005"]
"core/tools/workflow_as_tool/test_provider.py" = ["TID251"]
"core/tools/workflow_as_tool/test_tool.py" = ["ANN401", "ARG001", "ARG005", "TID251"]
"core/trigger/conftest.py" = ["ANN401", "TID251"]
"core/variables/test_segment_type_validation.py" = ["TID251"]
"core/workflow/context/test_execution_context.py" = ["ANN401", "ARG002", "S110", "TID251"]
"core/workflow/context/test_flask_app_context.py" = ["ARG002"]
"core/workflow/generator/test_runner.py" = ["ARG001", "ARG002", "TID251"]
@@ -354,8 +354,8 @@ class TestDatasourceFileMessageTransformer:
assert result[0].type == DatasourceMessage.MessageType.BINARY_LINK
assert _text(result[0]) == "/files/datasources/blob_id_no_name.bin"
@patch("core.datasource.utils.message_transformer.ToolFileManager")
def test_transform_image_message_not_text_message(self, mock_tool_file_manager_cls: MagicMock) -> None:
@patch("core.datasource.utils.message_transformer.ToolFileManager", new=MagicMock())
def test_transform_image_message_not_text_message(self) -> None:
# This tests line 24-26 where it checks if message is instance of TextMessage
messages = [
DatasourceMessage(
@@ -254,12 +254,11 @@ class TestExtensible:
@patch("core.extension.extensible.os.listdir")
@patch("core.extension.extensible.os.path.isdir")
@patch("core.extension.extensible.os.path.exists")
@patch("core.extension.extensible.Path.read_text")
@patch("core.extension.extensible.Path.read_text", new=MagicMock())
@patch("core.extension.extensible.importlib.util.module_from_spec")
def test_scan_extensions_builtin_without_position_file(
self,
mock_module_from_spec: MagicMock,
mock_read_text: MagicMock,
mock_exists: MagicMock,
mock_isdir: MagicMock,
mock_listdir: MagicMock,
@@ -1,6 +1,6 @@
import json
from base64 import b64decode
from typing import Any
from typing import NoReturn
import pytest
@@ -43,7 +43,7 @@ def test_serialize_inputs_encodes_payload() -> None:
def test_transform_response_parses_json_result_and_converts_scientific_notation() -> None:
response = '<<RESULT>>{"value": "1e+3", "nested": {"x": "2E-2"}, "arr": ["3e+1"]}<<RESULT>>'
result: dict[str, Any] = _DummyTransformer.transform_response(response)
result: dict[str, object] = _DummyTransformer.transform_response(response)
assert result == {"value": 1000.0, "nested": {"x": 0.02}, "arr": [30.0]}
@@ -66,7 +66,7 @@ def test_transform_response_raises_for_non_string_keys(monkeypatch: pytest.Monke
def test_transform_response_raises_for_unexpected_errors(monkeypatch: pytest.MonkeyPatch) -> None:
def _raise_unexpected(_: str) -> Any:
def _raise_unexpected(_: str) -> NoReturn:
raise RuntimeError("boom")
monkeypatch.setattr("json.loads", _raise_unexpected)
@@ -10,7 +10,6 @@ This module tests all aspects of the content moderation system including:
- Configuration validation
"""
from typing import Any
from unittest.mock import MagicMock, Mock, patch
import pytest
@@ -29,7 +28,7 @@ class TestKeywordsModeration:
"""Test suite for custom keyword-based content moderation."""
@pytest.fixture
def keywords_config(self) -> dict[str, Any]:
def keywords_config(self) -> dict[str, object]:
"""
Fixture providing a standard keywords moderation configuration.
@@ -49,7 +48,7 @@ class TestKeywordsModeration:
}
@pytest.fixture
def keywords_moderation(self, keywords_config: dict[str, Any]) -> KeywordsModeration:
def keywords_moderation(self, keywords_config: dict[str, object]) -> KeywordsModeration:
"""
Fixture providing a KeywordsModeration instance.
@@ -65,7 +64,7 @@ class TestKeywordsModeration:
config=keywords_config,
)
def test_validate_config_success(self, keywords_config: dict[str, Any]) -> None:
def test_validate_config_success(self, keywords_config: dict[str, object]) -> None:
"""Test successful validation of keywords moderation configuration."""
# Should not raise any exception
KeywordsModeration.validate_config("test-tenant", keywords_config)
@@ -127,7 +126,7 @@ class TestKeywordsModeration:
with pytest.raises(ValueError, match="inputs_config.preset_response must be less than 100 characters"):
KeywordsModeration.validate_config("test-tenant", config)
def test_moderation_for_inputs_crlf_keywords_match(self, keywords_config: dict[str, Any]) -> None:
def test_moderation_for_inputs_crlf_keywords_match(self, keywords_config: dict[str, object]) -> None:
"""Keywords pasted with Windows line endings still match."""
keywords_config["keywords"] = "spam\r\nfree money"
moderation = KeywordsModeration(app_id="app", tenant_id="tenant", config=keywords_config)
@@ -136,7 +135,7 @@ class TestKeywordsModeration:
assert result.flagged is True
def test_moderation_whitespace_only_keyword_row_is_ignored(self, keywords_config: dict[str, Any]) -> None:
def test_moderation_whitespace_only_keyword_row_is_ignored(self, keywords_config: dict[str, object]) -> None:
"""A whitespace-only keyword row must not flag every message."""
keywords_config["keywords"] = "spam\n \n "
moderation = KeywordsModeration(app_id="app", tenant_id="tenant", config=keywords_config)
@@ -293,7 +292,7 @@ class TestOpenAIModeration:
"""Test suite for OpenAI-based content moderation."""
@pytest.fixture
def openai_config(self) -> dict[str, Any]:
def openai_config(self) -> dict[str, object]:
"""
Fixture providing OpenAI moderation configuration.
@@ -312,7 +311,7 @@ class TestOpenAIModeration:
}
@pytest.fixture
def openai_moderation(self, openai_config: dict[str, Any]) -> OpenAIModeration:
def openai_moderation(self, openai_config: dict[str, object]) -> OpenAIModeration:
"""
Fixture providing an OpenAIModeration instance.
@@ -328,7 +327,7 @@ class TestOpenAIModeration:
config=openai_config,
)
def test_validate_config_success(self, openai_config: dict[str, Any]) -> None:
def test_validate_config_success(self, openai_config: dict[str, object]) -> None:
"""Test successful validation of OpenAI moderation configuration."""
# Should not raise any exception
OpenAIModeration.validate_config("test-tenant", openai_config)
@@ -154,9 +154,7 @@ class TestOutputModeration:
result = output_moderation.moderation("tenant", "app", "buffer")
assert result is None
def test_worker_loop_and_exit(
self, output_moderation: OutputModeration, queue_manager: MessageBasedAppQueueManager
) -> None:
def test_worker_loop_and_exit(self, output_moderation: OutputModeration) -> None:
app = Flask(__name__)
# Test exit on thread_running=False
@@ -174,7 +172,7 @@ class TestOutputModeration:
output_moderation.is_final_chunk = True
# To avoid infinite loop, we'll set thread_running to False after one iteration
def side_effect[**P](*args: P.args, **kwargs: P.kwargs) -> object:
def side_effect(*_args: object, **_kwargs: object) -> object:
output_moderation.thread_running = False
return mock_moderation.return_value
@@ -210,7 +208,7 @@ class TestOutputModeration:
with patch.object(OutputModeration, "moderation") as mock_moderation:
# Use side_effect to change thread_running on second call
def side_effect[**P](*args: P.args, **kwargs: P.kwargs) -> object:
def side_effect(*_args: object, **_kwargs: object) -> object:
if mock_moderation.call_count > 1:
output_moderation.thread_running = False
return None
@@ -234,7 +232,7 @@ class TestOutputModeration:
output_moderation.buffer = "123" # length 3
output_moderation.is_final_chunk = False
def sleep_side_effect(seconds: float) -> None:
def sleep_side_effect(_seconds: float) -> None:
output_moderation.thread_running = False
mock_sleep.side_effect = sleep_side_effect
@@ -251,7 +249,7 @@ class TestOutputModeration:
# Return None (exception or no rule)
mock_moderation.return_value = None
def side_effect[**P](*args: P.args, **kwargs: P.kwargs) -> object:
def side_effect(*_args: object, **_kwargs: object) -> object:
output_moderation.thread_running = False
mock_moderation.side_effect = side_effect
@@ -40,7 +40,7 @@ def test_keyword_initialization_uses_configured_factory(monkeypatch: pytest.Monk
fake_processor = MagicMock()
apply_config_overrides(monkeypatch, KEYWORD_STORE=KeyWordType.JIEBA)
monkeypatch.setattr(Keyword, "get_keyword_factory", staticmethod(lambda keyword_type: lambda _: fake_processor))
monkeypatch.setattr(Keyword, "get_keyword_factory", staticmethod(lambda _keyword_type: lambda _: fake_processor))
keyword = Keyword(dataset)
@@ -2,7 +2,7 @@
import asyncio
import inspect
from typing import Any, override
from typing import override
import pytest
@@ -17,7 +17,7 @@ class ConcreteEmbeddings(Embeddings):
return [[1.0] * 10 for _ in texts]
@override
def embed_multimodal_documents(self, multimodel_documents: list[dict[str, Any]]) -> list[list[float]]:
def embed_multimodal_documents(self, multimodel_documents: list[dict[str, object]]) -> list[list[float]]:
return [[1.0] * 10 for _ in multimodel_documents]
@override
@@ -25,7 +25,7 @@ class ConcreteEmbeddings(Embeddings):
return [1.0] * 10
@override
def embed_multimodal_query(self, multimodel_document: dict[str, Any]) -> list[float]:
def embed_multimodal_query(self, multimodel_document: dict[str, object]) -> list[float]:
return [1.0] * 10
@@ -37,7 +37,7 @@ class _SuperCallingEmbeddings(Embeddings):
return super().embed_documents(texts)
@override
def embed_multimodal_documents(self, multimodel_documents: list[dict[str, Any]]) -> list[list[float]]:
def embed_multimodal_documents(self, multimodel_documents: list[dict[str, object]]) -> list[list[float]]:
return super().embed_multimodal_documents(multimodel_documents)
@override
@@ -45,7 +45,7 @@ class _SuperCallingEmbeddings(Embeddings):
return super().embed_query(text)
@override
def embed_multimodal_query(self, multimodel_document: dict[str, Any]) -> list[float]:
def embed_multimodal_query(self, multimodel_document: dict[str, object]) -> list[float]:
return super().embed_multimodal_query(multimodel_document)
@@ -119,7 +119,7 @@ class TestEmbeddingsBase:
def test_concrete_implementation_embed_multimodal_documents(self) -> None:
"""Test concrete implementation of embed_multimodal_documents."""
concrete = ConcreteEmbeddings()
docs: list[dict[str, Any]] = [{"file_id": "file1"}, {"file_id": "file2"}]
docs: list[dict[str, object]] = [{"file_id": "file1"}, {"file_id": "file2"}]
result = concrete.embed_multimodal_documents(docs)
assert len(result) == 2
@@ -2,7 +2,6 @@
import json
from collections.abc import Mapping
from typing import Any
from unittest.mock import MagicMock, create_autospec
import pytest
@@ -15,7 +14,7 @@ from services.data_source.provider_service import DatasourceProviderService
from services.data_source.website_service import WebsiteService
def _response(status_code: int, json_data: Mapping[str, Any] | None = None, text: str = "") -> MagicMock:
def _response(status_code: int, json_data: Mapping[str, object] | None = None, text: str = "") -> MagicMock:
response = MagicMock()
response.status_code = status_code
response.text = text
@@ -72,7 +72,7 @@ def test_extract_images_formats(
mock_page = MagicMock()
mock_image_obj = MagicMock()
def mock_extract(buf: io.BytesIO, fb_format: str | None = None) -> None:
def mock_extract(buf: io.BytesIO, **_kwargs: object) -> None:
buf.write(image_bytes)
mock_image_obj.extract.side_effect = mock_extract
@@ -118,8 +118,8 @@ def test_extract_images_formats(
],
)
@pytest.mark.parametrize("sqlite_session", [(UploadFile,)], indirect=True)
@pytest.mark.usefixtures("mock_dependencies")
def test_extract_images_get_objects_scenarios(
mock_dependencies: _Dependencies,
get_objects_side_effect: Exception | None,
get_objects_return_value: list[object] | None,
) -> None:
@@ -139,7 +139,8 @@ def test_extract_images_get_objects_scenarios(
@pytest.mark.parametrize("sqlite_session", [(UploadFile,)], indirect=True)
def test_extract_calls_extract_images(mock_dependencies: _Dependencies, monkeypatch: pytest.MonkeyPatch) -> None:
@pytest.mark.usefixtures("mock_dependencies")
def test_extract_calls_extract_images(monkeypatch: pytest.MonkeyPatch) -> None:
# Mock pypdfium2
mock_pdf_doc = MagicMock()
mock_page = MagicMock()
@@ -158,7 +159,7 @@ def test_extract_calls_extract_images(mock_dependencies: _Dependencies, monkeypa
extractor = pe.PdfExtractor(file_path="test.pdf", tenant_id=TENANT_ID, user_id=USER_ID)
# Mock _extract_images to return a known string
monkeypatch.setattr(extractor, "_extract_images", lambda p: "![image](img_url)")
monkeypatch.setattr(extractor, "_extract_images", lambda _page: "![image](img_url)")
documents = list(extractor.extract())
@@ -181,7 +182,7 @@ def test_extract_images_failures(mock_dependencies: _Dependencies) -> None:
# Second image is OK (JPEG)
jpeg_bytes = b"\xff\xd8\xff some image data"
def mock_extract(buf: io.BytesIO, fb_format: str | None = None) -> None:
def mock_extract(buf: io.BytesIO, **_kwargs: object) -> None:
buf.write(jpeg_bytes)
mock_image_obj_ok.extract.side_effect = mock_extract
@@ -36,7 +36,7 @@ class TestTextExtractor:
calls = []
def fake_read_text(self: Path, encoding: str | None = None) -> str:
def fake_read_text(_self: Path, encoding: str | None = None) -> str:
calls.append(encoding)
if encoding is None:
raise UnicodeDecodeError("utf-8", b"x", 0, 1, "decode")
@@ -59,7 +59,7 @@ class TestTextExtractor:
def test_extract_autodetect_all_fail_raises_runtime_error(self, monkeypatch: pytest.MonkeyPatch) -> None:
extractor = TextExtractor("dummy.txt", autodetect_encoding=True)
def always_decode_error(self: Path, encoding: str | None = None) -> str:
def always_decode_error(_self: Path, **_kwargs: object) -> str:
raise UnicodeDecodeError("utf-8", b"x", 0, 1, "decode")
monkeypatch.setattr(Path, "read_text", always_decode_error, raising=True)
@@ -73,7 +73,7 @@ class TestTextExtractor:
) -> None:
extractor = TextExtractor("dummy.txt", autodetect_encoding=False)
def always_decode_error(self: Path, encoding: str | None = None) -> str:
def always_decode_error(_self: Path, **_kwargs: object) -> str:
raise UnicodeDecodeError("utf-8", b"x", 0, 1, "decode")
monkeypatch.setattr(Path, "read_text", always_decode_error, raising=True)
@@ -84,7 +84,7 @@ class TestTextExtractor:
def test_extract_wraps_non_decode_exceptions(self, monkeypatch: pytest.MonkeyPatch) -> None:
extractor = TextExtractor("dummy.txt")
def raise_other(self: Path, encoding: str | None = None) -> str:
def raise_other(_self: Path, **_kwargs: object) -> str:
raise OSError("io error")
monkeypatch.setattr(Path, "read_text", raise_other, raising=True)
@@ -1,5 +1,4 @@
from contextlib import AbstractContextManager, nullcontext
from typing import Any
import pytest
@@ -10,7 +9,7 @@ class _FakeFlaskApp:
class _FakeExecutor:
def __init__(self, future: Any) -> None:
def __init__(self, future: object) -> None:
self._future = future
def __enter__(self) -> "_FakeExecutor":
@@ -19,7 +18,7 @@ class _FakeExecutor:
def __exit__(self, exc_type: object, exc_value: object, traceback: object) -> bool:
return False
def submit(self, func: object, preview: object) -> Any:
def submit(self, *_args: object) -> object:
return self._future
@@ -75,13 +75,7 @@ class TestTenantIsolatedTaskQueue:
"""Test cases for TenantIsolatedTaskQueue functionality."""
@pytest.fixture
def mock_redis_client(self) -> MagicMock:
"""Mock Redis client for testing."""
mock_redis = MagicMock()
return mock_redis
@pytest.fixture
def sample_queue(self, mock_redis_client: MagicMock) -> TenantIsolatedTaskQueue:
def sample_queue(self) -> TenantIsolatedTaskQueue:
"""Create a sample TenantIsolatedTaskQueue instance."""
return TenantIsolatedTaskQueue("tenant-123", "test-key")
@@ -2,8 +2,6 @@
from __future__ import annotations
from typing import Any
from core.entities.provider_entities import ProviderConfig
from core.tools.entities.common_entities import I18nObject
from core.trigger.entities.entities import (
@@ -72,15 +70,14 @@ def make_controller(
)
def make_subscription(**overrides: Any) -> Subscription:
defaults = {
def make_subscription(**overrides: object) -> Subscription:
defaults: dict[str, object] = {
"expires_at": 9999999999,
"endpoint": "https://hook.test",
"properties": {"k": "v"},
"parameters": dict[str, object](),
}
defaults.update(overrides)
return Subscription(**defaults)
return Subscription.model_validate(defaults | overrides)
def make_provider_config(
@@ -6,7 +6,6 @@ including edge cases, error conditions, and different ArrayValidation strategies
"""
from dataclasses import dataclass
from typing import Any
import pytest
@@ -52,7 +51,7 @@ class ValidationTestCase:
"""Test case data structure for validation tests."""
segment_type: SegmentType
value: Any
value: object
expected: bool
description: str
@@ -65,7 +64,7 @@ class ArrayValidationTestCase:
"""Test case data structure for array validation tests."""
segment_type: SegmentType
value: Any
value: object
array_validation: ArrayValidation
expected: bool
description: str
@@ -561,7 +560,7 @@ class TestSegmentTypeIsValid:
for segment_type in all_segment_types:
# Create a valid test value for each type
test_value: Any = None
test_value: object = None
if segment_type == SegmentType.STRING:
test_value = "test"
elif segment_type in {SegmentType.NUMBER, SegmentType.INTEGER}:
@@ -730,7 +729,7 @@ class TestSegmentTypeValidationIntegration:
for segment_type in non_array_types:
# Create appropriate valid value for each type
valid_value: Any
valid_value: object
if segment_type == SegmentType.STRING:
valid_value = "test"
elif segment_type == SegmentType.NUMBER: