standard-tests: Ruff autofixes (#31862)

Auto-fixes from ruff with rule ALL
This commit is contained in:
Christophe Bornet 2025-07-07 16:27:39 +02:00 committed by GitHub
parent 2df3fdf40d
commit 9368b92b2c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
19 changed files with 120 additions and 178 deletions

View File

@ -1,5 +1,4 @@
""" """Base Test classes for standard testing.
Base Test classes for standard testing.
To learn how to use these classes, see the To learn how to use these classes, see the
`Integration standard testing <https://python.langchain.com/docs/contributing/how_to/integrations/standard_tests/>`_ `Integration standard testing <https://python.langchain.com/docs/contributing/how_to/integrations/standard_tests/>`_

View File

@ -2,13 +2,10 @@ from abc import ABC
class BaseStandardTests(ABC): class BaseStandardTests(ABC):
""" """:private:"""
:private:
"""
def test_no_overrides_DO_NOT_OVERRIDE(self) -> None: def test_no_overrides_DO_NOT_OVERRIDE(self) -> None:
""" """Test that no standard tests are overridden.
Test that no standard tests are overridden.
:private: :private:
""" """
@ -22,10 +19,11 @@ class BaseStandardTests(ABC):
if comparison_class is None: if comparison_class is None:
comparison_class = base comparison_class = base
else: else:
raise ValueError( msg = (
"Multiple standard test base classes found: " "Multiple standard test base classes found: "
f"{comparison_class}, {base}" f"{comparison_class}, {base}"
) )
raise ValueError(msg)
else: else:
explore_bases(base) explore_bases(base)
@ -34,12 +32,10 @@ class BaseStandardTests(ABC):
print(f"Comparing {self.__class__} to {comparison_class}") # noqa: T201 print(f"Comparing {self.__class__} to {comparison_class}") # noqa: T201
running_tests = set( running_tests = {method for method in dir(self) if method.startswith("test_")}
[method for method in dir(self) if method.startswith("test_")] base_tests = {
) method for method in dir(comparison_class) if method.startswith("test_")
base_tests = set( }
[method for method in dir(comparison_class) if method.startswith("test_")]
)
deleted_tests = base_tests - running_tests deleted_tests = base_tests - running_tests
assert not deleted_tests, f"Standard tests deleted: {deleted_tests}" assert not deleted_tests, f"Standard tests deleted: {deleted_tests}"

View File

@ -52,9 +52,8 @@ class CustomPersister:
# If cassette path is already Path this is a no-op # If cassette path is already Path this is a no-op
cassette_path = Path(cassette_path) cassette_path = Path(cassette_path)
if not cassette_path.is_file(): if not cassette_path.is_file():
raise CassetteNotFoundError( msg = f"Cassette file {cassette_path} does not exist."
f"Cassette file {cassette_path} does not exist." raise CassetteNotFoundError(msg)
)
with cassette_path.open(mode="rb") as f: with cassette_path.open(mode="rb") as f:
data = f.read() data = f.read()
deser = serializer.deserialize(data) deser = serializer.deserialize(data)

View File

@ -26,13 +26,13 @@ from .tools import ToolsIntegrationTests
from .vectorstores import VectorStoreIntegrationTests from .vectorstores import VectorStoreIntegrationTests
__all__ = [ __all__ = [
"ChatModelIntegrationTests", "AsyncCacheTestSuite",
"EmbeddingsIntegrationTests",
"ToolsIntegrationTests",
"BaseStoreAsyncTests", "BaseStoreAsyncTests",
"BaseStoreSyncTests", "BaseStoreSyncTests",
"AsyncCacheTestSuite", "ChatModelIntegrationTests",
"SyncCacheTestSuite", "EmbeddingsIntegrationTests",
"VectorStoreIntegrationTests",
"RetrieversIntegrationTests", "RetrieversIntegrationTests",
"SyncCacheTestSuite",
"ToolsIntegrationTests",
"VectorStoreIntegrationTests",
] ]

View File

@ -1,5 +1,4 @@
""" """Standard tests for the BaseStore abstraction.
Standard tests for the BaseStore abstraction
We don't recommend implementing externally managed BaseStore abstractions at this time. We don't recommend implementing externally managed BaseStore abstractions at this time.
@ -38,10 +37,9 @@ class BaseStoreSyncTests(BaseStandardTests, Generic[V]):
""" """
@abstractmethod @abstractmethod
@pytest.fixture() @pytest.fixture
def three_values(self) -> tuple[V, V, V]: def three_values(self) -> tuple[V, V, V]:
"""Three example values that will be used in the tests.""" """Three example values that will be used in the tests."""
pass
def test_three_values(self, three_values: tuple[V, V, V]) -> None: def test_three_values(self, three_values: tuple[V, V, V]) -> None:
"""Test that the fixture provides three values.""" """Test that the fixture provides three values."""
@ -169,10 +167,9 @@ class BaseStoreAsyncTests(BaseStandardTests, Generic[V]):
""" """
@abstractmethod @abstractmethod
@pytest.fixture() @pytest.fixture
def three_values(self) -> tuple[V, V, V]: def three_values(self) -> tuple[V, V, V]:
"""Three example values that will be used in the tests.""" """Three example values that will be used in the tests."""
pass
async def test_three_values(self, three_values: tuple[V, V, V]) -> None: async def test_three_values(self, three_values: tuple[V, V, V]) -> None:
"""Test that the fixture provides three values.""" """Test that the fixture provides three values."""

View File

@ -1,5 +1,4 @@
""" """Standard tests for the BaseCache abstraction.
Standard tests for the BaseCache abstraction
We don't recommend implementing externally managed BaseCache abstractions at this time. We don't recommend implementing externally managed BaseCache abstractions at this time.

View File

@ -41,9 +41,7 @@ from langchain_tests.utils.pydantic import PYDANTIC_MAJOR_VERSION
def _get_joke_class( def _get_joke_class(
schema_type: Literal["pydantic", "typeddict", "json_schema"], schema_type: Literal["pydantic", "typeddict", "json_schema"],
) -> Any: ) -> Any:
""" """:private:"""
:private:
"""
class Joke(BaseModel): class Joke(BaseModel):
"""Joke to tell user.""" """Joke to tell user."""
@ -61,18 +59,18 @@ def _get_joke_class(
punchline: Annotated[str, ..., "answer to resolve the joke"] punchline: Annotated[str, ..., "answer to resolve the joke"]
def validate_joke_dict(result: Any) -> bool: def validate_joke_dict(result: Any) -> bool:
return all(key in ["setup", "punchline"] for key in result.keys()) return all(key in ["setup", "punchline"] for key in result)
if schema_type == "pydantic": if schema_type == "pydantic":
return Joke, validate_joke return Joke, validate_joke
elif schema_type == "typeddict": if schema_type == "typeddict":
return JokeDict, validate_joke_dict return JokeDict, validate_joke_dict
elif schema_type == "json_schema": if schema_type == "json_schema":
return Joke.model_json_schema(), validate_joke_dict return Joke.model_json_schema(), validate_joke_dict
else: msg = "Invalid schema type"
raise ValueError("Invalid schema type") raise ValueError(msg)
class _TestCallbackHandler(BaseCallbackHandler): class _TestCallbackHandler(BaseCallbackHandler):
@ -879,8 +877,7 @@ class ChatModelIntegrationTests(ChatModelTests):
assert len(result.content) > 0 assert len(result.content) > 0
def test_double_messages_conversation(self, model: BaseChatModel) -> None: def test_double_messages_conversation(self, model: BaseChatModel) -> None:
""" """Test to verify that the model can handle double-message conversations.
Test to verify that the model can handle double-message conversations.
This should pass for all integrations. Tests the model's ability to process This should pass for all integrations. Tests the model's ability to process
a sequence of double-system, double-human, and double-ai messages as context a sequence of double-system, double-human, and double-ai messages as context
@ -1083,7 +1080,8 @@ class ChatModelIntegrationTests(ChatModelTests):
assert usage_metadata.get("input_tokens", 0) >= total_detailed_tokens assert usage_metadata.get("input_tokens", 0) >= total_detailed_tokens
def test_usage_metadata_streaming(self, model: BaseChatModel) -> None: def test_usage_metadata_streaming(self, model: BaseChatModel) -> None:
""" """Test usage metadata in streaming mode.
Test to verify that the model returns correct usage metadata in streaming mode. Test to verify that the model returns correct usage metadata in streaming mode.
.. versionchanged:: 0.3.17 .. versionchanged:: 0.3.17
@ -1193,7 +1191,7 @@ class ChatModelIntegrationTests(ChatModelTests):
"Only one chunk should set input_tokens," "Only one chunk should set input_tokens,"
" the rest should be 0 or None" " the rest should be 0 or None"
) )
full = chunk if full is None else cast(AIMessageChunk, full + chunk) full = chunk if full is None else cast("AIMessageChunk", full + chunk)
assert isinstance(full, AIMessageChunk) assert isinstance(full, AIMessageChunk)
assert full.usage_metadata is not None assert full.usage_metadata is not None
@ -1261,7 +1259,7 @@ class ChatModelIntegrationTests(ChatModelTests):
run_manager: Optional[CallbackManagerForLLMRun] = None, run_manager: Optional[CallbackManagerForLLMRun] = None,
**kwargs: Any, **kwargs: Any,
) -> ChatResult: ) -> ChatResult:
""" # noqa: E501 """
result = model.invoke("hi", stop=["you"]) result = model.invoke("hi", stop=["you"])
assert isinstance(result, AIMessage) assert isinstance(result, AIMessage)
@ -1315,10 +1313,7 @@ class ChatModelIntegrationTests(ChatModelTests):
""" """
if not self.has_tool_calling: if not self.has_tool_calling:
pytest.skip("Test requires tool calling.") pytest.skip("Test requires tool calling.")
if not self.has_tool_choice: tool_choice_value = None if not self.has_tool_choice else "any"
tool_choice_value = None
else:
tool_choice_value = "any"
# Emit warning if tool_choice_value property is overridden # Emit warning if tool_choice_value property is overridden
if inspect.getattr_static( if inspect.getattr_static(
self, "tool_choice_value" self, "tool_choice_value"
@ -1391,10 +1386,7 @@ class ChatModelIntegrationTests(ChatModelTests):
""" """
if not self.has_tool_calling: if not self.has_tool_calling:
pytest.skip("Test requires tool calling.") pytest.skip("Test requires tool calling.")
if not self.has_tool_choice: tool_choice_value = None if not self.has_tool_choice else "any"
tool_choice_value = None
else:
tool_choice_value = "any"
model_with_tools = model.bind_tools( model_with_tools = model.bind_tools(
[magic_function], tool_choice=tool_choice_value [magic_function], tool_choice=tool_choice_value
) )
@ -1730,10 +1722,7 @@ class ChatModelIntegrationTests(ChatModelTests):
""" # noqa: E501 """ # noqa: E501
if not self.has_tool_calling: if not self.has_tool_calling:
pytest.skip("Test requires tool calling.") pytest.skip("Test requires tool calling.")
if not self.has_tool_choice: tool_choice_value = None if not self.has_tool_choice else "any"
tool_choice_value = None
else:
tool_choice_value = "any"
model_with_tools = model.bind_tools( model_with_tools = model.bind_tools(
[magic_function_no_args], tool_choice=tool_choice_value [magic_function_no_args], tool_choice=tool_choice_value
) )
@ -1856,14 +1845,15 @@ class ChatModelIntegrationTests(ChatModelTests):
@pytest.mark.xfail(reason=("Not implemented.")) @pytest.mark.xfail(reason=("Not implemented."))
def test_structured_few_shot_examples(self, *args: Any) -> None: def test_structured_few_shot_examples(self, *args: Any) -> None:
super().test_structured_few_shot_examples(*args) super().test_structured_few_shot_examples(*args)
""" # noqa: E501 """
if not self.has_tool_calling: if not self.has_tool_calling:
pytest.skip("Test requires tool calling.") pytest.skip("Test requires tool calling.")
model_with_tools = model.bind_tools([my_adder_tool], tool_choice="any") model_with_tools = model.bind_tools([my_adder_tool], tool_choice="any")
function_result = json.dumps({"result": 3}) function_result = json.dumps({"result": 3})
tool_schema = my_adder_tool.args_schema tool_schema = my_adder_tool.args_schema
assert isinstance(tool_schema, type) and issubclass(tool_schema, BaseModel) assert isinstance(tool_schema, type)
assert issubclass(tool_schema, BaseModel)
few_shot_messages = tool_example_to_messages( few_shot_messages = tool_example_to_messages(
"What is 1 + 2", "What is 1 + 2",
[tool_schema(a=1, b=2)], [tool_schema(a=1, b=2)],
@ -1871,7 +1861,7 @@ class ChatModelIntegrationTests(ChatModelTests):
ai_response=function_result, ai_response=function_result,
) )
messages = few_shot_messages + [HumanMessage("What is 3 + 4")] messages = [*few_shot_messages, HumanMessage("What is 3 + 4")]
result = model_with_tools.invoke(messages) result = model_with_tools.invoke(messages)
assert isinstance(result, AIMessage) assert isinstance(result, AIMessage)
@ -1905,7 +1895,7 @@ class ChatModelIntegrationTests(ChatModelTests):
most formats: https://python.langchain.com/api_reference/core/utils/langchain_core.utils.function_calling.convert_to_openai_tool.html most formats: https://python.langchain.com/api_reference/core/utils/langchain_core.utils.function_calling.convert_to_openai_tool.html
See example implementation of ``with_structured_output`` here: https://python.langchain.com/api_reference/_modules/langchain_openai/chat_models/base.html#BaseChatOpenAI.with_structured_output See example implementation of ``with_structured_output`` here: https://python.langchain.com/api_reference/_modules/langchain_openai/chat_models/base.html#BaseChatOpenAI.with_structured_output
""" # noqa: E501 """
if not self.has_structured_output: if not self.has_structured_output:
pytest.skip("Test requires structured output.") pytest.skip("Test requires structured output.")
@ -1983,7 +1973,7 @@ class ChatModelIntegrationTests(ChatModelTests):
most formats: https://python.langchain.com/api_reference/core/utils/langchain_core.utils.function_calling.convert_to_openai_tool.html most formats: https://python.langchain.com/api_reference/core/utils/langchain_core.utils.function_calling.convert_to_openai_tool.html
See example implementation of ``with_structured_output`` here: https://python.langchain.com/api_reference/_modules/langchain_openai/chat_models/base.html#BaseChatOpenAI.with_structured_output See example implementation of ``with_structured_output`` here: https://python.langchain.com/api_reference/_modules/langchain_openai/chat_models/base.html#BaseChatOpenAI.with_structured_output
""" # noqa: E501 """
if not self.has_structured_output: if not self.has_structured_output:
pytest.skip("Test requires structured output.") pytest.skip("Test requires structured output.")
@ -2163,7 +2153,7 @@ class ChatModelIntegrationTests(ChatModelTests):
assert isinstance(result, dict) assert isinstance(result, dict)
def test_json_mode(self, model: BaseChatModel) -> None: def test_json_mode(self, model: BaseChatModel) -> None:
"""Test structured output via `JSON mode. <https://python.langchain.com/docs/concepts/structured_outputs/#json-mode>`_ """Test structured output via `JSON mode. <https://python.langchain.com/docs/concepts/structured_outputs/#json-mode>`_.
This test is optional and should be skipped if the model does not support This test is optional and should be skipped if the model does not support
the JSON mode feature (see Configuration below). the JSON mode feature (see Configuration below).
@ -2183,7 +2173,7 @@ class ChatModelIntegrationTests(ChatModelTests):
.. dropdown:: Troubleshooting .. dropdown:: Troubleshooting
See example implementation of ``with_structured_output`` here: https://python.langchain.com/api_reference/_modules/langchain_openai/chat_models/base.html#BaseChatOpenAI.with_structured_output See example implementation of ``with_structured_output`` here: https://python.langchain.com/api_reference/_modules/langchain_openai/chat_models/base.html#BaseChatOpenAI.with_structured_output
""" # noqa: E501 """
if not self.supports_json_mode: if not self.supports_json_mode:
pytest.skip("Test requires json mode support.") pytest.skip("Test requires json mode support.")
@ -2893,20 +2883,20 @@ class ChatModelIntegrationTests(ChatModelTests):
def invoke_with_audio_input(self, *, stream: bool = False) -> AIMessage: def invoke_with_audio_input(self, *, stream: bool = False) -> AIMessage:
""":private:""" """:private:"""
raise NotImplementedError() raise NotImplementedError
def invoke_with_audio_output(self, *, stream: bool = False) -> AIMessage: def invoke_with_audio_output(self, *, stream: bool = False) -> AIMessage:
""":private:""" """:private:"""
raise NotImplementedError() raise NotImplementedError
def invoke_with_reasoning_output(self, *, stream: bool = False) -> AIMessage: def invoke_with_reasoning_output(self, *, stream: bool = False) -> AIMessage:
""":private:""" """:private:"""
raise NotImplementedError() raise NotImplementedError
def invoke_with_cache_read_input(self, *, stream: bool = False) -> AIMessage: def invoke_with_cache_read_input(self, *, stream: bool = False) -> AIMessage:
""":private:""" """:private:"""
raise NotImplementedError() raise NotImplementedError
def invoke_with_cache_creation_input(self, *, stream: bool = False) -> AIMessage: def invoke_with_cache_creation_input(self, *, stream: bool = False) -> AIMessage:
""":private:""" """:private:"""
raise NotImplementedError() raise NotImplementedError

View File

@ -31,7 +31,7 @@ class DocumentIndexerTestSuite(ABC):
"""Get the index.""" """Get the index."""
def test_upsert_documents_has_no_ids(self, index: DocumentIndex) -> None: def test_upsert_documents_has_no_ids(self, index: DocumentIndex) -> None:
"""Verify that there is not parameter called ids in upsert""" """Verify that there is not parameter called ids in upsert."""
signature = inspect.signature(index.upsert) signature = inspect.signature(index.upsert)
assert "ids" not in signature.parameters assert "ids" not in signature.parameters
@ -75,7 +75,7 @@ class DocumentIndexerTestSuite(ABC):
] ]
response = index.upsert(documents) response = index.upsert(documents)
ids = response["succeeded"] ids = response["succeeded"]
other_id = list(set(ids) - {foo_uuid})[0] other_id = next(iter(set(ids) - {foo_uuid}))
assert response["failed"] == [] assert response["failed"] == []
assert foo_uuid in ids assert foo_uuid in ids
# Ordering is not guaranteed, so we use a set. # Ordering is not guaranteed, so we use a set.
@ -221,7 +221,7 @@ class AsyncDocumentIndexTestSuite(ABC):
"""Get the index.""" """Get the index."""
async def test_upsert_documents_has_no_ids(self, index: DocumentIndex) -> None: async def test_upsert_documents_has_no_ids(self, index: DocumentIndex) -> None:
"""Verify that there is not parameter called ids in upsert""" """Verify that there is not parameter called ids in upsert."""
signature = inspect.signature(index.upsert) signature = inspect.signature(index.upsert)
assert "ids" not in signature.parameters assert "ids" not in signature.parameters
@ -265,7 +265,7 @@ class AsyncDocumentIndexTestSuite(ABC):
] ]
response = await index.aupsert(documents) response = await index.aupsert(documents)
ids = response["succeeded"] ids = response["succeeded"]
other_id = list(set(ids) - {foo_uuid})[0] other_id = next(iter(set(ids) - {foo_uuid}))
assert response["failed"] == [] assert response["failed"] == []
assert foo_uuid in ids assert foo_uuid in ids
# Ordering is not guaranteed, so we use a set. # Ordering is not guaranteed, so we use a set.

