mirror of
https://github.com/hwchase17/langchain.git
synced 2025-08-14 07:07:34 +00:00
chore(standard-tests): add ruff rules D (#32347)
See https://docs.astral.sh/ruff/rules/#pydocstyle-d Co-authored-by: Mason Daugherty <mason@langchain.dev>
This commit is contained in:
parent
46bbd52e81
commit
09a616fe85
@ -1,8 +1,13 @@
|
||||
"""Standard tests."""
|
||||
|
||||
from abc import ABC
|
||||
|
||||
|
||||
class BaseStandardTests(ABC):
|
||||
""":private:"""
|
||||
"""Base class for standard tests.
|
||||
|
||||
:private:
|
||||
"""
|
||||
|
||||
def test_no_overrides_DO_NOT_OVERRIDE(self) -> None:
|
||||
"""Test that no standard tests are overridden.
|
||||
|
@ -1,3 +1,5 @@
|
||||
"""Pytest conftest."""
|
||||
|
||||
import gzip
|
||||
from os import PathLike
|
||||
from pathlib import Path
|
||||
@ -88,7 +90,7 @@ _BASE_FILTER_HEADERS = [
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
def _base_vcr_config() -> dict:
|
||||
"""Get configuration that every cassette will receive.
|
||||
"""Return VCR configuration that every cassette will receive.
|
||||
|
||||
(Anything permitted by ``vcr.VCR(**kwargs)`` can be put here.)
|
||||
"""
|
||||
@ -105,4 +107,5 @@ def _base_vcr_config() -> dict:
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
def vcr_config(_base_vcr_config: dict) -> dict:
|
||||
"""VCR config fixture."""
|
||||
return _base_vcr_config
|
||||
|
@ -1,3 +1,5 @@
|
||||
"""Integration tests for LangChain components."""
|
||||
|
||||
# ruff: noqa: E402
|
||||
import pytest
|
||||
|
||||
|
@ -62,7 +62,9 @@ class BaseStoreSyncTests(BaseStandardTests, Generic[V]):
|
||||
assert kv_store.mget(["foo", "bar"]) == [foo, bar]
|
||||
|
||||
def test_store_still_empty(self, kv_store: BaseStore[str, V]) -> None:
|
||||
"""This test should follow a test that sets values.
|
||||
"""Test that the store is still empty.
|
||||
|
||||
This test should follow a test that sets values.
|
||||
|
||||
This just verifies that the fixture is set up properly to be empty
|
||||
after each test.
|
||||
@ -192,7 +194,9 @@ class BaseStoreAsyncTests(BaseStandardTests, Generic[V]):
|
||||
assert await kv_store.amget(["foo", "bar"]) == [foo, bar]
|
||||
|
||||
async def test_store_still_empty(self, kv_store: BaseStore[str, V]) -> None:
|
||||
"""This test should follow a test that sets values.
|
||||
"""Test that the store is still empty.
|
||||
|
||||
This test should follow a test that sets values.
|
||||
|
||||
This just verifies that the fixture is set up properly to be empty
|
||||
after each test.
|
||||
|
@ -62,7 +62,9 @@ class SyncCacheTestSuite(BaseStandardTests):
|
||||
assert cache.lookup(prompt, llm_string) == [generation]
|
||||
|
||||
def test_cache_still_empty(self, cache: BaseCache) -> None:
|
||||
"""This test should follow a test that updates the cache.
|
||||
"""Test that the cache is still empty.
|
||||
|
||||
This test should follow a test that updates the cache.
|
||||
|
||||
This just verifies that the fixture is set up properly to be empty
|
||||
after each test.
|
||||
@ -153,7 +155,9 @@ class AsyncCacheTestSuite(BaseStandardTests):
|
||||
assert await cache.alookup(prompt, llm_string) == [generation]
|
||||
|
||||
async def test_cache_still_empty(self, cache: BaseCache) -> None:
|
||||
"""This test should follow a test that updates the cache.
|
||||
"""Test that the cache is still empty.
|
||||
|
||||
This test should follow a test that updates the cache.
|
||||
|
||||
This just verifies that the fixture is set up properly to be empty
|
||||
after each test.
|
||||
|
@ -1,3 +1,5 @@
|
||||
"""Integration tests for chat models."""
|
||||
|
||||
import base64
|
||||
import inspect
|
||||
import json
|
||||
@ -39,8 +41,6 @@ from langchain_tests.utils.pydantic import PYDANTIC_MAJOR_VERSION
|
||||
def _get_joke_class(
|
||||
schema_type: Literal["pydantic", "typeddict", "json_schema"],
|
||||
) -> Any:
|
||||
""":private:"""
|
||||
|
||||
class Joke(BaseModel):
|
||||
"""Joke to tell user."""
|
||||
|
||||
@ -95,13 +95,13 @@ class _MagicFunctionSchema(BaseModel):
|
||||
|
||||
@tool(args_schema=_MagicFunctionSchema)
|
||||
def magic_function(_input: int) -> int:
|
||||
"""Applies a magic function to an input."""
|
||||
"""Apply a magic function to an input."""
|
||||
return _input + 2
|
||||
|
||||
|
||||
@tool
|
||||
def magic_function_no_args() -> int:
|
||||
"""Calculates a magic function."""
|
||||
"""Calculate a magic function."""
|
||||
return 5
|
||||
|
||||
|
||||
@ -143,7 +143,7 @@ def unicode_customer(customer_name: str, description: str) -> str:
|
||||
|
||||
|
||||
class ChatModelIntegrationTests(ChatModelTests):
|
||||
"""Base class for chat model integration tests.
|
||||
'''Base class for chat model integration tests.
|
||||
|
||||
Test subclasses must implement the ``chat_model_class`` and
|
||||
``chat_model_params`` properties to specify what model to test and its
|
||||
@ -587,7 +587,7 @@ class ChatModelIntegrationTests(ChatModelTests):
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
def vcr_config(_base_vcr_config: dict) -> dict: # noqa: F811
|
||||
\"\"\"Extend the default configuration from langchain_tests.\"\"\"
|
||||
"""Extend the default configuration from langchain_tests."""
|
||||
config = _base_vcr_config.copy()
|
||||
config.setdefault("filter_headers", []).extend(_EXTRA_HEADERS)
|
||||
config["before_record_response"] = remove_response_headers
|
||||
@ -623,7 +623,7 @@ class ChatModelIntegrationTests(ChatModelTests):
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
def vcr_config(_base_vcr_config: dict) -> dict: # noqa: F811
|
||||
\"\"\"Extend the default configuration from langchain_tests.\"\"\"
|
||||
"""Extend the default configuration from langchain_tests."""
|
||||
config = _base_vcr_config.copy()
|
||||
config.setdefault("filter_headers", []).extend(_EXTRA_HEADERS)
|
||||
config["before_record_response"] = remove_response_headers
|
||||
@ -675,11 +675,14 @@ class ChatModelIntegrationTests(ChatModelTests):
|
||||
You can then commit the cassette to your repository. Subsequent test runs
|
||||
will use the cassette instead of making HTTP calls.
|
||||
|
||||
""" # noqa: E501
|
||||
''' # noqa: E501,D214
|
||||
|
||||
@property
|
||||
def standard_chat_model_params(self) -> dict:
|
||||
""":private:"""
|
||||
"""Standard parameters for chat model.
|
||||
|
||||
:private:
|
||||
"""
|
||||
return {}
|
||||
|
||||
def test_invoke(self, model: BaseChatModel) -> None:
|
||||
@ -1270,8 +1273,10 @@ class ChatModelIntegrationTests(ChatModelTests):
|
||||
)
|
||||
|
||||
def test_stop_sequence(self, model: BaseChatModel) -> None:
|
||||
"""Test that model does not fail when invoked with the ``stop`` parameter,
|
||||
which is a standard parameter for stopping generation at a certain token.
|
||||
"""Test that model does not fail when invoked with the ``stop`` parameter.
|
||||
|
||||
The ``stop`` parameter is a standard parameter for stopping generation at a
|
||||
certain token.
|
||||
|
||||
`More on standard parameters <https://python.langchain.com/docs/concepts/chat_models/#standard-parameters>`__
|
||||
|
||||
@ -1306,8 +1311,10 @@ class ChatModelIntegrationTests(ChatModelTests):
|
||||
assert isinstance(result, AIMessage)
|
||||
|
||||
def test_tool_calling(self, model: BaseChatModel) -> None:
|
||||
"""Test that the model generates tool calls. This test is skipped if the
|
||||
``has_tool_calling`` property on the test class is set to False.
|
||||
"""Test that the model generates tool calls.
|
||||
|
||||
This test is skipped if the ``has_tool_calling`` property on the test class is
|
||||
set to False.
|
||||
|
||||
This test is optional and should be skipped if the model does not support
|
||||
tool calling (see Configuration below).
|
||||
@ -1381,8 +1388,10 @@ class ChatModelIntegrationTests(ChatModelTests):
|
||||
_validate_tool_call_message(full)
|
||||
|
||||
async def test_tool_calling_async(self, model: BaseChatModel) -> None:
|
||||
"""Test that the model generates tool calls. This test is skipped if the
|
||||
``has_tool_calling`` property on the test class is set to False.
|
||||
"""Test that the model generates tool calls.
|
||||
|
||||
This test is skipped if the ``has_tool_calling`` property on the test class is
|
||||
set to False.
|
||||
|
||||
This test is optional and should be skipped if the model does not support
|
||||
tool calling (see Configuration below).
|
||||
@ -1441,7 +1450,9 @@ class ChatModelIntegrationTests(ChatModelTests):
|
||||
_validate_tool_call_message(full)
|
||||
|
||||
def test_bind_runnables_as_tools(self, model: BaseChatModel) -> None:
|
||||
"""Test that the model generates tool calls for tools that are derived from
|
||||
"""Test bind runnables as tools.
|
||||
|
||||
Test that the model generates tool calls for tools that are derived from
|
||||
LangChain runnables. This test is skipped if the ``has_tool_calling`` property
|
||||
on the test class is set to False.
|
||||
|
||||
@ -1509,8 +1520,10 @@ class ChatModelIntegrationTests(ChatModelTests):
|
||||
def test_tool_message_histories_string_content(
|
||||
self, model: BaseChatModel, my_adder_tool: BaseTool
|
||||
) -> None:
|
||||
"""Test that message histories are compatible with string tool contents
|
||||
(e.g. OpenAI format). If a model passes this test, it should be compatible
|
||||
"""Test that message histories are compatible with string tool contents.
|
||||
|
||||
For instance with OpenAI format contents.
|
||||
If a model passes this test, it should be compatible
|
||||
with messages generated from providers following OpenAI format.
|
||||
|
||||
This test should be skipped if the model does not support tool calling
|
||||
@ -1581,8 +1594,9 @@ class ChatModelIntegrationTests(ChatModelTests):
|
||||
model: BaseChatModel,
|
||||
my_adder_tool: BaseTool,
|
||||
) -> None:
|
||||
"""Test that message histories are compatible with list tool contents
|
||||
(e.g. Anthropic format).
|
||||
"""Test that message histories are compatible with list tool contents.
|
||||
|
||||
For instance with Anthropic format contents.
|
||||
|
||||
These message histories will include ``AIMessage`` objects with "tool use" and
|
||||
content blocks, e.g.,
|
||||
@ -1671,7 +1685,9 @@ class ChatModelIntegrationTests(ChatModelTests):
|
||||
assert isinstance(result_list_content, AIMessage)
|
||||
|
||||
def test_tool_choice(self, model: BaseChatModel) -> None:
|
||||
"""Test that the model can force tool calling via the ``tool_choice``
|
||||
"""Test ``tool_choice`` parameter.
|
||||
|
||||
Test that the model can force tool calling via the ``tool_choice``
|
||||
parameter. This test is skipped if the ``has_tool_choice`` property on the
|
||||
test class is set to False.
|
||||
|
||||
@ -1723,6 +1739,7 @@ class ChatModelIntegrationTests(ChatModelTests):
|
||||
|
||||
def test_tool_calling_with_no_arguments(self, model: BaseChatModel) -> None:
|
||||
"""Test that the model generates tool calls for tools with no arguments.
|
||||
|
||||
This test is skipped if the ``has_tool_calling`` property on the test class
|
||||
is set to False.
|
||||
|
||||
@ -2075,7 +2092,9 @@ class ChatModelIntegrationTests(ChatModelTests):
|
||||
|
||||
@pytest.mark.skipif(PYDANTIC_MAJOR_VERSION != 2, reason="Test requires pydantic 2.")
|
||||
def test_structured_output_pydantic_2_v1(self, model: BaseChatModel) -> None:
|
||||
"""Test to verify we can generate structured output using ``pydantic.v1.BaseModel``.
|
||||
"""Test structured output using pydantic.v1.BaseModel.
|
||||
|
||||
Verify we can generate structured output using ``pydantic.v1.BaseModel``.
|
||||
|
||||
``pydantic.v1.BaseModel`` is available in the Pydantic 2 package.
|
||||
|
||||
@ -2140,7 +2159,9 @@ class ChatModelIntegrationTests(ChatModelTests):
|
||||
assert set(chunk.keys()) == {"setup", "punchline"}
|
||||
|
||||
def test_structured_output_optional_param(self, model: BaseChatModel) -> None:
|
||||
"""Test to verify we can generate structured output that includes optional
|
||||
"""Test structured output with optional parameters.
|
||||
|
||||
Test to verify we can generate structured output that includes optional
|
||||
parameters.
|
||||
|
||||
This test is optional and should be skipped if the model does not support
|
||||
@ -2847,8 +2868,10 @@ class ChatModelIntegrationTests(ChatModelTests):
|
||||
assert len(result.content) > 0
|
||||
|
||||
def test_agent_loop(self, model: BaseChatModel) -> None:
|
||||
"""Test that the model supports a simple ReAct agent loop. This test is skipped
|
||||
if the ``has_tool_calling`` property on the test class is set to False.
|
||||
"""Test that the model supports a simple ReAct agent loop.
|
||||
|
||||
This test is skipped if the ``has_tool_calling`` property on the test class is
|
||||
set to False.
|
||||
|
||||
This test is optional and should be skipped if the model does not support
|
||||
tool calling (see Configuration below).
|
||||
@ -2953,23 +2976,38 @@ class ChatModelIntegrationTests(ChatModelTests):
|
||||
benchmark(_run)
|
||||
|
||||
def invoke_with_audio_input(self, *, stream: bool = False) -> AIMessage:
|
||||
""":private:"""
|
||||
"""Invoke with audio input.
|
||||
|
||||
:private:
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def invoke_with_audio_output(self, *, stream: bool = False) -> AIMessage:
|
||||
""":private:"""
|
||||
"""Invoke with audio output.
|
||||
|
||||
:private:
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def invoke_with_reasoning_output(self, *, stream: bool = False) -> AIMessage:
|
||||
""":private:"""
|
||||
"""Invoke with reasoning output.
|
||||
|
||||
:private:
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def invoke_with_cache_read_input(self, *, stream: bool = False) -> AIMessage:
|
||||
""":private:"""
|
||||
"""Invoke with cache read input.
|
||||
|
||||
:private:
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def invoke_with_cache_creation_input(self, *, stream: bool = False) -> AIMessage:
|
||||
""":private:"""
|
||||
"""Invoke with cache creation input.
|
||||
|
||||
:private:
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def test_unicode_tool_call_integration(
|
||||
@ -2979,7 +3017,7 @@ class ChatModelIntegrationTests(ChatModelTests):
|
||||
tool_choice: Optional[str] = None,
|
||||
force_tool_call: bool = True,
|
||||
) -> None:
|
||||
"""Generic integration test for Unicode characters in tool calls.
|
||||
r"""Generic integration test for Unicode characters in tool calls.
|
||||
|
||||
Args:
|
||||
model: The chat model to test
|
||||
|
@ -1,3 +1,5 @@
|
||||
"""Integration tests for embeddings."""
|
||||
|
||||
from langchain_core.embeddings import Embeddings
|
||||
|
||||
from langchain_tests.unit_tests.embeddings import EmbeddingsTests
|
||||
|
@ -1,3 +1,5 @@
|
||||
"""Integration tests for retrievers."""
|
||||
|
||||
from abc import abstractmethod
|
||||
|
||||
import pytest
|
||||
@ -37,7 +39,10 @@ class RetrieversIntegrationTests(BaseStandardTests):
|
||||
|
||||
@pytest.fixture
|
||||
def retriever(self) -> BaseRetriever:
|
||||
""":private:"""
|
||||
"""Return retriever fixture.
|
||||
|
||||
:private:
|
||||
"""
|
||||
return self.retriever_constructor(**self.retriever_constructor_params)
|
||||
|
||||
def test_k_constructor_param(self) -> None:
|
||||
@ -148,7 +153,9 @@ class RetrieversIntegrationTests(BaseStandardTests):
|
||||
assert all(isinstance(doc, Document) for doc in result_3)
|
||||
|
||||
def test_invoke_returns_documents(self, retriever: BaseRetriever) -> None:
|
||||
"""If invoked with the example params, the retriever should return a list of
|
||||
"""Test invoke returns documents.
|
||||
|
||||
If invoked with the example params, the retriever should return a list of
|
||||
Documents.
|
||||
|
||||
.. dropdown:: Troubleshooting
|
||||
@ -163,7 +170,9 @@ class RetrieversIntegrationTests(BaseStandardTests):
|
||||
assert all(isinstance(doc, Document) for doc in result)
|
||||
|
||||
async def test_ainvoke_returns_documents(self, retriever: BaseRetriever) -> None:
|
||||
"""If ainvoked with the example params, the retriever should return a list of
|
||||
"""Test ainvoke returns documents.
|
||||
|
||||
If ainvoked with the example params, the retriever should return a list of
|
||||
Documents.
|
||||
|
||||
See :meth:`test_invoke_returns_documents` for more information on
|
||||
|
@ -1,3 +1,5 @@
|
||||
"""Integration tests for tools."""
|
||||
|
||||
from langchain_core.messages import ToolCall
|
||||
from langchain_core.tools import BaseTool
|
||||
|
||||
@ -66,7 +68,9 @@ class ToolsIntegrationTests(ToolsTests):
|
||||
assert all(isinstance(c, (str, dict)) for c in tool_message.content)
|
||||
|
||||
def test_invoke_no_tool_call(self, tool: BaseTool) -> None:
|
||||
"""If invoked without a ToolCall, the tool can return anything
|
||||
"""Test invoke without ToolCall.
|
||||
|
||||
If invoked without a ToolCall, the tool can return anything
|
||||
but it shouldn't throw an error.
|
||||
|
||||
If this test fails, your tool may not be handling the input you defined
|
||||
@ -78,7 +82,9 @@ class ToolsIntegrationTests(ToolsTests):
|
||||
tool.invoke(self.tool_invoke_params_example)
|
||||
|
||||
async def test_async_invoke_no_tool_call(self, tool: BaseTool) -> None:
|
||||
"""If ainvoked without a ToolCall, the tool can return anything
|
||||
"""Test async invoke without ToolCall.
|
||||
|
||||
If ainvoked without a ToolCall, the tool can return anything
|
||||
but it shouldn't throw an error.
|
||||
|
||||
For debugging tips, see :meth:`test_invoke_no_tool_call`.
|
||||
|
@ -116,7 +116,9 @@ class VectorStoreIntegrationTests(BaseStandardTests):
|
||||
|
||||
@staticmethod
|
||||
def get_embeddings() -> Embeddings:
|
||||
"""A pre-defined embeddings model that should be used for this test.
|
||||
"""Get embeddings.
|
||||
|
||||
A pre-defined embeddings model that should be used for this test.
|
||||
|
||||
This currently uses ``DeterministicFakeEmbedding`` from ``langchain-core``,
|
||||
which uses numpy to generate random numbers based on a hash of the input text.
|
||||
@ -173,7 +175,9 @@ class VectorStoreIntegrationTests(BaseStandardTests):
|
||||
]
|
||||
|
||||
def test_vectorstore_still_empty(self, vectorstore: VectorStore) -> None:
|
||||
"""This test should follow a test that adds documents.
|
||||
"""Test that the vectorstore is still empty.
|
||||
|
||||
This test should follow a test that adds documents.
|
||||
|
||||
This just verifies that the fixture is set up properly to be empty
|
||||
after each test.
|
||||
@ -499,7 +503,9 @@ class VectorStoreIntegrationTests(BaseStandardTests):
|
||||
async def test_vectorstore_still_empty_async(
|
||||
self, vectorstore: VectorStore
|
||||
) -> None:
|
||||
"""This test should follow a test that adds documents.
|
||||
"""Test that the vectorstore is still empty.
|
||||
|
||||
This test should follow a test that adds documents.
|
||||
|
||||
This just verifies that the fixture is set up properly to be empty
|
||||
after each test.
|
||||
|
@ -1,3 +1,5 @@
|
||||
"""Unit tests for LangChain components."""
|
||||
|
||||
# ruff: noqa: E402
|
||||
import pytest
|
||||
|
||||
|
@ -83,7 +83,10 @@ class ChatModelTests(BaseStandardTests):
|
||||
|
||||
@property
|
||||
def standard_chat_model_params(self) -> dict:
|
||||
""":private:"""
|
||||
"""Standard chat model parameters.
|
||||
|
||||
:private:
|
||||
"""
|
||||
return {
|
||||
"temperature": 0,
|
||||
"max_tokens": 100,
|
||||
@ -94,7 +97,10 @@ class ChatModelTests(BaseStandardTests):
|
||||
|
||||
@pytest.fixture
|
||||
def model(self) -> BaseChatModel:
|
||||
""":private:"""
|
||||
"""Model fixture.
|
||||
|
||||
:private:
|
||||
"""
|
||||
return self.chat_model_class(
|
||||
**{
|
||||
**self.standard_chat_model_params,
|
||||
@ -104,11 +110,17 @@ class ChatModelTests(BaseStandardTests):
|
||||
|
||||
@pytest.fixture
|
||||
def my_adder_tool(self) -> BaseTool:
|
||||
""":private:"""
|
||||
"""Adder tool fixture.
|
||||
|
||||
:private:
|
||||
"""
|
||||
|
||||
@tool
|
||||
def my_adder_tool(a: int, b: int) -> int:
|
||||
"""Takes two integers, a and b, and returns their sum."""
|
||||
"""Tool that adds two integers.
|
||||
|
||||
Takes two integers, a and b, and returns their sum.
|
||||
"""
|
||||
return a + b
|
||||
|
||||
return my_adder_tool
|
||||
@ -151,12 +163,22 @@ class ChatModelTests(BaseStandardTests):
|
||||
|
||||
@property
|
||||
def supports_image_inputs(self) -> bool:
|
||||
"""(bool) whether the chat model supports image inputs, defaults to ``False``.""" # noqa: E501
|
||||
"""Supports image inputs.
|
||||
|
||||
(bool) whether the chat model supports image inputs, defaults to
|
||||
``False``.
|
||||
|
||||
"""
|
||||
return False
|
||||
|
||||
@property
|
||||
def supports_image_urls(self) -> bool:
|
||||
"""(bool) whether the chat model supports image inputs from URLs, defaults to ``False``.""" # noqa: E501
|
||||
"""Supports image inputs from URLs.
|
||||
|
||||
(bool) whether the chat model supports image inputs from URLs, defaults to
|
||||
``False``.
|
||||
|
||||
"""
|
||||
return False
|
||||
|
||||
@property
|
||||
@ -166,12 +188,18 @@ class ChatModelTests(BaseStandardTests):
|
||||
|
||||
@property
|
||||
def supports_audio_inputs(self) -> bool:
|
||||
"""(bool) whether the chat model supports audio inputs, defaults to ``False``.""" # noqa: E501
|
||||
"""Supports audio inputs.
|
||||
|
||||
(bool) whether the chat model supports audio inputs, defaults to ``False``.
|
||||
|
||||
"""
|
||||
return False
|
||||
|
||||
@property
|
||||
def supports_video_inputs(self) -> bool:
|
||||
"""(bool) whether the chat model supports video inputs, defaults to ``False``.
|
||||
"""Supports video inputs.
|
||||
|
||||
(bool) whether the chat model supports video inputs, defaults to ``False``.
|
||||
|
||||
No current tests are written for this feature.
|
||||
|
||||
@ -180,7 +208,12 @@ class ChatModelTests(BaseStandardTests):
|
||||
|
||||
@property
|
||||
def returns_usage_metadata(self) -> bool:
|
||||
"""(bool) whether the chat model returns usage metadata on invoke and streaming responses.""" # noqa: E501
|
||||
"""Returns usage metadata.
|
||||
|
||||
(bool) whether the chat model returns usage metadata on invoke and streaming
|
||||
responses.
|
||||
|
||||
"""
|
||||
return True
|
||||
|
||||
@property
|
||||
@ -190,7 +223,12 @@ class ChatModelTests(BaseStandardTests):
|
||||
|
||||
@property
|
||||
def supports_image_tool_message(self) -> bool:
|
||||
"""(bool) whether the chat model supports ``ToolMessage``s that include image content.""" # noqa: E501
|
||||
"""Supports image ToolMessages.
|
||||
|
||||
(bool) whether the chat model supports ToolMessages that include image
|
||||
content.
|
||||
|
||||
"""
|
||||
return False
|
||||
|
||||
@property
|
||||
@ -219,14 +257,16 @@ class ChatModelTests(BaseStandardTests):
|
||||
]
|
||||
],
|
||||
]:
|
||||
"""(dict) what usage metadata details are emitted in invoke and stream. Only
|
||||
"""Supported usage metadata details.
|
||||
|
||||
(dict) what usage metadata details are emitted in invoke and stream. Only
|
||||
needs to be overridden if these details are returned by the model.
|
||||
"""
|
||||
return {"invoke": [], "stream": []}
|
||||
|
||||
|
||||
class ChatModelUnitTests(ChatModelTests):
|
||||
"""Base class for chat model unit tests.
|
||||
'''Base class for chat model unit tests.
|
||||
|
||||
Test subclasses must implement the ``chat_model_class`` and
|
||||
``chat_model_params`` properties to specify what model to test and its
|
||||
@ -669,7 +709,7 @@ class ChatModelUnitTests(ChatModelTests):
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
def vcr_config(_base_vcr_config: dict) -> dict: # noqa: F811
|
||||
\"\"\"Extend the default configuration from langchain_tests.\"\"\"
|
||||
"""Extend the default configuration from langchain_tests."""
|
||||
config = _base_vcr_config.copy()
|
||||
config.setdefault("filter_headers", []).extend(_EXTRA_HEADERS)
|
||||
config["before_record_response"] = remove_response_headers
|
||||
@ -705,7 +745,7 @@ class ChatModelUnitTests(ChatModelTests):
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
def vcr_config(_base_vcr_config: dict) -> dict: # noqa: F811
|
||||
\"\"\"Extend the default configuration from langchain_tests.\"\"\"
|
||||
"""Extend the default configuration from langchain_tests."""
|
||||
config = _base_vcr_config.copy()
|
||||
config.setdefault("filter_headers", []).extend(_EXTRA_HEADERS)
|
||||
config["before_record_response"] = remove_response_headers
|
||||
@ -789,18 +829,23 @@ class ChatModelUnitTests(ChatModelTests):
|
||||
},
|
||||
)
|
||||
|
||||
""" # noqa: E501
|
||||
''' # noqa: E501,D214
|
||||
|
||||
@property
|
||||
def standard_chat_model_params(self) -> dict:
|
||||
""":private:"""
|
||||
"""Standard chat model parameters.
|
||||
|
||||
:private:
|
||||
"""
|
||||
params = super().standard_chat_model_params
|
||||
params["api_key"] = "test"
|
||||
return params
|
||||
|
||||
@property
|
||||
def init_from_env_params(self) -> tuple[dict, dict, dict]:
|
||||
"""(tuple) environment variables, additional initialization args, and expected
|
||||
"""Init from env params.
|
||||
|
||||
(tuple) environment variables, additional initialization args, and expected
|
||||
instance attributes for testing initialization from environment variables.
|
||||
|
||||
"""
|
||||
@ -826,9 +871,10 @@ class ChatModelUnitTests(ChatModelTests):
|
||||
assert model is not None
|
||||
|
||||
def test_init_from_env(self) -> None:
|
||||
"""Test initialization from environment variables. Relies on the
|
||||
``init_from_env_params`` property. Test is skipped if that property is not
|
||||
set.
|
||||
"""Test initialization from environment variables.
|
||||
|
||||
Relies on the ``init_from_env_params`` property. Test is skipped if that
|
||||
property is not set.
|
||||
|
||||
.. dropdown:: Troubleshooting
|
||||
|
||||
@ -853,8 +899,9 @@ class ChatModelUnitTests(ChatModelTests):
|
||||
def test_init_streaming(
|
||||
self,
|
||||
) -> None:
|
||||
"""Test that model can be initialized with ``streaming=True``. This is for
|
||||
backward-compatibility purposes.
|
||||
"""Test that model can be initialized with ``streaming=True``.
|
||||
|
||||
This is for backward-compatibility purposes.
|
||||
|
||||
.. dropdown:: Troubleshooting
|
||||
|
||||
@ -876,7 +923,9 @@ class ChatModelUnitTests(ChatModelTests):
|
||||
model: BaseChatModel,
|
||||
my_adder_tool: BaseTool,
|
||||
) -> None:
|
||||
"""Test that chat model correctly handles Pydantic models that are passed
|
||||
"""Test bind tools with Pydantic models.
|
||||
|
||||
Test that chat model correctly handles Pydantic models that are passed
|
||||
into ``bind_tools``. Test is skipped if the ``has_tool_calling`` property
|
||||
on the test class is False.
|
||||
|
||||
@ -893,7 +942,7 @@ class ChatModelUnitTests(ChatModelTests):
|
||||
return
|
||||
|
||||
def my_adder(a: int, b: int) -> int:
|
||||
"""Takes two integers, a and b, and returns their sum."""
|
||||
"""Return the sum of two integers."""
|
||||
return a + b
|
||||
|
||||
tools = [my_adder_tool, my_adder]
|
||||
@ -918,8 +967,10 @@ class ChatModelUnitTests(ChatModelTests):
|
||||
model: BaseChatModel,
|
||||
schema: Any,
|
||||
) -> None:
|
||||
"""Test ``with_structured_output`` method. Test is skipped if the
|
||||
``has_structured_output`` property on the test class is False.
|
||||
"""Test ``with_structured_output`` method.
|
||||
|
||||
Test is skipped if the ``has_structured_output`` property on the test class is
|
||||
False.
|
||||
|
||||
.. dropdown:: Troubleshooting
|
||||
|
||||
@ -942,8 +993,9 @@ class ChatModelUnitTests(ChatModelTests):
|
||||
)
|
||||
|
||||
def test_standard_params(self, model: BaseChatModel) -> None:
|
||||
"""Test that model properly generates standard parameters. These are used
|
||||
for tracing purposes.
|
||||
"""Test that model properly generates standard parameters.
|
||||
|
||||
These are used for tracing purposes.
|
||||
|
||||
.. dropdown:: Troubleshooting
|
||||
|
||||
@ -981,9 +1033,10 @@ class ChatModelUnitTests(ChatModelTests):
|
||||
pytest.fail(f"Validation error: {e}")
|
||||
|
||||
def test_serdes(self, model: BaseChatModel, snapshot: SnapshotAssertion) -> None:
|
||||
"""Test serialization and deserialization of the model. Test is skipped if the
|
||||
``is_lc_serializable`` property on the chat model class is not overwritten
|
||||
to return ``True``.
|
||||
"""Test serialization and deserialization of the model.
|
||||
|
||||
Test is skipped if the ``is_lc_serializable`` property on the chat model class
|
||||
is not overwritten to return ``True``.
|
||||
|
||||
.. dropdown:: Troubleshooting
|
||||
|
||||
@ -1007,7 +1060,9 @@ class ChatModelUnitTests(ChatModelTests):
|
||||
|
||||
@pytest.mark.benchmark
|
||||
def test_init_time(self, benchmark: BenchmarkFixture) -> None:
|
||||
"""Test initialization time of the chat model. If this test fails, check that
|
||||
"""Test initialization time of the chat model.
|
||||
|
||||
If this test fails, check that
|
||||
we are not introducing undue overhead in the model's initialization.
|
||||
|
||||
"""
|
||||
|
@ -1,3 +1,5 @@
|
||||
"""Embeddings unit tests."""
|
||||
|
||||
import os
|
||||
from abc import abstractmethod
|
||||
from unittest import mock
|
||||
@ -10,18 +12,24 @@ from langchain_tests.base import BaseStandardTests
|
||||
|
||||
|
||||
class EmbeddingsTests(BaseStandardTests):
|
||||
""":private:"""
|
||||
"""Embeddings tests base class.
|
||||
|
||||
:private:
|
||||
"""
|
||||
|
||||
@property
|
||||
@abstractmethod
|
||||
def embeddings_class(self) -> type[Embeddings]: ...
|
||||
def embeddings_class(self) -> type[Embeddings]:
|
||||
"""Embeddings class."""
|
||||
|
||||
@property
|
||||
def embedding_model_params(self) -> dict:
|
||||
"""Embeddings model parameters."""
|
||||
return {}
|
||||
|
||||
@pytest.fixture
|
||||
def model(self) -> Embeddings:
|
||||
"""Embeddings model fixture."""
|
||||
return self.embeddings_class(**self.embedding_model_params)
|
||||
|
||||
|
||||
@ -87,7 +95,7 @@ class EmbeddingsUnitTests(EmbeddingsTests):
|
||||
},
|
||||
)
|
||||
|
||||
"""
|
||||
""" # noqa: D214
|
||||
|
||||
def test_init(self) -> None:
|
||||
"""Test model initialization.
|
||||
@ -102,7 +110,9 @@ class EmbeddingsUnitTests(EmbeddingsTests):
|
||||
|
||||
@property
|
||||
def init_from_env_params(self) -> tuple[dict, dict, dict]:
|
||||
"""This property is used in unit tests to test initialization from environment
|
||||
"""Init from env params.
|
||||
|
||||
This property is used in unit tests to test initialization from environment
|
||||
variables. It should return a tuple of three dictionaries that specify the
|
||||
environment variables, additional initialization args, and expected instance
|
||||
attributes to check.
|
||||
@ -110,9 +120,10 @@ class EmbeddingsUnitTests(EmbeddingsTests):
|
||||
return {}, {}, {}
|
||||
|
||||
def test_init_from_env(self) -> None:
|
||||
"""Test initialization from environment variables. Relies on the
|
||||
``init_from_env_params`` property. Test is skipped if that property is not
|
||||
set.
|
||||
"""Test initialization from environment variables.
|
||||
|
||||
Relies on the ``init_from_env_params`` property.
|
||||
Test is skipped if that property is not set.
|
||||
|
||||
.. dropdown:: Troubleshooting
|
||||
|
||||
|
@ -1,3 +1,5 @@
|
||||
"""Tools unit tests."""
|
||||
|
||||
import os
|
||||
from abc import abstractmethod
|
||||
from typing import Union
|
||||
@ -11,9 +13,11 @@ from langchain_tests.base import BaseStandardTests
|
||||
|
||||
|
||||
class ToolsTests(BaseStandardTests):
|
||||
""":private:
|
||||
Base class for testing tools. This won't show in the documentation, but
|
||||
the docstrings will be inherited by subclasses.
|
||||
"""Base class for testing tools.
|
||||
|
||||
:private:
|
||||
This won't show in the documentation, but the docstrings will be inherited by
|
||||
subclasses.
|
||||
"""
|
||||
|
||||
@property
|
||||
@ -38,7 +42,10 @@ class ToolsTests(BaseStandardTests):
|
||||
|
||||
@pytest.fixture
|
||||
def tool(self) -> BaseTool:
|
||||
""":private:"""
|
||||
"""Tool fixture.
|
||||
|
||||
:private:
|
||||
"""
|
||||
if isinstance(self.tool_constructor, BaseTool):
|
||||
if self.tool_constructor_params != {}:
|
||||
msg = (
|
||||
@ -55,13 +62,17 @@ class ToolsUnitTests(ToolsTests):
|
||||
|
||||
@property
|
||||
def init_from_env_params(self) -> tuple[dict, dict, dict]:
|
||||
"""Return env vars, init args, and expected instance attrs for initializing
|
||||
"""Init from env params.
|
||||
|
||||
Return env vars, init args, and expected instance attrs for initializing
|
||||
from env vars.
|
||||
"""
|
||||
return {}, {}, {}
|
||||
|
||||
def test_init(self) -> None:
|
||||
"""Test that the tool can be initialized with :attr:`tool_constructor` and
|
||||
"""Test init.
|
||||
|
||||
Test that the tool can be initialized with :attr:`tool_constructor` and
|
||||
:attr:`tool_constructor_params`. If this fails, check that the
|
||||
keyword args defined in :attr:`tool_constructor_params` are valid.
|
||||
"""
|
||||
@ -72,6 +83,7 @@ class ToolsUnitTests(ToolsTests):
|
||||
assert tool is not None
|
||||
|
||||
def test_init_from_env(self) -> None:
|
||||
"""Test that the tool can be initialized from environment variables."""
|
||||
env_params, tools_params, expected_attrs = self.init_from_env_params
|
||||
if env_params:
|
||||
with mock.patch.dict(os.environ, env_params):
|
||||
|
@ -0,0 +1 @@
|
||||
"""Langchain tests utilities."""
|
@ -55,9 +55,12 @@ ignore_missing_imports = true
|
||||
target-version = "py39"
|
||||
|
||||
[tool.ruff.lint]
|
||||
select = ["E", "F", "I", "PGH", "T201", "UP",]
|
||||
select = ["D", "E", "F", "I", "PGH", "T201", "UP",]
|
||||
pyupgrade.keep-runtime-typing = true
|
||||
|
||||
[tool.ruff.lint.per-file-ignores]
|
||||
"tests/**" = [ "D1",]
|
||||
|
||||
[tool.coverage.run]
|
||||
omit = ["tests/*"]
|
||||
|
||||
|
@ -1,3 +1,5 @@
|
||||
"""Check imports script."""
|
||||
|
||||
import secrets
|
||||
import string
|
||||
import sys
|
||||
|
@ -10,7 +10,9 @@ from pydantic import Field
|
||||
|
||||
|
||||
class ChatParrotLink(BaseChatModel):
|
||||
"""A custom chat model that echoes the first `parrot_buffer_length` characters
|
||||
"""Chat Parrot Link.
|
||||
|
||||
A custom chat model that echoes the first `parrot_buffer_length` characters
|
||||
of the input.
|
||||
|
||||
When contributing an implementation to LangChain, carefully document
|
||||
@ -60,6 +62,8 @@ class ChatParrotLink(BaseChatModel):
|
||||
it makes it much easier to parse the output of the model
|
||||
downstream and understand why generation stopped.
|
||||
run_manager: A run manager with callbacks for the LLM.
|
||||
**kwargs: Additional keyword arguments.
|
||||
|
||||
"""
|
||||
# Replace this with actual logic to generate a response from a list
|
||||
# of messages.
|
||||
@ -111,6 +115,8 @@ class ChatParrotLink(BaseChatModel):
|
||||
it makes it much easier to parse the output of the model
|
||||
downstream and understand why generation stopped.
|
||||
run_manager: A run manager with callbacks for the LLM.
|
||||
**kwargs: Additional keyword arguments.
|
||||
|
||||
"""
|
||||
_ = stop # Mark as used to avoid unused variable warning
|
||||
_ = kwargs # Mark as used to avoid unused variable warning
|
||||
|
Loading…
Reference in New Issue
Block a user