mirror of
https://github.com/hwchase17/langchain.git
synced 2025-08-14 15:16:21 +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
|
from abc import ABC
|
||||||
|
|
||||||
|
|
||||||
class BaseStandardTests(ABC):
|
class BaseStandardTests(ABC):
|
||||||
""":private:"""
|
"""Base class for standard tests.
|
||||||
|
|
||||||
|
: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.
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
"""Pytest conftest."""
|
||||||
|
|
||||||
import gzip
|
import gzip
|
||||||
from os import PathLike
|
from os import PathLike
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
@ -88,7 +90,7 @@ _BASE_FILTER_HEADERS = [
|
|||||||
|
|
||||||
@pytest.fixture(scope="session")
|
@pytest.fixture(scope="session")
|
||||||
def _base_vcr_config() -> dict:
|
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.)
|
(Anything permitted by ``vcr.VCR(**kwargs)`` can be put here.)
|
||||||
"""
|
"""
|
||||||
@ -105,4 +107,5 @@ def _base_vcr_config() -> dict:
|
|||||||
|
|
||||||
@pytest.fixture(scope="session")
|
@pytest.fixture(scope="session")
|
||||||
def vcr_config(_base_vcr_config: dict) -> dict:
|
def vcr_config(_base_vcr_config: dict) -> dict:
|
||||||
|
"""VCR config fixture."""
|
||||||
return _base_vcr_config
|
return _base_vcr_config
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
"""Integration tests for LangChain components."""
|
||||||
|
|
||||||
# ruff: noqa: E402
|
# ruff: noqa: E402
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
@ -62,7 +62,9 @@ class BaseStoreSyncTests(BaseStandardTests, Generic[V]):
|
|||||||
assert kv_store.mget(["foo", "bar"]) == [foo, bar]
|
assert kv_store.mget(["foo", "bar"]) == [foo, bar]
|
||||||
|
|
||||||
def test_store_still_empty(self, kv_store: BaseStore[str, V]) -> None:
|
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
|
This just verifies that the fixture is set up properly to be empty
|
||||||
after each test.
|
after each test.
|
||||||
@ -192,7 +194,9 @@ class BaseStoreAsyncTests(BaseStandardTests, Generic[V]):
|
|||||||
assert await kv_store.amget(["foo", "bar"]) == [foo, bar]
|
assert await kv_store.amget(["foo", "bar"]) == [foo, bar]
|
||||||
|
|
||||||
async def test_store_still_empty(self, kv_store: BaseStore[str, V]) -> None:
|
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
|
This just verifies that the fixture is set up properly to be empty
|
||||||
after each test.
|
after each test.
|
||||||
|
@ -62,7 +62,9 @@ class SyncCacheTestSuite(BaseStandardTests):
|
|||||||
assert cache.lookup(prompt, llm_string) == [generation]
|
assert cache.lookup(prompt, llm_string) == [generation]
|
||||||
|
|
||||||
def test_cache_still_empty(self, cache: BaseCache) -> None:
|
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
|
This just verifies that the fixture is set up properly to be empty
|
||||||
after each test.
|
after each test.
|
||||||
@ -153,7 +155,9 @@ class AsyncCacheTestSuite(BaseStandardTests):
|
|||||||
assert await cache.alookup(prompt, llm_string) == [generation]
|
assert await cache.alookup(prompt, llm_string) == [generation]
|
||||||
|
|
||||||
async def test_cache_still_empty(self, cache: BaseCache) -> None:
|
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
|
This just verifies that the fixture is set up properly to be empty
|
||||||
after each test.
|
after each test.
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
"""Integration tests for chat models."""
|
||||||
|
|
||||||
import base64
|
import base64
|
||||||
import inspect
|
import inspect
|
||||||
import json
|
import json
|
||||||
@ -39,8 +41,6 @@ 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:"""
|
|
||||||
|
|
||||||
class Joke(BaseModel):
|
class Joke(BaseModel):
|
||||||
"""Joke to tell user."""
|
"""Joke to tell user."""
|
||||||
|
|
||||||
@ -95,13 +95,13 @@ class _MagicFunctionSchema(BaseModel):
|
|||||||
|
|
||||||
@tool(args_schema=_MagicFunctionSchema)
|
@tool(args_schema=_MagicFunctionSchema)
|
||||||
def magic_function(_input: int) -> int:
|
def magic_function(_input: int) -> int:
|
||||||
"""Applies a magic function to an input."""
|
"""Apply a magic function to an input."""
|
||||||
return _input + 2
|
return _input + 2
|
||||||
|
|
||||||
|
|
||||||
@tool
|
@tool
|
||||||
def magic_function_no_args() -> int:
|
def magic_function_no_args() -> int:
|
||||||
"""Calculates a magic function."""
|
"""Calculate a magic function."""
|
||||||
return 5
|
return 5
|
||||||
|
|
||||||
|
|
||||||
@ -143,7 +143,7 @@ def unicode_customer(customer_name: str, description: str) -> str:
|
|||||||
|
|
||||||
|
|
||||||
class ChatModelIntegrationTests(ChatModelTests):
|
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
|
Test subclasses must implement the ``chat_model_class`` and
|
||||||
``chat_model_params`` properties to specify what model to test and its
|
``chat_model_params`` properties to specify what model to test and its
|
||||||
@ -587,7 +587,7 @@ class ChatModelIntegrationTests(ChatModelTests):
|
|||||||
|
|
||||||
@pytest.fixture(scope="session")
|
@pytest.fixture(scope="session")
|
||||||
def vcr_config(_base_vcr_config: dict) -> dict: # noqa: F811
|
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 = _base_vcr_config.copy()
|
||||||
config.setdefault("filter_headers", []).extend(_EXTRA_HEADERS)
|
config.setdefault("filter_headers", []).extend(_EXTRA_HEADERS)
|
||||||
config["before_record_response"] = remove_response_headers
|
config["before_record_response"] = remove_response_headers
|
||||||
@ -623,7 +623,7 @@ class ChatModelIntegrationTests(ChatModelTests):
|
|||||||
|
|
||||||
@pytest.fixture(scope="session")
|
@pytest.fixture(scope="session")
|
||||||
def vcr_config(_base_vcr_config: dict) -> dict: # noqa: F811
|
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 = _base_vcr_config.copy()
|
||||||
config.setdefault("filter_headers", []).extend(_EXTRA_HEADERS)
|
config.setdefault("filter_headers", []).extend(_EXTRA_HEADERS)
|
||||||
config["before_record_response"] = remove_response_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
|
You can then commit the cassette to your repository. Subsequent test runs
|
||||||
will use the cassette instead of making HTTP calls.
|
will use the cassette instead of making HTTP calls.
|
||||||
|
|
||||||
""" # noqa: E501
|
''' # noqa: E501,D214
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def standard_chat_model_params(self) -> dict:
|
def standard_chat_model_params(self) -> dict:
|
||||||
""":private:"""
|
"""Standard parameters for chat model.
|
||||||
|
|
||||||
|
:private:
|
||||||
|
"""
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
def test_invoke(self, model: BaseChatModel) -> None:
|
def test_invoke(self, model: BaseChatModel) -> None:
|
||||||
@ -1270,8 +1273,10 @@ class ChatModelIntegrationTests(ChatModelTests):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def test_stop_sequence(self, model: BaseChatModel) -> None:
|
def test_stop_sequence(self, model: BaseChatModel) -> None:
|
||||||
"""Test that model does not fail when invoked with the ``stop`` parameter,
|
"""Test that model does not fail when invoked with the ``stop`` parameter.
|
||||||
which is a standard parameter for stopping generation at a certain token.
|
|
||||||
|
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>`__
|
`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)
|
assert isinstance(result, AIMessage)
|
||||||
|
|
||||||
def test_tool_calling(self, model: BaseChatModel) -> None:
|
def test_tool_calling(self, model: BaseChatModel) -> None:
|
||||||
"""Test that the model generates tool calls. This test is skipped if the
|
"""Test that the model generates tool calls.
|
||||||
``has_tool_calling`` property on the test class is set to False.
|
|
||||||
|
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
|
This test is optional and should be skipped if the model does not support
|
||||||
tool calling (see Configuration below).
|
tool calling (see Configuration below).
|
||||||
@ -1381,8 +1388,10 @@ class ChatModelIntegrationTests(ChatModelTests):
|
|||||||
_validate_tool_call_message(full)
|
_validate_tool_call_message(full)
|
||||||
|
|
||||||
async def test_tool_calling_async(self, model: BaseChatModel) -> None:
|
async def test_tool_calling_async(self, model: BaseChatModel) -> None:
|
||||||
"""Test that the model generates tool calls. This test is skipped if the
|
"""Test that the model generates tool calls.
|
||||||
``has_tool_calling`` property on the test class is set to False.
|
|
||||||
|
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
|
This test is optional and should be skipped if the model does not support
|
||||||
tool calling (see Configuration below).
|
tool calling (see Configuration below).
|
||||||
@ -1441,7 +1450,9 @@ class ChatModelIntegrationTests(ChatModelTests):
|
|||||||
_validate_tool_call_message(full)
|
_validate_tool_call_message(full)
|
||||||
|
|
||||||
def test_bind_runnables_as_tools(self, model: BaseChatModel) -> None:
|
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
|
LangChain runnables. This test is skipped if the ``has_tool_calling`` property
|
||||||
on the test class is set to False.
|
on the test class is set to False.
|
||||||
|
|
||||||
@ -1509,8 +1520,10 @@ class ChatModelIntegrationTests(ChatModelTests):
|
|||||||
def test_tool_message_histories_string_content(
|
def test_tool_message_histories_string_content(
|
||||||
self, model: BaseChatModel, my_adder_tool: BaseTool
|
self, model: BaseChatModel, my_adder_tool: BaseTool
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test that message histories are compatible with string tool contents
|
"""Test that message histories are compatible with string tool contents.
|
||||||
(e.g. OpenAI format). If a model passes this test, it should be compatible
|
|
||||||
|
For instance with OpenAI format contents.
|
||||||
|
If a model passes this test, it should be compatible
|
||||||
with messages generated from providers following OpenAI format.
|
with messages generated from providers following OpenAI format.
|
||||||
|
|
||||||
This test should be skipped if the model does not support tool calling
|
This test should be skipped if the model does not support tool calling
|
||||||
@ -1581,8 +1594,9 @@ class ChatModelIntegrationTests(ChatModelTests):
|
|||||||
model: BaseChatModel,
|
model: BaseChatModel,
|
||||||
my_adder_tool: BaseTool,
|
my_adder_tool: BaseTool,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test that message histories are compatible with list tool contents
|
"""Test that message histories are compatible with list tool contents.
|
||||||
(e.g. Anthropic format).
|
|
||||||
|
For instance with Anthropic format contents.
|
||||||
|
|
||||||
These message histories will include ``AIMessage`` objects with "tool use" and
|
These message histories will include ``AIMessage`` objects with "tool use" and
|
||||||
content blocks, e.g.,
|
content blocks, e.g.,
|
||||||
@ -1671,7 +1685,9 @@ class ChatModelIntegrationTests(ChatModelTests):
|
|||||||
assert isinstance(result_list_content, AIMessage)
|
assert isinstance(result_list_content, AIMessage)
|
||||||
|
|
||||||
def test_tool_choice(self, model: BaseChatModel) -> None:
|
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
|
parameter. This test is skipped if the ``has_tool_choice`` property on the
|
||||||
test class is set to False.
|
test class is set to False.
|
||||||
|
|
||||||
@ -1723,6 +1739,7 @@ class ChatModelIntegrationTests(ChatModelTests):
|
|||||||
|
|
||||||
def test_tool_calling_with_no_arguments(self, model: BaseChatModel) -> None:
|
def test_tool_calling_with_no_arguments(self, model: BaseChatModel) -> None:
|
||||||
"""Test that the model generates tool calls for tools with no arguments.
|
"""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
|
This test is skipped if the ``has_tool_calling`` property on the test class
|
||||||
is set to False.
|
is set to False.
|
||||||
|
|
||||||
@ -2075,7 +2092,9 @@ class ChatModelIntegrationTests(ChatModelTests):
|
|||||||
|
|
||||||
@pytest.mark.skipif(PYDANTIC_MAJOR_VERSION != 2, reason="Test requires pydantic 2.")
|
@pytest.mark.skipif(PYDANTIC_MAJOR_VERSION != 2, reason="Test requires pydantic 2.")
|
||||||
def test_structured_output_pydantic_2_v1(self, model: BaseChatModel) -> None:
|
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.
|
``pydantic.v1.BaseModel`` is available in the Pydantic 2 package.
|
||||||
|
|
||||||
@ -2140,7 +2159,9 @@ class ChatModelIntegrationTests(ChatModelTests):
|
|||||||
assert set(chunk.keys()) == {"setup", "punchline"}
|
assert set(chunk.keys()) == {"setup", "punchline"}
|
||||||
|
|
||||||
def test_structured_output_optional_param(self, model: BaseChatModel) -> None:
|
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.
|
parameters.
|
||||||
|
|
||||||
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
|
||||||
@ -2847,8 +2868,10 @@ class ChatModelIntegrationTests(ChatModelTests):
|
|||||||
assert len(result.content) > 0
|
assert len(result.content) > 0
|
||||||
|
|
||||||
def test_agent_loop(self, model: BaseChatModel) -> None:
|
def test_agent_loop(self, model: BaseChatModel) -> None:
|
||||||
"""Test that the model supports a simple ReAct agent loop. This test is skipped
|
"""Test that the model supports a simple ReAct agent loop.
|
||||||
if the ``has_tool_calling`` property on the test class is set to False.
|
|
||||||
|
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
|
This test is optional and should be skipped if the model does not support
|
||||||
tool calling (see Configuration below).
|
tool calling (see Configuration below).
|
||||||
@ -2953,23 +2976,38 @@ class ChatModelIntegrationTests(ChatModelTests):
|
|||||||
benchmark(_run)
|
benchmark(_run)
|
||||||
|
|
||||||
def invoke_with_audio_input(self, *, stream: bool = False) -> AIMessage:
|
def invoke_with_audio_input(self, *, stream: bool = False) -> AIMessage:
|
||||||
""":private:"""
|
"""Invoke with audio input.
|
||||||
|
|
||||||
|
: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:"""
|
"""Invoke with audio output.
|
||||||
|
|
||||||
|
: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:"""
|
"""Invoke with reasoning output.
|
||||||
|
|
||||||
|
: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:"""
|
"""Invoke with cache read input.
|
||||||
|
|
||||||
|
: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:"""
|
"""Invoke with cache creation input.
|
||||||
|
|
||||||
|
:private:
|
||||||
|
"""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
def test_unicode_tool_call_integration(
|
def test_unicode_tool_call_integration(
|
||||||
@ -2979,7 +3017,7 @@ class ChatModelIntegrationTests(ChatModelTests):
|
|||||||
tool_choice: Optional[str] = None,
|
tool_choice: Optional[str] = None,
|
||||||
force_tool_call: bool = True,
|
force_tool_call: bool = True,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Generic integration test for Unicode characters in tool calls.
|
r"""Generic integration test for Unicode characters in tool calls.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
model: The chat model to test
|
model: The chat model to test
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
"""Integration tests for embeddings."""
|
||||||
|
|
||||||
from langchain_core.embeddings import Embeddings
|
from langchain_core.embeddings import Embeddings
|
||||||
|
|
||||||
from langchain_tests.unit_tests.embeddings import EmbeddingsTests
|
from langchain_tests.unit_tests.embeddings import EmbeddingsTests
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
"""Integration tests for retrievers."""
|
||||||
|
|
||||||
from abc import abstractmethod
|
from abc import abstractmethod
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
@ -37,7 +39,10 @@ class RetrieversIntegrationTests(BaseStandardTests):
|
|||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def retriever(self) -> BaseRetriever:
|
def retriever(self) -> BaseRetriever:
|
||||||
""":private:"""
|
"""Return retriever fixture.
|
||||||
|
|
||||||
|
: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:
|
||||||
@ -148,7 +153,9 @@ 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
|
"""Test invoke returns documents.
|
||||||
|
|
||||||
|
If invoked with the example params, the retriever should return a list of
|
||||||
Documents.
|
Documents.
|
||||||
|
|
||||||
.. dropdown:: Troubleshooting
|
.. dropdown:: Troubleshooting
|
||||||
@ -163,7 +170,9 @@ 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
|
"""Test ainvoke returns documents.
|
||||||
|
|
||||||
|
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
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
"""Integration tests for tools."""
|
||||||
|
|
||||||
from langchain_core.messages import ToolCall
|
from langchain_core.messages import ToolCall
|
||||||
from langchain_core.tools import BaseTool
|
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)
|
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
|
"""Test invoke without ToolCall.
|
||||||
|
|
||||||
|
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
|
||||||
@ -78,7 +82,9 @@ 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
|
"""Test async invoke without ToolCall.
|
||||||
|
|
||||||
|
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`.
|
||||||
|
@ -116,7 +116,9 @@ class VectorStoreIntegrationTests(BaseStandardTests):
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_embeddings() -> Embeddings:
|
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``,
|
This currently uses ``DeterministicFakeEmbedding`` from ``langchain-core``,
|
||||||
which uses numpy to generate random numbers based on a hash of the input text.
|
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:
|
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
|
This just verifies that the fixture is set up properly to be empty
|
||||||
after each test.
|
after each test.
|
||||||
@ -499,7 +503,9 @@ class VectorStoreIntegrationTests(BaseStandardTests):
|
|||||||
async def test_vectorstore_still_empty_async(
|
async def test_vectorstore_still_empty_async(
|
||||||
self, vectorstore: VectorStore
|
self, vectorstore: VectorStore
|
||||||
) -> None:
|
) -> 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
|
This just verifies that the fixture is set up properly to be empty
|
||||||
after each test.
|
after each test.
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
"""Unit tests for LangChain components."""
|
||||||
|
|
||||||
# ruff: noqa: E402
|
# ruff: noqa: E402
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
@ -83,7 +83,10 @@ class ChatModelTests(BaseStandardTests):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def standard_chat_model_params(self) -> dict:
|
def standard_chat_model_params(self) -> dict:
|
||||||
""":private:"""
|
"""Standard chat model parameters.
|
||||||
|
|
||||||
|
:private:
|
||||||
|
"""
|
||||||
return {
|
return {
|
||||||
"temperature": 0,
|
"temperature": 0,
|
||||||
"max_tokens": 100,
|
"max_tokens": 100,
|
||||||
@ -94,7 +97,10 @@ class ChatModelTests(BaseStandardTests):
|
|||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def model(self) -> BaseChatModel:
|
def model(self) -> BaseChatModel:
|
||||||
""":private:"""
|
"""Model fixture.
|
||||||
|
|
||||||
|
:private:
|
||||||
|
"""
|
||||||
return self.chat_model_class(
|
return self.chat_model_class(
|
||||||
**{
|
**{
|
||||||
**self.standard_chat_model_params,
|
**self.standard_chat_model_params,
|
||||||
@ -104,11 +110,17 @@ class ChatModelTests(BaseStandardTests):
|
|||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def my_adder_tool(self) -> BaseTool:
|
def my_adder_tool(self) -> BaseTool:
|
||||||
""":private:"""
|
"""Adder tool fixture.
|
||||||
|
|
||||||
|
:private:
|
||||||
|
"""
|
||||||
|
|
||||||
@tool
|
@tool
|
||||||
def my_adder_tool(a: int, b: int) -> int:
|
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 a + b
|
||||||
|
|
||||||
return my_adder_tool
|
return my_adder_tool
|
||||||
@ -151,12 +163,22 @@ 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 ``False``.""" # noqa: E501
|
"""Supports image inputs.
|
||||||
|
|
||||||
|
(bool) whether the chat model supports image inputs, defaults to
|
||||||
|
``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 ``False``.""" # noqa: E501
|
"""Supports image inputs from URLs.
|
||||||
|
|
||||||
|
(bool) whether the chat model supports image inputs from URLs, defaults to
|
||||||
|
``False``.
|
||||||
|
|
||||||
|
"""
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@ -166,12 +188,18 @@ 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 ``False``.""" # noqa: E501
|
"""Supports audio inputs.
|
||||||
|
|
||||||
|
(bool) whether the chat model supports audio inputs, defaults to ``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``.
|
"""Supports video inputs.
|
||||||
|
|
||||||
|
(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.
|
||||||
|
|
||||||
@ -180,7 +208,12 @@ class ChatModelTests(BaseStandardTests):
|
|||||||
|
|
||||||
@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 responses.""" # noqa: E501
|
"""Returns usage metadata.
|
||||||
|
|
||||||
|
(bool) whether the chat model returns usage metadata on invoke and streaming
|
||||||
|
responses.
|
||||||
|
|
||||||
|
"""
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@ -190,7 +223,12 @@ 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 ``ToolMessage``s that include image content.""" # noqa: E501
|
"""Supports image ToolMessages.
|
||||||
|
|
||||||
|
(bool) whether the chat model supports ToolMessages that include image
|
||||||
|
content.
|
||||||
|
|
||||||
|
"""
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@property
|
@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.
|
needs to be overridden if these details are returned by the model.
|
||||||
"""
|
"""
|
||||||
return {"invoke": [], "stream": []}
|
return {"invoke": [], "stream": []}
|
||||||
|
|
||||||
|
|
||||||
class ChatModelUnitTests(ChatModelTests):
|
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
|
Test subclasses must implement the ``chat_model_class`` and
|
||||||
``chat_model_params`` properties to specify what model to test and its
|
``chat_model_params`` properties to specify what model to test and its
|
||||||
@ -669,7 +709,7 @@ class ChatModelUnitTests(ChatModelTests):
|
|||||||
|
|
||||||
@pytest.fixture(scope="session")
|
@pytest.fixture(scope="session")
|
||||||
def vcr_config(_base_vcr_config: dict) -> dict: # noqa: F811
|
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 = _base_vcr_config.copy()
|
||||||
config.setdefault("filter_headers", []).extend(_EXTRA_HEADERS)
|
config.setdefault("filter_headers", []).extend(_EXTRA_HEADERS)
|
||||||
config["before_record_response"] = remove_response_headers
|
config["before_record_response"] = remove_response_headers
|
||||||
@ -705,7 +745,7 @@ class ChatModelUnitTests(ChatModelTests):
|
|||||||
|
|
||||||
@pytest.fixture(scope="session")
|
@pytest.fixture(scope="session")
|
||||||
def vcr_config(_base_vcr_config: dict) -> dict: # noqa: F811
|
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 = _base_vcr_config.copy()
|
||||||
config.setdefault("filter_headers", []).extend(_EXTRA_HEADERS)
|
config.setdefault("filter_headers", []).extend(_EXTRA_HEADERS)
|
||||||
config["before_record_response"] = remove_response_headers
|
config["before_record_response"] = remove_response_headers
|
||||||
@ -789,18 +829,23 @@ class ChatModelUnitTests(ChatModelTests):
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
""" # noqa: E501
|
''' # noqa: E501,D214
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def standard_chat_model_params(self) -> dict:
|
def standard_chat_model_params(self) -> dict:
|
||||||
""":private:"""
|
"""Standard chat model parameters.
|
||||||
|
|
||||||
|
:private:
|
||||||
|
"""
|
||||||
params = super().standard_chat_model_params
|
params = super().standard_chat_model_params
|
||||||
params["api_key"] = "test"
|
params["api_key"] = "test"
|
||||||
return params
|
return params
|
||||||
|
|
||||||
@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
|
"""Init from env params.
|
||||||
|
|
||||||
|
(tuple) environment variables, additional initialization args, and expected
|
||||||
instance attributes for testing initialization from environment variables.
|
instance attributes for testing initialization from environment variables.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
@ -826,9 +871,10 @@ class ChatModelUnitTests(ChatModelTests):
|
|||||||
assert model is not None
|
assert model is not None
|
||||||
|
|
||||||
def test_init_from_env(self) -> None:
|
def test_init_from_env(self) -> None:
|
||||||
"""Test initialization from environment variables. Relies on the
|
"""Test initialization from environment variables.
|
||||||
``init_from_env_params`` property. Test is skipped if that property is not
|
|
||||||
set.
|
Relies on the ``init_from_env_params`` property. Test is skipped if that
|
||||||
|
property is not set.
|
||||||
|
|
||||||
.. dropdown:: Troubleshooting
|
.. dropdown:: Troubleshooting
|
||||||
|
|
||||||
@ -853,8 +899,9 @@ class ChatModelUnitTests(ChatModelTests):
|
|||||||
def test_init_streaming(
|
def test_init_streaming(
|
||||||
self,
|
self,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test that model can be initialized with ``streaming=True``. This is for
|
"""Test that model can be initialized with ``streaming=True``.
|
||||||
backward-compatibility purposes.
|
|
||||||
|
This is for backward-compatibility purposes.
|
||||||
|
|
||||||
.. dropdown:: Troubleshooting
|
.. dropdown:: Troubleshooting
|
||||||
|
|
||||||
@ -876,7 +923,9 @@ class ChatModelUnitTests(ChatModelTests):
|
|||||||
model: BaseChatModel,
|
model: BaseChatModel,
|
||||||
my_adder_tool: BaseTool,
|
my_adder_tool: BaseTool,
|
||||||
) -> None:
|
) -> 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
|
into ``bind_tools``. Test is skipped if the ``has_tool_calling`` property
|
||||||
on the test class is False.
|
on the test class is False.
|
||||||
|
|
||||||
@ -893,7 +942,7 @@ class ChatModelUnitTests(ChatModelTests):
|
|||||||
return
|
return
|
||||||
|
|
||||||
def my_adder(a: int, b: int) -> int:
|
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
|
return a + b
|
||||||
|
|
||||||
tools = [my_adder_tool, my_adder]
|
tools = [my_adder_tool, my_adder]
|
||||||
@ -918,8 +967,10 @@ class ChatModelUnitTests(ChatModelTests):
|
|||||||
model: BaseChatModel,
|
model: BaseChatModel,
|
||||||
schema: Any,
|
schema: Any,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test ``with_structured_output`` method. Test is skipped if the
|
"""Test ``with_structured_output`` method.
|
||||||
``has_structured_output`` property on the test class is False.
|
|
||||||
|
Test is skipped if the ``has_structured_output`` property on the test class is
|
||||||
|
False.
|
||||||
|
|
||||||
.. dropdown:: Troubleshooting
|
.. dropdown:: Troubleshooting
|
||||||
|
|
||||||
@ -942,8 +993,9 @@ class ChatModelUnitTests(ChatModelTests):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def test_standard_params(self, model: BaseChatModel) -> None:
|
def test_standard_params(self, model: BaseChatModel) -> None:
|
||||||
"""Test that model properly generates standard parameters. These are used
|
"""Test that model properly generates standard parameters.
|
||||||
for tracing purposes.
|
|
||||||
|
These are used for tracing purposes.
|
||||||
|
|
||||||
.. dropdown:: Troubleshooting
|
.. dropdown:: Troubleshooting
|
||||||
|
|
||||||
@ -981,9 +1033,10 @@ class ChatModelUnitTests(ChatModelTests):
|
|||||||
pytest.fail(f"Validation error: {e}")
|
pytest.fail(f"Validation error: {e}")
|
||||||
|
|
||||||
def test_serdes(self, model: BaseChatModel, snapshot: SnapshotAssertion) -> None:
|
def test_serdes(self, model: BaseChatModel, snapshot: SnapshotAssertion) -> None:
|
||||||
"""Test serialization and deserialization of the model. Test is skipped if the
|
"""Test serialization and deserialization of the model.
|
||||||
``is_lc_serializable`` property on the chat model class is not overwritten
|
|
||||||
to return ``True``.
|
Test is skipped if the ``is_lc_serializable`` property on the chat model class
|
||||||
|
is not overwritten to return ``True``.
|
||||||
|
|
||||||
.. dropdown:: Troubleshooting
|
.. dropdown:: Troubleshooting
|
||||||
|
|
||||||
@ -1007,7 +1060,9 @@ class ChatModelUnitTests(ChatModelTests):
|
|||||||
|
|
||||||
@pytest.mark.benchmark
|
@pytest.mark.benchmark
|
||||||
def test_init_time(self, benchmark: BenchmarkFixture) -> None:
|
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.
|
we are not introducing undue overhead in the model's initialization.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
"""Embeddings unit tests."""
|
||||||
|
|
||||||
import os
|
import os
|
||||||
from abc import abstractmethod
|
from abc import abstractmethod
|
||||||
from unittest import mock
|
from unittest import mock
|
||||||
@ -10,18 +12,24 @@ from langchain_tests.base import BaseStandardTests
|
|||||||
|
|
||||||
|
|
||||||
class EmbeddingsTests(BaseStandardTests):
|
class EmbeddingsTests(BaseStandardTests):
|
||||||
""":private:"""
|
"""Embeddings tests base class.
|
||||||
|
|
||||||
|
:private:
|
||||||
|
"""
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def embeddings_class(self) -> type[Embeddings]: ...
|
def embeddings_class(self) -> type[Embeddings]:
|
||||||
|
"""Embeddings class."""
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def embedding_model_params(self) -> dict:
|
def embedding_model_params(self) -> dict:
|
||||||
|
"""Embeddings model parameters."""
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def model(self) -> Embeddings:
|
def model(self) -> Embeddings:
|
||||||
|
"""Embeddings model fixture."""
|
||||||
return self.embeddings_class(**self.embedding_model_params)
|
return self.embeddings_class(**self.embedding_model_params)
|
||||||
|
|
||||||
|
|
||||||
@ -87,7 +95,7 @@ class EmbeddingsUnitTests(EmbeddingsTests):
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
"""
|
""" # noqa: D214
|
||||||
|
|
||||||
def test_init(self) -> None:
|
def test_init(self) -> None:
|
||||||
"""Test model initialization.
|
"""Test model initialization.
|
||||||
@ -102,7 +110,9 @@ class EmbeddingsUnitTests(EmbeddingsTests):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def init_from_env_params(self) -> tuple[dict, dict, dict]:
|
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
|
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.
|
||||||
@ -110,9 +120,10 @@ class EmbeddingsUnitTests(EmbeddingsTests):
|
|||||||
return {}, {}, {}
|
return {}, {}, {}
|
||||||
|
|
||||||
def test_init_from_env(self) -> None:
|
def test_init_from_env(self) -> None:
|
||||||
"""Test initialization from environment variables. Relies on the
|
"""Test initialization from environment variables.
|
||||||
``init_from_env_params`` property. Test is skipped if that property is not
|
|
||||||
set.
|
Relies on the ``init_from_env_params`` property.
|
||||||
|
Test is skipped if that property is not set.
|
||||||
|
|
||||||
.. dropdown:: Troubleshooting
|
.. dropdown:: Troubleshooting
|
||||||
|
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
"""Tools unit tests."""
|
||||||
|
|
||||||
import os
|
import os
|
||||||
from abc import abstractmethod
|
from abc import abstractmethod
|
||||||
from typing import Union
|
from typing import Union
|
||||||
@ -11,9 +13,11 @@ from langchain_tests.base import BaseStandardTests
|
|||||||
|
|
||||||
|
|
||||||
class ToolsTests(BaseStandardTests):
|
class ToolsTests(BaseStandardTests):
|
||||||
""":private:
|
"""Base class for testing tools.
|
||||||
Base class for testing tools. This won't show in the documentation, but
|
|
||||||
the docstrings will be inherited by subclasses.
|
:private:
|
||||||
|
This won't show in the documentation, but the docstrings will be inherited by
|
||||||
|
subclasses.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@ -38,7 +42,10 @@ class ToolsTests(BaseStandardTests):
|
|||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def tool(self) -> BaseTool:
|
def tool(self) -> BaseTool:
|
||||||
""":private:"""
|
"""Tool fixture.
|
||||||
|
|
||||||
|
: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 = (
|
||||||
@ -55,13 +62,17 @@ class ToolsUnitTests(ToolsTests):
|
|||||||
|
|
||||||
@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
|
"""Init from env params.
|
||||||
|
|
||||||
|
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 init.
|
||||||
|
|
||||||
|
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.
|
||||||
"""
|
"""
|
||||||
@ -72,6 +83,7 @@ class ToolsUnitTests(ToolsTests):
|
|||||||
assert tool is not None
|
assert tool is not None
|
||||||
|
|
||||||
def test_init_from_env(self) -> 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
|
env_params, tools_params, expected_attrs = self.init_from_env_params
|
||||||
if env_params:
|
if env_params:
|
||||||
with mock.patch.dict(os.environ, 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"
|
target-version = "py39"
|
||||||
|
|
||||||
[tool.ruff.lint]
|
[tool.ruff.lint]
|
||||||
select = ["E", "F", "I", "PGH", "T201", "UP",]
|
select = ["D", "E", "F", "I", "PGH", "T201", "UP",]
|
||||||
pyupgrade.keep-runtime-typing = true
|
pyupgrade.keep-runtime-typing = true
|
||||||
|
|
||||||
|
[tool.ruff.lint.per-file-ignores]
|
||||||
|
"tests/**" = [ "D1",]
|
||||||
|
|
||||||
[tool.coverage.run]
|
[tool.coverage.run]
|
||||||
omit = ["tests/*"]
|
omit = ["tests/*"]
|
||||||
|
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
"""Check imports script."""
|
||||||
|
|
||||||
import secrets
|
import secrets
|
||||||
import string
|
import string
|
||||||
import sys
|
import sys
|
||||||
|
@ -10,7 +10,9 @@ from pydantic import Field
|
|||||||
|
|
||||||
|
|
||||||
class ChatParrotLink(BaseChatModel):
|
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.
|
of the input.
|
||||||
|
|
||||||
When contributing an implementation to LangChain, carefully document
|
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
|
it makes it much easier to parse the output of the model
|
||||||
downstream and understand why generation stopped.
|
downstream and understand why generation stopped.
|
||||||
run_manager: A run manager with callbacks for the LLM.
|
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
|
# Replace this with actual logic to generate a response from a list
|
||||||
# of messages.
|
# of messages.
|
||||||
@ -111,6 +115,8 @@ class ChatParrotLink(BaseChatModel):
|
|||||||
it makes it much easier to parse the output of the model
|
it makes it much easier to parse the output of the model
|
||||||
downstream and understand why generation stopped.
|
downstream and understand why generation stopped.
|
||||||
run_manager: A run manager with callbacks for the LLM.
|
run_manager: A run manager with callbacks for the LLM.
|
||||||
|
**kwargs: Additional keyword arguments.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
_ = stop # Mark as used to avoid unused variable warning
|
_ = stop # Mark as used to avoid unused variable warning
|
||||||
_ = kwargs # 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