View File

@ -8,43 +8,32 @@ from langchain_tests.base import BaseStandardTests
class RetrieversIntegrationTests(BaseStandardTests): class RetrieversIntegrationTests(BaseStandardTests):
""" """Base class for retrievers integration tests."""
Base class for retrievers integration tests.
"""
@property @property
@abstractmethod @abstractmethod
def retriever_constructor(self) -> type[BaseRetriever]: def retriever_constructor(self) -> type[BaseRetriever]:
""" """A BaseRetriever subclass to be tested."""
A BaseRetriever subclass to be tested.
"""
... ...
@property @property
def retriever_constructor_params(self) -> dict: def retriever_constructor_params(self) -> dict:
""" """Returns a dictionary of parameters to pass to the retriever constructor."""
Returns a dictionary of parameters to pass to the retriever constructor.
"""
return {} return {}
@property @property
@abstractmethod @abstractmethod
def retriever_query_example(self) -> str: def retriever_query_example(self) -> str:
""" """Returns a str representing the "query" of an example retriever call."""
Returns a str representing the "query" of an example retriever call.
"""
... ...
@pytest.fixture @pytest.fixture
def retriever(self) -> BaseRetriever: def retriever(self) -> BaseRetriever:
""" """:private:"""
:private:
"""
return self.retriever_constructor(**self.retriever_constructor_params) return self.retriever_constructor(**self.retriever_constructor_params)
def test_k_constructor_param(self) -> None: def test_k_constructor_param(self) -> None:
""" """Test that the retriever constructor accepts a k parameter, representing
Test that the retriever constructor accepts a k parameter, representing
the number of documents to return. the number of documents to return.
.. dropdown:: Troubleshooting .. dropdown:: Troubleshooting
@ -77,8 +66,7 @@ class RetrieversIntegrationTests(BaseStandardTests):
assert all(isinstance(doc, Document) for doc in result_1) assert all(isinstance(doc, Document) for doc in result_1)
def test_invoke_with_k_kwarg(self, retriever: BaseRetriever) -> None: def test_invoke_with_k_kwarg(self, retriever: BaseRetriever) -> None:
""" """Test that the invoke method accepts a k parameter, representing the number of
Test that the invoke method accepts a k parameter, representing the number of
documents to return. documents to return.
.. dropdown:: Troubleshooting .. dropdown:: Troubleshooting
@ -104,8 +92,7 @@ class RetrieversIntegrationTests(BaseStandardTests):
assert all(isinstance(doc, Document) for doc in result_3) assert all(isinstance(doc, Document) for doc in result_3)
def test_invoke_returns_documents(self, retriever: BaseRetriever) -> None: def test_invoke_returns_documents(self, retriever: BaseRetriever) -> None:
""" """If invoked with the example params, the retriever should return a list of
If invoked with the example params, the retriever should return a list of
Documents. Documents.
.. dropdown:: Troubleshooting .. dropdown:: Troubleshooting
@ -120,8 +107,7 @@ class RetrieversIntegrationTests(BaseStandardTests):
assert all(isinstance(doc, Document) for doc in result) assert all(isinstance(doc, Document) for doc in result)
async def test_ainvoke_returns_documents(self, retriever: BaseRetriever) -> None: async def test_ainvoke_returns_documents(self, retriever: BaseRetriever) -> None:
""" """If ainvoked with the example params, the retriever should return a list of
If ainvoked with the example params, the retriever should return a list of
Documents. Documents.
See :meth:`test_invoke_returns_documents` for more information on See :meth:`test_invoke_returns_documents` for more information on

