Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ integration-only-slow = 'pytest --maxfail=5 -m "integration and slow" {args:test
all = 'pytest {args:test}'

# TODO We want to eventually type the whole test folder
types = "mypy --install-types --non-interactive --cache-dir=.mypy_cache/ {args:haystack test/core/ test/marshal/ test/testing/ test/tracing/}"
types = "mypy --install-types --non-interactive --cache-dir=.mypy_cache/ {args:haystack test/core/ test/marshal/ test/testing/ test/tracing/ test/human_in_the_loop test/evaluation test/document_stores test/dataclasses}"

[tool.hatch.envs.e2e]
template = "test"
Expand Down
30 changes: 20 additions & 10 deletions test/dataclasses/test_chat_message.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import json
import warnings
from collections.abc import Sequence

import pytest

Expand Down Expand Up @@ -306,7 +307,7 @@ def test_from_assistant_with_reasoning_string(self):

def test_from_assistant_with_invalid_reasoning(self):
with pytest.raises(TypeError):
ChatMessage.from_assistant(text="text", reasoning=123)
ChatMessage.from_assistant(text="text", reasoning=123) # type: ignore[arg-type]

def test_from_user_with_valid_content(self):
text = "I have a question."
Expand Down Expand Up @@ -354,7 +355,7 @@ def test_from_user_empty_text(self):
assert message.texts == [""]