View File

@ -5,12 +5,11 @@ from langchain_tests.unit_tests.tools import ToolsTests
class ToolsIntegrationTests(ToolsTests): class ToolsIntegrationTests(ToolsTests):
""" """Base class for tools integration tests."""
Base class for tools integration tests.
"""
def test_invoke_matches_output_schema(self, tool: BaseTool) -> None: def test_invoke_matches_output_schema(self, tool: BaseTool) -> None:
""" """Test invoke matches output schema.
If invoked with a ToolCall, the tool should return a valid ToolMessage content. If invoked with a ToolCall, the tool should return a valid ToolMessage content.
If you have followed the `custom tool guide <https://python.langchain.com/docs/how_to/custom_tools/>`_, If you have followed the `custom tool guide <https://python.langchain.com/docs/how_to/custom_tools/>`_,
@ -41,7 +40,8 @@ class ToolsIntegrationTests(ToolsTests):
assert all(isinstance(c, (str, dict)) for c in tool_message.content) assert all(isinstance(c, (str, dict)) for c in tool_message.content)
async def test_async_invoke_matches_output_schema(self, tool: BaseTool) -> None: async def test_async_invoke_matches_output_schema(self, tool: BaseTool) -> None:
""" """Test async invoke matches output schema.
If ainvoked with a ToolCall, the tool should return a valid ToolMessage content. If ainvoked with a ToolCall, the tool should return a valid ToolMessage content.
For debugging tips, see :meth:`test_invoke_matches_output_schema`. For debugging tips, see :meth:`test_invoke_matches_output_schema`.
@ -66,9 +66,8 @@ class ToolsIntegrationTests(ToolsTests):
assert all(isinstance(c, (str, dict)) for c in tool_message.content) assert all(isinstance(c, (str, dict)) for c in tool_message.content)
def test_invoke_no_tool_call(self, tool: BaseTool) -> None: def test_invoke_no_tool_call(self, tool: BaseTool) -> None:
""" """If invoked without a ToolCall, the tool can return anything
If invoked without a ToolCall, the tool can return anything but it shouldn't throw an error.
but it shouldn't throw an error
If this test fails, your tool may not be handling the input you defined If this test fails, your tool may not be handling the input you defined
in `tool_invoke_params_example` correctly, and it's throwing an error. in `tool_invoke_params_example` correctly, and it's throwing an error.
@ -79,9 +78,8 @@ class ToolsIntegrationTests(ToolsTests):
tool.invoke(self.tool_invoke_params_example) tool.invoke(self.tool_invoke_params_example)
async def test_async_invoke_no_tool_call(self, tool: BaseTool) -> None: async def test_async_invoke_no_tool_call(self, tool: BaseTool) -> None:
""" """If ainvoked without a ToolCall, the tool can return anything
If ainvoked without a ToolCall, the tool can return anything but it shouldn't throw an error.
but it shouldn't throw an error
For debugging tips, see :meth:`test_invoke_no_tool_call`. For debugging tips, see :meth:`test_invoke_no_tool_call`.
""" """

View File

@ -105,16 +105,12 @@ class VectorStoreIntegrationTests(BaseStandardTests):
@property @property
def has_sync(self) -> bool: def has_sync(self) -> bool:
""" """Configurable property to enable or disable sync tests."""
Configurable property to enable or disable sync tests.
"""
return True return True
@property @property
def has_async(self) -> bool: def has_async(self) -> bool:
""" """Configurable property to enable or disable async tests."""
Configurable property to enable or disable async tests.
"""
return True return True
@staticmethod @staticmethod
@ -368,7 +364,7 @@ class VectorStoreIntegrationTests(BaseStandardTests):
@pytest.mark.xfail(reason=("get_by_ids not implemented.")) @pytest.mark.xfail(reason=("get_by_ids not implemented."))
def test_get_by_ids_missing(self, vectorstore: VectorStore) -> None: def test_get_by_ids_missing(self, vectorstore: VectorStore) -> None:
super().test_get_by_ids_missing(vectorstore) super().test_get_by_ids_missing(vectorstore)
""" # noqa: E501 """
if not self.has_sync: if not self.has_sync:
pytest.skip("Sync tests not supported.") pytest.skip("Sync tests not supported.")

View File

@ -1,6 +1,4 @@
""" """:autodoc-options: autoproperty."""
:autodoc-options: autoproperty
"""
import inspect import inspect
import os import os
@ -31,13 +29,13 @@ from langchain_tests.utils.pydantic import PYDANTIC_MAJOR_VERSION
def generate_schema_pydantic_v1_from_2() -> Any: def generate_schema_pydantic_v1_from_2() -> Any:
""" """Use to generate a schema from v1 namespace in pydantic 2.
Use to generate a schema from v1 namespace in pydantic 2.
:private: :private:
""" """
if PYDANTIC_MAJOR_VERSION != 2: if PYDANTIC_MAJOR_VERSION != 2:
raise AssertionError("This function is only compatible with Pydantic v2.") msg = "This function is only compatible with Pydantic v2."
raise AssertionError(msg)
class PersonB(BaseModelV1): class PersonB(BaseModelV1):
"""Record attributes of a person.""" """Record attributes of a person."""
@ -49,8 +47,7 @@ def generate_schema_pydantic_v1_from_2() -> Any:
def generate_schema_pydantic() -> Any: def generate_schema_pydantic() -> Any:
""" """Works with either pydantic 1 or 2.
Works with either pydantic 1 or 2
:private: :private:
""" """
@ -74,7 +71,7 @@ class ChatModelTests(BaseStandardTests):
"""Base class for chat model tests. """Base class for chat model tests.
:private: :private:
""" # noqa: E501 """
@property @property
@abstractmethod @abstractmethod
@ -158,13 +155,15 @@ class ChatModelTests(BaseStandardTests):
@property @property
def supports_image_inputs(self) -> bool: def supports_image_inputs(self) -> bool:
"""(bool) whether the chat model supports image inputs, defaults to """(bool) whether the chat model supports image inputs, defaults to
``False``.""" ``False``.
"""
return False return False
@property @property
def supports_image_urls(self) -> bool: def supports_image_urls(self) -> bool:
"""(bool) whether the chat model supports image inputs from URLs, defaults to """(bool) whether the chat model supports image inputs from URLs, defaults to
``False``.""" ``False``.
"""
return False return False
@property @property
@ -175,19 +174,22 @@ class ChatModelTests(BaseStandardTests):
@property @property
def supports_audio_inputs(self) -> bool: def supports_audio_inputs(self) -> bool:
"""(bool) whether the chat model supports audio inputs, defaults to """(bool) whether the chat model supports audio inputs, defaults to
``False``.""" ``False``.
"""
return False return False
@property @property
def supports_video_inputs(self) -> bool: def supports_video_inputs(self) -> bool:
"""(bool) whether the chat model supports video inputs, defaults to ``False``. """(bool) whether the chat model supports video inputs, defaults to ``False``.
No current tests are written for this feature.""" No current tests are written for this feature.
"""
return False return False
@property @property
def returns_usage_metadata(self) -> bool: def returns_usage_metadata(self) -> bool:
"""(bool) whether the chat model returns usage metadata on invoke and streaming """(bool) whether the chat model returns usage metadata on invoke and streaming
responses.""" responses.
"""
return True return True
@property @property
@ -198,7 +200,8 @@ class ChatModelTests(BaseStandardTests):
@property @property
def supports_image_tool_message(self) -> bool: def supports_image_tool_message(self) -> bool:
"""(bool) whether the chat model supports ToolMessages that include image """(bool) whether the chat model supports ToolMessages that include image
content.""" content.
"""
return False return False
@property @property
@ -227,7 +230,8 @@ class ChatModelTests(BaseStandardTests):
], ],
]: ]:
"""(dict) what usage metadata details are emitted in invoke and stream. Only """(dict) what usage metadata details are emitted in invoke and stream. Only
needs to be overridden if these details are returned by the model.""" needs to be overridden if these details are returned by the model.
"""
return {"invoke": [], "stream": []} return {"invoke": [], "stream": []}
@ -806,7 +810,8 @@ class ChatModelUnitTests(ChatModelTests):
@property @property
def init_from_env_params(self) -> tuple[dict, dict, dict]: def init_from_env_params(self) -> tuple[dict, dict, dict]:
"""(tuple) environment variables, additional initialization args, and expected """(tuple) environment variables, additional initialization args, and expected
instance attributes for testing initialization from environment variables.""" instance attributes for testing initialization from environment variables.
"""
return {}, {}, {} return {}, {}, {}
def test_init(self) -> None: def test_init(self) -> None:
@ -887,7 +892,7 @@ class ChatModelUnitTests(ChatModelTests):
a utility function that will accommodate most formats: https://python.langchain.com/api_reference/core/utils/langchain_core.utils.function_calling.convert_to_openai_tool.html a utility function that will accommodate most formats: https://python.langchain.com/api_reference/core/utils/langchain_core.utils.function_calling.convert_to_openai_tool.html
See example implementation of ``bind_tools`` here: https://python.langchain.com/api_reference/_modules/langchain_openai/chat_models/base.html#BaseChatOpenAI.bind_tools See example implementation of ``bind_tools`` here: https://python.langchain.com/api_reference/_modules/langchain_openai/chat_models/base.html#BaseChatOpenAI.bind_tools
""" # noqa: E501 """
if not self.has_tool_calling: if not self.has_tool_calling:
return return
@ -927,7 +932,7 @@ class ChatModelUnitTests(ChatModelTests):
a utility function that will accommodate most formats: https://python.langchain.com/api_reference/core/utils/langchain_core.utils.function_calling.convert_to_openai_tool.html a utility function that will accommodate most formats: https://python.langchain.com/api_reference/core/utils/langchain_core.utils.function_calling.convert_to_openai_tool.html
See example implementation of ``with_structured_output`` here: https://python.langchain.com/api_reference/_modules/langchain_openai/chat_models/base.html#BaseChatOpenAI.with_structured_output See example implementation of ``with_structured_output`` here: https://python.langchain.com/api_reference/_modules/langchain_openai/chat_models/base.html#BaseChatOpenAI.with_structured_output
""" # noqa: E501 """
if not self.has_structured_output: if not self.has_structured_output:
return return