def test_from_user_with_content_parts(self, base64_image_string, base64_pdf_string):
content_parts = [
content_parts: list[TextContent | ImageContent | FileContent | str] = [
TextContent(text="text"),
ImageContent(base64_image=base64_image_string),
FileContent(base64_data=base64_pdf_string),
Expand Down Expand Up @@ -393,7 +394,7 @@ def test_from_user_with_content_parts(self, base64_image_string, base64_pdf_stri
def test_from_user_with_content_parts_fails_unsupported_parts(self):
with pytest.raises(TypeError):
ChatMessage.from_user(
content_parts=["text part", ToolCall(id="123", tool_name="mytool", arguments={"a": 1})]
content_parts=["text part", ToolCall(id="123", tool_name="mytool", arguments={"a": 1})] # type: ignore[list-item]
)

def test_from_user_with_content_parts_fails_with_empty_parts(self):
Expand Down Expand Up @@ -442,7 +443,10 @@ def test_from_tool_with_valid_content(self):
assert not message.reasoning

def test_from_tool_with_valid_mixed_content(self, base64_image_string):
tool_result = [TextContent(text="Hello"), ImageContent(base64_image=base64_image_string, mime_type="image/png")]
tool_result: list[TextContent | ImageContent] = [
TextContent(text="Hello"),
ImageContent(base64_image=base64_image_string, mime_type="image/png"),
]
message = ChatMessage.from_tool(
tool_result=tool_result, origin=ToolCall(tool_name="mytool", arguments={}), error=False
)
Expand Down Expand Up @@ -472,7 +476,10 @@ def test_multiple_text_segments(self):
assert len(message) == 2

def test_mixed_content(self):
content = [TextContent(text="Hello"), ToolCall(id="123", tool_name="mytool", arguments={"a": 1})]
content: list[TextContent | ToolCall] = [
TextContent(text="Hello"),
ToolCall(id="123", tool_name="mytool", arguments={"a": 1}),
]

message = ChatMessage(_role=ChatRole.ASSISTANT, _content=content)

Expand All @@ -485,16 +492,16 @@ def test_mixed_content(self):

def test_from_function_class_method_removed(self):
with pytest.raises(AttributeError):
ChatMessage.from_function("Result of function invocation", "my_function")
ChatMessage.from_function("Result of function invocation", "my_function") # type: ignore[attr-defined]

def test_chat_message_content_attribute_removed(self):
message = ChatMessage.from_user(text="This is a message")
with pytest.raises(AttributeError):
message.content
message.content # type: ignore[attr-defined]

def test_chat_message_init_parameters_removed(self):
with pytest.raises(TypeError):
ChatMessage(role="irrelevant", content="This is a message")
ChatMessage(role="irrelevant", content="This is a message") # type: ignore[call-arg]

def test_no_warning_on_init(self):
with warnings.catch_warnings():
Expand Down Expand Up @@ -572,7 +579,7 @@ def test_to_dict_with_invalid_content_type(self):
text_content = TextContent(text="Hello")
invalid_content = "invalid"

message = ChatMessage(_role=ChatRole.ASSISTANT, _content=[text_content, invalid_content])
message = ChatMessage(_role=ChatRole.ASSISTANT, _content=[text_content, invalid_content]) # type: ignore[list-item]

with pytest.raises(TypeError):
message.to_dict()
Expand Down Expand Up @@ -888,7 +895,7 @@ def test_to_openai_dict_format_require_tool_call_ids_false(self):
assert openai_msg == {"role": "tool", "content": "result"}

def test_to_openai_dict_format_tool_message_list_with_unsupported_image(self, base64_image_string):
tool_result = [
tool_result: Sequence[TextContent | ImageContent] = [
TextContent(text="first result"),
ImageContent(base64_image=base64_image_string, mime_type="image/png"),
]
Expand Down Expand Up @@ -940,6 +947,7 @@ def test_from_openai_dict_format_tool_message(self):
openai_msg = {"role": "tool", "content": "The weather is sunny", "tool_call_id": "call_123"}
message = ChatMessage.from_openai_dict_format(openai_msg)
assert message.role.value == "tool"
assert message.tool_call_result is not None
assert message.tool_call_result.result == "The weather is sunny"
assert message.tool_call_result.origin.id == "call_123"

Expand All @@ -951,13 +959,15 @@ def test_from_openai_dict_format_tool_message_list(self):
}
message = ChatMessage.from_openai_dict_format(openai_msg)
assert message.role.value == "tool"
assert message.tool_call_result is not None
assert message.tool_call_result.result == [TextContent(text="first result"), TextContent(text="second result")]
assert message.tool_call_result.origin.id == "call_123"

def test_from_openai_dict_format_tool_without_id(self):
openai_msg = {"role": "tool", "content": "The weather is sunny"}
message = ChatMessage.from_openai_dict_format(openai_msg)
assert message.role.value == "tool"
assert message.tool_call_result is not None
assert message.tool_call_result.result == "The weather is sunny"
assert message.tool_call_result.origin.id is None

Expand Down
7 changes: 4 additions & 3 deletions test/dataclasses/test_document.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ def test_init():

def test_init_with_wrong_parameters():
with pytest.raises(TypeError):
Document(text="")
Document(text="") # type: ignore[call-arg]


def test_init_with_parameters():
Expand All @@ -53,6 +53,7 @@ def test_init_with_parameters():
)
assert doc.id == "1aa43af57c1dbc317241bf55d3067049f334d3b458d95dc72f71a7111f6c1a56"
assert doc.content == "test text"
assert doc.blob is not None
assert doc.blob.data == blob_data
assert doc.blob.mime_type == "text/markdown"
assert doc.meta == {"text": "test text"}
Expand Down Expand Up @@ -88,7 +89,7 @@ def test_init_with_legacy_field():
doc = Document(
content="test text",
content_type="text", # type: ignore
id_hash_keys=["content"], # type: ignore
id_hash_keys=["content"],
score=0.812,
embedding=[0.1, 0.2, 0.3],
meta={"date": "10-10-2023", "type": "article"},
Expand Down Expand Up @@ -265,7 +266,7 @@ def test_from_dict_with_legacy_field_and_flat_meta():
) == Document(
content="test text",
content_type="text", # type: ignore
id_hash_keys=["content"], # type: ignore
id_hash_keys=["content"],
score=0.812,
embedding=[0.1, 0.2, 0.3],
meta={"date": "10-10-2023", "type": "article"},
Expand Down
13 changes: 10 additions & 3 deletions test/dataclasses/test_streaming_chunk.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,16 @@
ToolCallDelta,
ToolCallResult,
)
from haystack.dataclasses.streaming_chunk import FinishReason


@component
class ExampleComponent:
def __init__(self):
self.name = "test_component"

def run(self) -> str:
return "Test content"
def run(self) -> dict[str, str]:
return {"test": "Test content"}


def test_create_chunk_with_content_and_metadata():
Expand Down Expand Up @@ -143,7 +144,7 @@ def test_create_chunk_with_finish_reason_and_meta():

def test_finish_reason_standard_values():
"""Test all standard finish_reason values including the new Haystack-specific ones."""
standard_values = ["stop", "length", "tool_calls", "content_filter", "tool_call_results"]
standard_values: list[FinishReason] = ["stop", "length", "tool_calls", "content_filter", "tool_call_results"]

for value in standard_values:
chunk = StreamingChunk(content="Test content", finish_reason=value)
Expand Down Expand Up @@ -271,8 +272,10 @@ def test_from_dict_tool_call_result():
assert chunk.content == ""
assert chunk.meta == {"key": "value"}
assert chunk.index == 0
assert chunk.component_info is not None
assert chunk.component_info.type == "test_streaming_chunk.ExampleComponent"
assert chunk.component_info.name == "test_component"
assert chunk.tool_call_result is not None
assert chunk.tool_call_result.result == "output"
assert chunk.tool_call_result.error is False
assert chunk.tool_call_result.origin.id == "123"
Expand All @@ -298,8 +301,10 @@ def test_from_dict_tool_calls():
assert chunk.content == ""
assert chunk.meta == {"key": "value"}
assert chunk.index == 0
assert chunk.component_info is not None
assert chunk.component_info.type == "test_streaming_chunk.ExampleComponent"
assert chunk.component_info.name == "test_component"
assert chunk.tool_calls is not None
assert chunk.tool_calls[0].tool_name == "test_tool"
assert chunk.tool_calls[0].index == 0
assert chunk.finish_reason == "tool_calls"
Expand All @@ -325,8 +330,10 @@ def test_from_dict_reasoning():
assert chunk.content == ""
assert chunk.meta == {"key": "value"}
assert chunk.index == 0
assert chunk.component_info is not None
assert chunk.component_info.type == "test_streaming_chunk.ExampleComponent"
assert chunk.component_info.name == "test_component"
assert chunk.reasoning is not None
assert chunk.reasoning.reasoning_text == "thinking"
assert chunk.reasoning.extra["step"] == 1
assert chunk.finish_reason == "stop"
Expand Down
4 changes: 3 additions & 1 deletion test/document_stores/test_filter_policy.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
#
# SPDX-License-Identifier: Apache-2.0

from typing import Literal

import pytest

from haystack.document_stores.types import FilterPolicy, apply_filter_policy
Expand Down Expand Up @@ -168,7 +170,7 @@ def test_merge_comparison_filters_with_same_field():


@pytest.mark.parametrize("logical_operator", ["AND", "OR", "NOT"])
def test_merge_with_custom_logical_operator(logical_operator: str):
def test_merge_with_custom_logical_operator(logical_operator: Literal["AND", "OR", "NOT"]) -> None:
"""
Merging with a custom logical operator

Expand Down
Loading
Loading