View File

@ -10,9 +10,7 @@ from langchain_tests.base import BaseStandardTests
class EmbeddingsTests(BaseStandardTests): class EmbeddingsTests(BaseStandardTests):
""" """:private:"""
:private:
"""
@property @property
@abstractmethod @abstractmethod
@ -88,7 +86,7 @@ class EmbeddingsUnitTests(EmbeddingsTests):
"my_api_key": "api_key", "my_api_key": "api_key",
}, },
) )
""" # noqa: E501 """
def test_init(self) -> None: def test_init(self) -> None:
"""Test model initialization. """Test model initialization.
@ -106,7 +104,8 @@ class EmbeddingsUnitTests(EmbeddingsTests):
"""This property is used in unit tests to test initialization from environment """This property is used in unit tests to test initialization from environment
variables. It should return a tuple of three dictionaries that specify the variables. It should return a tuple of three dictionaries that specify the
environment variables, additional initialization args, and expected instance environment variables, additional initialization args, and expected instance
attributes to check.""" attributes to check.
"""
return {}, {}, {} return {}, {}, {}
def test_init_from_env(self) -> None: def test_init_from_env(self) -> None:

View File

@ -11,8 +11,7 @@ from langchain_tests.base import BaseStandardTests
class ToolsTests(BaseStandardTests): class ToolsTests(BaseStandardTests):
""" """:private:
:private:
Base class for testing tools. This won't show in the documentation, but Base class for testing tools. This won't show in the documentation, but
the docstrings will be inherited by subclasses. the docstrings will be inherited by subclasses.
""" """
@ -20,22 +19,17 @@ class ToolsTests(BaseStandardTests):
@property @property
@abstractmethod @abstractmethod
def tool_constructor(self) -> Union[type[BaseTool], BaseTool]: def tool_constructor(self) -> Union[type[BaseTool], BaseTool]:
""" """Returns a class or instance of a tool to be tested."""
Returns a class or instance of a tool to be tested.
"""
... ...
@property @property
def tool_constructor_params(self) -> dict: def tool_constructor_params(self) -> dict:
""" """Returns a dictionary of parameters to pass to the tool constructor."""
Returns a dictionary of parameters to pass to the tool constructor.
"""
return {} return {}
@property @property
def tool_invoke_params_example(self) -> dict: def tool_invoke_params_example(self) -> dict:
""" """Returns a dictionary representing the "args" of an example tool call.
Returns a dictionary representing the "args" of an example tool call.
This should NOT be a ToolCall dict - it should not This should NOT be a ToolCall dict - it should not
have {"name", "id", "args"} keys. have {"name", "id", "args"} keys.
@ -44,9 +38,7 @@ class ToolsTests(BaseStandardTests):
@pytest.fixture @pytest.fixture
def tool(self) -> BaseTool: def tool(self) -> BaseTool:
""" """:private:"""
:private:
"""
if isinstance(self.tool_constructor, BaseTool): if isinstance(self.tool_constructor, BaseTool):
if self.tool_constructor_params != {}: if self.tool_constructor_params != {}:
msg = ( msg = (
@ -59,19 +51,17 @@ class ToolsTests(BaseStandardTests):
class ToolsUnitTests(ToolsTests): class ToolsUnitTests(ToolsTests):
""" """Base class for tools unit tests."""
Base class for tools unit tests.
"""
@property @property
def init_from_env_params(self) -> tuple[dict, dict, dict]: def init_from_env_params(self) -> tuple[dict, dict, dict]:
"""Return env vars, init args, and expected instance attrs for initializing """Return env vars, init args, and expected instance attrs for initializing
from env vars.""" from env vars.
"""
return {}, {}, {} return {}, {}, {}
def test_init(self) -> None: def test_init(self) -> None:
""" """Test that the tool can be initialized with :attr:`tool_constructor` and
Test that the tool can be initialized with :attr:`tool_constructor` and
:attr:`tool_constructor_params`. If this fails, check that the :attr:`tool_constructor_params`. If this fails, check that the
keyword args defined in :attr:`tool_constructor_params` are valid. keyword args defined in :attr:`tool_constructor_params` are valid.
""" """
@ -94,16 +84,14 @@ class ToolsUnitTests(ToolsTests):
assert actual == expected assert actual == expected
def test_has_name(self, tool: BaseTool) -> None: def test_has_name(self, tool: BaseTool) -> None:
""" """Tests that the tool has a name attribute to pass to chat models.
Tests that the tool has a name attribute to pass to chat models.
If this fails, add a `name` parameter to your tool. If this fails, add a `name` parameter to your tool.
""" """
assert tool.name assert tool.name
def test_has_input_schema(self, tool: BaseTool) -> None: def test_has_input_schema(self, tool: BaseTool) -> None:
""" """Tests that the tool has an input schema.
Tests that the tool has an input schema.
If this fails, add an `args_schema` to your tool. If this fails, add an `args_schema` to your tool.
@ -115,8 +103,7 @@ class ToolsUnitTests(ToolsTests):
assert tool.get_input_schema() assert tool.get_input_schema()
def test_input_schema_matches_invoke_params(self, tool: BaseTool) -> None: def test_input_schema_matches_invoke_params(self, tool: BaseTool) -> None:
""" """Tests that the provided example params match the declared input schema.
Tests that the provided example params match the declared input schema.
If this fails, update the `tool_invoke_params_example` attribute to match If this fails, update the `tool_invoke_params_example` attribute to match
the input schema (`args_schema`) of the tool. the input schema (`args_schema`) of the tool.

View File

@ -1,5 +1,4 @@
""" """Utilities for working with pydantic models.
Utilities for working with pydantic models.
:private: :private:
""" """

View File

@ -4,4 +4,3 @@ import pytest
@pytest.mark.compile @pytest.mark.compile
def test_placeholder() -> None: def test_placeholder() -> None:
"""Used for compiling integration tests without running any real tests.""" """Used for compiling integration tests without running any real tests."""
pass

View File

@ -41,8 +41,7 @@ class TestParrotMultiplyToolUnit(ToolsUnitTests):
@property @property
def tool_invoke_params_example(self) -> dict: def tool_invoke_params_example(self) -> dict:
""" """Returns a dictionary representing the "args" of an example tool call.
Returns a dictionary representing the "args" of an example tool call.
This should NOT be a ToolCall dict - i.e. it should not This should NOT be a ToolCall dict - i.e. it should not
have {"name", "id", "args"} keys. have {"name", "id", "args"} keys.
@ -64,8 +63,7 @@ class TestParrotMultiplyToolIntegration(ToolsIntegrationTests):
@property @property
def tool_invoke_params_example(self) -> dict: def tool_invoke_params_example(self) -> dict:
""" """Returns a dictionary representing the "args" of an example tool call.
Returns a dictionary representing the "args" of an example tool call.
This should NOT be a ToolCall dict - i.e. it should not This should NOT be a ToolCall dict - i.e. it should not
have {"name", "id", "args"} keys. have {"name", "id", "args"} keys.
@ -87,8 +85,7 @@ class TestParrotMultiplyArtifactToolIntegration(ToolsIntegrationTests):
@property @property
def tool_invoke_params_example(self) -> dict: def tool_invoke_params_example(self) -> dict:
""" """Returns a dictionary representing the "args" of an example tool call.
Returns a dictionary representing the "args" of an example tool call.
This should NOT be a ToolCall dict - i.e. it should not This should NOT be a ToolCall dict - i.e. it should not
have {"name", "id", "args"} keys. have {"name", "id", "args"} keys.

View File

@ -1,6 +1,4 @@
""" """Test the standard tests on the custom chat model in the docs."""
Test the standard tests on the custom chat model in the docs
"""
from langchain_tests.integration_tests import ChatModelIntegrationTests from langchain_tests.integration_tests import ChatModelIntegrationTests
from langchain_tests.unit_tests import ChatModelUnitTests from langchain_tests.unit_tests import ChatModelUnitTests

View File

@ -17,8 +17,7 @@ class TestParrotMultiplyToolUnit(ToolsUnitTests):
@property @property
def tool_invoke_params_example(self) -> dict: def tool_invoke_params_example(self) -> dict:
""" """Returns a dictionary representing the "args" of an example tool call.
Returns a dictionary representing the "args" of an example tool call.
This should NOT be a ToolCall dict - i.e. it should not This should NOT be a ToolCall dict - i.e. it should not
have {"name", "id", "args"} keys. have {"name", "id", "args"} keys.
@ -33,8 +32,7 @@ class TestParrotMultiplyToolIntegration(ToolsIntegrationTests):
@property @property
def tool_invoke_params_example(self) -> dict: def tool_invoke_params_example(self) -> dict:
""" """Returns a dictionary representing the "args" of an example tool call.
Returns a dictionary representing the "args" of an example tool call.
This should NOT be a ToolCall dict - i.e. it should not This should NOT be a ToolCall dict - i.e. it should not
have {"name", "id", "args"} keys. have {"name", "id", "args"} keys.