mirror of
https://github.com/hwchase17/langchain.git
synced 2025-07-10 06:55:09 +00:00
standard-tests: Ruff autofixes (#31862)
Auto-fixes from ruff with rule ALL
This commit is contained in:
parent
2df3fdf40d
commit
9368b92b2c
@ -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
|
||||
`Integration standard testing <https://python.langchain.com/docs/contributing/how_to/integrations/standard_tests/>`_
|
||||
|
@ -2,13 +2,10 @@ from abc import ABC
|
||||
|
||||
|
||||
class BaseStandardTests(ABC):
|
||||
"""
|
||||
:private:
|
||||
"""
|
||||
""":private:"""
|
||||
|
||||
def test_no_overrides_DO_NOT_OVERRIDE(self) -> None:
|
||||
"""
|
||||
Test that no standard tests are overridden.
|
||||
"""Test that no standard tests are overridden.
|
||||
|
||||
:private:
|
||||
"""
|
||||
@ -22,10 +19,11 @@ class BaseStandardTests(ABC):
|
||||
if comparison_class is None:
|
||||
comparison_class = base
|
||||
else:
|
||||
raise ValueError(
|
||||
msg = (
|
||||
"Multiple standard test base classes found: "
|
||||
f"{comparison_class}, {base}"
|
||||
)
|
||||
raise ValueError(msg)
|
||||
else:
|
||||
explore_bases(base)
|
||||
|
||||
@ -34,12 +32,10 @@ class BaseStandardTests(ABC):
|
||||
|
||||
print(f"Comparing {self.__class__} to {comparison_class}") # noqa: T201
|
||||
|
||||
running_tests = set(
|
||||
[method for method in dir(self) if method.startswith("test_")]
|
||||
)
|
||||
base_tests = set(
|
||||
[method for method in dir(comparison_class) if method.startswith("test_")]
|
||||
)
|
||||
running_tests = {method for method in dir(self) if method.startswith("test_")}
|
||||
base_tests = {
|
||||
method for method in dir(comparison_class) if method.startswith("test_")
|
||||
}
|
||||
deleted_tests = base_tests - running_tests
|
||||
assert not deleted_tests, f"Standard tests deleted: {deleted_tests}"
|
||||
|
||||
|
@ -52,9 +52,8 @@ class CustomPersister:
|
||||
# If cassette path is already Path this is a no-op
|
||||
cassette_path = Path(cassette_path)
|
||||
if not cassette_path.is_file():
|
||||
raise CassetteNotFoundError(
|
||||
f"Cassette file {cassette_path} does not exist."
|
||||
)
|
||||
msg = f"Cassette file {cassette_path} does not exist."
|
||||
raise CassetteNotFoundError(msg)
|
||||
with cassette_path.open(mode="rb") as f:
|
||||
data = f.read()
|
||||
deser = serializer.deserialize(data)
|
||||
|
@ -26,13 +26,13 @@ from .tools import ToolsIntegrationTests
|
||||
from .vectorstores import VectorStoreIntegrationTests
|
||||
|
||||
__all__ = [
|
||||
"ChatModelIntegrationTests",
|
||||
"EmbeddingsIntegrationTests",
|
||||
"ToolsIntegrationTests",
|
||||
"AsyncCacheTestSuite",
|
||||
"BaseStoreAsyncTests",
|
||||
"BaseStoreSyncTests",
|
||||
"AsyncCacheTestSuite",
|
||||
"SyncCacheTestSuite",
|
||||
"VectorStoreIntegrationTests",
|
||||
"ChatModelIntegrationTests",
|
||||
"EmbeddingsIntegrationTests",
|
||||
"RetrieversIntegrationTests",
|
||||
"SyncCacheTestSuite",
|
||||
"ToolsIntegrationTests",
|
||||
"VectorStoreIntegrationTests",
|
||||
]
|
||||
|
@ -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.
|
||||
|
||||
@ -38,10 +37,9 @@ class BaseStoreSyncTests(BaseStandardTests, Generic[V]):
|
||||
"""
|
||||
|
||||
@abstractmethod
|
||||
@pytest.fixture()
|
||||
@pytest.fixture
|
||||
def three_values(self) -> tuple[V, V, V]:
|
||||
"""Three example values that will be used in the tests."""
|
||||
pass
|
||||
|
||||
def test_three_values(self, three_values: tuple[V, V, V]) -> None:
|
||||
"""Test that the fixture provides three values."""
|
||||
@ -169,10 +167,9 @@ class BaseStoreAsyncTests(BaseStandardTests, Generic[V]):
|
||||
"""
|
||||
|
||||
@abstractmethod
|
||||
@pytest.fixture()
|
||||
@pytest.fixture
|
||||
def three_values(self) -> tuple[V, V, V]:
|
||||
"""Three example values that will be used in the tests."""
|
||||
pass
|
||||
|
||||
async def test_three_values(self, three_values: tuple[V, V, V]) -> None:
|
||||
"""Test that the fixture provides three values."""
|
||||
|
@ -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.
|
||||
|
||||
|
@ -41,9 +41,7 @@ from langchain_tests.utils.pydantic import PYDANTIC_MAJOR_VERSION
|
||||
def _get_joke_class(
|
||||
schema_type: Literal["pydantic", "typeddict", "json_schema"],
|
||||
) -> Any:
|
||||
"""
|
||||
:private:
|
||||
"""
|
||||
""":private:"""
|
||||
|
||||
class Joke(BaseModel):
|
||||
"""Joke to tell user."""
|
||||
@ -61,18 +59,18 @@ def _get_joke_class(
|
||||
punchline: Annotated[str, ..., "answer to resolve the joke"]
|
||||
|
||||
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":
|
||||
return Joke, validate_joke
|
||||
|
||||
elif schema_type == "typeddict":
|
||||
if schema_type == "typeddict":
|
||||
return JokeDict, validate_joke_dict
|
||||
|
||||
elif schema_type == "json_schema":
|
||||
if schema_type == "json_schema":
|
||||
return Joke.model_json_schema(), validate_joke_dict
|
||||
else:
|
||||
raise ValueError("Invalid schema type")
|
||||
msg = "Invalid schema type"
|
||||
raise ValueError(msg)
|
||||
|
||||
|
||||
class _TestCallbackHandler(BaseCallbackHandler):
|
||||
@ -879,8 +877,7 @@ class ChatModelIntegrationTests(ChatModelTests):
|
||||
assert len(result.content) > 0
|
||||
|
||||
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
|
||||
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
|
||||
|
||||
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.
|
||||
|
||||
.. versionchanged:: 0.3.17
|
||||
@ -1193,7 +1191,7 @@ class ChatModelIntegrationTests(ChatModelTests):
|
||||
"Only one chunk should set input_tokens,"
|
||||
" 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 full.usage_metadata is not None
|
||||
@ -1261,7 +1259,7 @@ class ChatModelIntegrationTests(ChatModelTests):
|
||||
run_manager: Optional[CallbackManagerForLLMRun] = None,
|
||||
**kwargs: Any,
|
||||
) -> ChatResult:
|
||||
""" # noqa: E501
|
||||
"""
|
||||
result = model.invoke("hi", stop=["you"])
|
||||
assert isinstance(result, AIMessage)
|
||||
|
||||
@ -1315,10 +1313,7 @@ class ChatModelIntegrationTests(ChatModelTests):
|
||||
"""
|
||||
if not self.has_tool_calling:
|
||||
pytest.skip("Test requires tool calling.")
|
||||
if not self.has_tool_choice:
|
||||
tool_choice_value = None
|
||||
else:
|
||||
tool_choice_value = "any"
|
||||
tool_choice_value = None if not self.has_tool_choice else "any"
|
||||
# Emit warning if tool_choice_value property is overridden
|
||||
if inspect.getattr_static(
|
||||
self, "tool_choice_value"
|
||||
@ -1391,10 +1386,7 @@ class ChatModelIntegrationTests(ChatModelTests):
|
||||
"""
|
||||
if not self.has_tool_calling:
|
||||
pytest.skip("Test requires tool calling.")
|
||||
if not self.has_tool_choice:
|
||||
tool_choice_value = None
|
||||
else:
|
||||
tool_choice_value = "any"
|
||||
tool_choice_value = None if not self.has_tool_choice else "any"
|
||||
model_with_tools = model.bind_tools(
|
||||
[magic_function], tool_choice=tool_choice_value
|
||||
)
|
||||
@ -1730,10 +1722,7 @@ class ChatModelIntegrationTests(ChatModelTests):
|
||||
""" # noqa: E501
|
||||
if not self.has_tool_calling:
|
||||
pytest.skip("Test requires tool calling.")
|
||||
if not self.has_tool_choice:
|
||||
tool_choice_value = None
|
||||
else:
|
||||
tool_choice_value = "any"
|
||||
tool_choice_value = None if not self.has_tool_choice else "any"
|
||||
model_with_tools = model.bind_tools(
|
||||
[magic_function_no_args], tool_choice=tool_choice_value
|
||||
)
|
||||
@ -1856,14 +1845,15 @@ class ChatModelIntegrationTests(ChatModelTests):
|
||||
@pytest.mark.xfail(reason=("Not implemented."))
|
||||
def test_structured_few_shot_examples(self, *args: Any) -> None:
|
||||
super().test_structured_few_shot_examples(*args)
|
||||
""" # noqa: E501
|
||||
"""
|
||||
if not self.has_tool_calling:
|
||||
pytest.skip("Test requires tool calling.")
|
||||
model_with_tools = model.bind_tools([my_adder_tool], tool_choice="any")
|
||||
function_result = json.dumps({"result": 3})
|
||||
|
||||
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(
|
||||
"What is 1 + 2",
|
||||
[tool_schema(a=1, b=2)],
|
||||
@ -1871,7 +1861,7 @@ class ChatModelIntegrationTests(ChatModelTests):
|
||||
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)
|
||||
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
|
||||
|
||||
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:
|
||||
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
|
||||
|
||||
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:
|
||||
pytest.skip("Test requires structured output.")
|
||||
|
||||
@ -2163,7 +2153,7 @@ class ChatModelIntegrationTests(ChatModelTests):
|
||||
assert isinstance(result, dict)
|
||||
|
||||
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
|
||||
the JSON mode feature (see Configuration below).
|
||||
@ -2183,7 +2173,7 @@ class ChatModelIntegrationTests(ChatModelTests):
|
||||
.. 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
|
||||
""" # noqa: E501
|
||||
"""
|
||||
if not self.supports_json_mode:
|
||||
pytest.skip("Test requires json mode support.")
|
||||
|
||||
@ -2893,20 +2883,20 @@ class ChatModelIntegrationTests(ChatModelTests):
|
||||
|
||||
def invoke_with_audio_input(self, *, stream: bool = False) -> AIMessage:
|
||||
""":private:"""
|
||||
raise NotImplementedError()
|
||||
raise NotImplementedError
|
||||
|
||||
def invoke_with_audio_output(self, *, stream: bool = False) -> AIMessage:
|
||||
""":private:"""
|
||||
raise NotImplementedError()
|
||||
raise NotImplementedError
|
||||
|
||||
def invoke_with_reasoning_output(self, *, stream: bool = False) -> AIMessage:
|
||||
""":private:"""
|
||||
raise NotImplementedError()
|
||||
raise NotImplementedError
|
||||
|
||||
def invoke_with_cache_read_input(self, *, stream: bool = False) -> AIMessage:
|
||||
""":private:"""
|
||||
raise NotImplementedError()
|
||||
raise NotImplementedError
|
||||
|
||||
def invoke_with_cache_creation_input(self, *, stream: bool = False) -> AIMessage:
|
||||
""":private:"""
|
||||
raise NotImplementedError()
|
||||
raise NotImplementedError
|
||||
|
@ -31,7 +31,7 @@ class DocumentIndexerTestSuite(ABC):
|
||||
"""Get the index."""
|
||||
|
||||
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)
|
||||
assert "ids" not in signature.parameters
|
||||
|
||||
@ -75,7 +75,7 @@ class DocumentIndexerTestSuite(ABC):
|
||||
]
|
||||
response = index.upsert(documents)
|
||||
ids = response["succeeded"]
|
||||
other_id = list(set(ids) - {foo_uuid})[0]
|
||||
other_id = next(iter(set(ids) - {foo_uuid}))
|
||||
assert response["failed"] == []
|
||||
assert foo_uuid in ids
|
||||
# Ordering is not guaranteed, so we use a set.
|
||||
@ -221,7 +221,7 @@ class AsyncDocumentIndexTestSuite(ABC):
|
||||
"""Get the index."""
|
||||
|
||||
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)
|
||||
assert "ids" not in signature.parameters
|
||||
|
||||
@ -265,7 +265,7 @@ class AsyncDocumentIndexTestSuite(ABC):
|
||||
]
|
||||
response = await index.aupsert(documents)
|
||||
ids = response["succeeded"]
|
||||
other_id = list(set(ids) - {foo_uuid})[0]
|
||||
other_id = next(iter(set(ids) - {foo_uuid}))
|
||||
assert response["failed"] == []
|
||||
assert foo_uuid in ids
|
||||
# Ordering is not guaranteed, so we use a set.
|
||||
|
@ -8,43 +8,32 @@ from langchain_tests.base import BaseStandardTests
|
||||
|
||||
|
||||
class RetrieversIntegrationTests(BaseStandardTests):
|
||||
"""
|
||||
Base class for retrievers integration tests.
|
||||
"""
|
||||
"""Base class for retrievers integration tests."""
|
||||
|
||||
@property
|
||||
@abstractmethod
|
||||
def retriever_constructor(self) -> type[BaseRetriever]:
|
||||
"""
|
||||
A BaseRetriever subclass to be tested.
|
||||
"""
|
||||
"""A BaseRetriever subclass to be tested."""
|
||||
...
|
||||
|
||||
@property
|
||||
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 {}
|
||||
|
||||
@property
|
||||
@abstractmethod
|
||||
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
|
||||
def retriever(self) -> BaseRetriever:
|
||||
"""
|
||||
:private:
|
||||
"""
|
||||
""":private:"""
|
||||
return self.retriever_constructor(**self.retriever_constructor_params)
|
||||
|
||||
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.
|
||||
|
||||
.. dropdown:: Troubleshooting
|
||||
@ -77,8 +66,7 @@ class RetrieversIntegrationTests(BaseStandardTests):
|
||||
assert all(isinstance(doc, Document) for doc in result_1)
|
||||
|
||||
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.
|
||||
|
||||
.. dropdown:: Troubleshooting
|
||||
@ -104,8 +92,7 @@ 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
|
||||
"""If invoked with the example params, the retriever should return a list of
|
||||
Documents.
|
||||
|
||||
.. dropdown:: Troubleshooting
|
||||
@ -120,8 +107,7 @@ 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
|
||||
"""If ainvoked with the example params, the retriever should return a list of
|
||||
Documents.
|
||||
|
||||
See :meth:`test_invoke_returns_documents` for more information on
|
||||
|
@ -5,12 +5,11 @@ from langchain_tests.unit_tests.tools import 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:
|
||||
"""
|
||||
"""Test invoke matches output schema.
|
||||
|
||||
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/>`_,
|
||||
@ -41,7 +40,8 @@ class ToolsIntegrationTests(ToolsTests):
|
||||
assert all(isinstance(c, (str, dict)) for c in tool_message.content)
|
||||
|
||||
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.
|
||||
|
||||
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)
|
||||
|
||||
def test_invoke_no_tool_call(self, tool: BaseTool) -> None:
|
||||
"""
|
||||
If invoked without a ToolCall, the tool can return anything
|
||||
but it shouldn't throw an error
|
||||
"""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
|
||||
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)
|
||||
|
||||
async def test_async_invoke_no_tool_call(self, tool: BaseTool) -> None:
|
||||
"""
|
||||
If ainvoked without a ToolCall, the tool can return anything
|
||||
but it shouldn't throw an error
|
||||
"""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`.
|
||||
"""
|
||||
|
@ -105,16 +105,12 @@ class VectorStoreIntegrationTests(BaseStandardTests):
|
||||
|
||||
@property
|
||||
def has_sync(self) -> bool:
|
||||
"""
|
||||
Configurable property to enable or disable sync tests.
|
||||
"""
|
||||
"""Configurable property to enable or disable sync tests."""
|
||||
return True
|
||||
|
||||
@property
|
||||
def has_async(self) -> bool:
|
||||
"""
|
||||
Configurable property to enable or disable async tests.
|
||||
"""
|
||||
"""Configurable property to enable or disable async tests."""
|
||||
return True
|
||||
|
||||
@staticmethod
|
||||
@ -368,7 +364,7 @@ class VectorStoreIntegrationTests(BaseStandardTests):
|
||||
@pytest.mark.xfail(reason=("get_by_ids not implemented."))
|
||||
def test_get_by_ids_missing(self, vectorstore: VectorStore) -> None:
|
||||
super().test_get_by_ids_missing(vectorstore)
|
||||
""" # noqa: E501
|
||||
"""
|
||||
if not self.has_sync:
|
||||
pytest.skip("Sync tests not supported.")
|
||||
|
||||
|
@ -1,6 +1,4 @@
|
||||
"""
|
||||
:autodoc-options: autoproperty
|
||||
"""
|
||||
""":autodoc-options: autoproperty."""
|
||||
|
||||
import inspect
|
||||
import os
|
||||
@ -31,13 +29,13 @@ from langchain_tests.utils.pydantic import PYDANTIC_MAJOR_VERSION
|
||||
|
||||
|
||||
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:
|
||||
"""
|
||||
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):
|
||||
"""Record attributes of a person."""
|
||||
@ -49,8 +47,7 @@ def generate_schema_pydantic_v1_from_2() -> Any:
|
||||
|
||||
|
||||
def generate_schema_pydantic() -> Any:
|
||||
"""
|
||||
Works with either pydantic 1 or 2
|
||||
"""Works with either pydantic 1 or 2.
|
||||
|
||||
:private:
|
||||
"""
|
||||
@ -74,7 +71,7 @@ class ChatModelTests(BaseStandardTests):
|
||||
"""Base class for chat model tests.
|
||||
|
||||
:private:
|
||||
""" # noqa: E501
|
||||
"""
|
||||
|
||||
@property
|
||||
@abstractmethod
|
||||
@ -158,13 +155,15 @@ class ChatModelTests(BaseStandardTests):
|
||||
@property
|
||||
def supports_image_inputs(self) -> bool:
|
||||
"""(bool) whether the chat model supports image inputs, defaults to
|
||||
``False``."""
|
||||
``False``.
|
||||
"""
|
||||
return False
|
||||
|
||||
@property
|
||||
def supports_image_urls(self) -> bool:
|
||||
"""(bool) whether the chat model supports image inputs from URLs, defaults to
|
||||
``False``."""
|
||||
``False``.
|
||||
"""
|
||||
return False
|
||||
|
||||
@property
|
||||
@ -175,19 +174,22 @@ class ChatModelTests(BaseStandardTests):
|
||||
@property
|
||||
def supports_audio_inputs(self) -> bool:
|
||||
"""(bool) whether the chat model supports audio inputs, defaults to
|
||||
``False``."""
|
||||
``False``.
|
||||
"""
|
||||
return False
|
||||
|
||||
@property
|
||||
def supports_video_inputs(self) -> bool:
|
||||
"""(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
|
||||
|
||||
@property
|
||||
def returns_usage_metadata(self) -> bool:
|
||||
"""(bool) whether the chat model returns usage metadata on invoke and streaming
|
||||
responses."""
|
||||
responses.
|
||||
"""
|
||||
return True
|
||||
|
||||
@property
|
||||
@ -198,7 +200,8 @@ class ChatModelTests(BaseStandardTests):
|
||||
@property
|
||||
def supports_image_tool_message(self) -> bool:
|
||||
"""(bool) whether the chat model supports ToolMessages that include image
|
||||
content."""
|
||||
content.
|
||||
"""
|
||||
return False
|
||||
|
||||
@property
|
||||
@ -227,7 +230,8 @@ class ChatModelTests(BaseStandardTests):
|
||||
],
|
||||
]:
|
||||
"""(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": []}
|
||||
|
||||
|
||||
@ -806,7 +810,8 @@ class ChatModelUnitTests(ChatModelTests):
|
||||
@property
|
||||
def init_from_env_params(self) -> tuple[dict, dict, dict]:
|
||||
"""(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 {}, {}, {}
|
||||
|
||||
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
|
||||
|
||||
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:
|
||||
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
|
||||
|
||||
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:
|
||||
return
|
||||
|
||||
|
@ -10,9 +10,7 @@ from langchain_tests.base import BaseStandardTests
|
||||
|
||||
|
||||
class EmbeddingsTests(BaseStandardTests):
|
||||
"""
|
||||
:private:
|
||||
"""
|
||||
""":private:"""
|
||||
|
||||
@property
|
||||
@abstractmethod
|
||||
@ -88,7 +86,7 @@ class EmbeddingsUnitTests(EmbeddingsTests):
|
||||
"my_api_key": "api_key",
|
||||
},
|
||||
)
|
||||
""" # noqa: E501
|
||||
"""
|
||||
|
||||
def test_init(self) -> None:
|
||||
"""Test model initialization.
|
||||
@ -106,7 +104,8 @@ class EmbeddingsUnitTests(EmbeddingsTests):
|
||||
"""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."""
|
||||
attributes to check.
|
||||
"""
|
||||
return {}, {}, {}
|
||||
|
||||
def test_init_from_env(self) -> None:
|
||||
|
@ -11,8 +11,7 @@ from langchain_tests.base import BaseStandardTests
|
||||
|
||||
|
||||
class ToolsTests(BaseStandardTests):
|
||||
"""
|
||||
:private:
|
||||
""":private:
|
||||
Base class for testing tools. This won't show in the documentation, but
|
||||
the docstrings will be inherited by subclasses.
|
||||
"""
|
||||
@ -20,22 +19,17 @@ class ToolsTests(BaseStandardTests):
|
||||
@property
|
||||
@abstractmethod
|
||||
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
|
||||
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 {}
|
||||
|
||||
@property
|
||||
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
|
||||
have {"name", "id", "args"} keys.
|
||||
@ -44,9 +38,7 @@ class ToolsTests(BaseStandardTests):
|
||||
|
||||
@pytest.fixture
|
||||
def tool(self) -> BaseTool:
|
||||
"""
|
||||
:private:
|
||||
"""
|
||||
""":private:"""
|
||||
if isinstance(self.tool_constructor, BaseTool):
|
||||
if self.tool_constructor_params != {}:
|
||||
msg = (
|
||||
@ -59,19 +51,17 @@ class ToolsTests(BaseStandardTests):
|
||||
|
||||
|
||||
class ToolsUnitTests(ToolsTests):
|
||||
"""
|
||||
Base class for tools unit tests.
|
||||
"""
|
||||
"""Base class for tools unit tests."""
|
||||
|
||||
@property
|
||||
def init_from_env_params(self) -> tuple[dict, dict, dict]:
|
||||
"""Return env vars, init args, and expected instance attrs for initializing
|
||||
from env vars."""
|
||||
from env vars.
|
||||
"""
|
||||
return {}, {}, {}
|
||||
|
||||
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
|
||||
keyword args defined in :attr:`tool_constructor_params` are valid.
|
||||
"""
|
||||
@ -94,16 +84,14 @@ class ToolsUnitTests(ToolsTests):
|
||||
assert actual == expected
|
||||
|
||||
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.
|
||||
"""
|
||||
assert tool.name
|
||||
|
||||
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.
|
||||
|
||||
@ -115,8 +103,7 @@ class ToolsUnitTests(ToolsTests):
|
||||
assert tool.get_input_schema()
|
||||
|
||||
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
|
||||
the input schema (`args_schema`) of the tool.
|
||||
|
@ -1,5 +1,4 @@
|
||||
"""
|
||||
Utilities for working with pydantic models.
|
||||
"""Utilities for working with pydantic models.
|
||||
|
||||
:private:
|
||||
"""
|
||||
|
@ -4,4 +4,3 @@ import pytest
|
||||
@pytest.mark.compile
|
||||
def test_placeholder() -> None:
|
||||
"""Used for compiling integration tests without running any real tests."""
|
||||
pass
|
||||
|
@ -41,8 +41,7 @@ class TestParrotMultiplyToolUnit(ToolsUnitTests):
|
||||
|
||||
@property
|
||||
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
|
||||
have {"name", "id", "args"} keys.
|
||||
@ -64,8 +63,7 @@ class TestParrotMultiplyToolIntegration(ToolsIntegrationTests):
|
||||
|
||||
@property
|
||||
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
|
||||
have {"name", "id", "args"} keys.
|
||||
@ -87,8 +85,7 @@ class TestParrotMultiplyArtifactToolIntegration(ToolsIntegrationTests):
|
||||
|
||||
@property
|
||||
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
|
||||
have {"name", "id", "args"} keys.
|
||||
|
@ -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.unit_tests import ChatModelUnitTests
|
||||
|
@ -17,8 +17,7 @@ class TestParrotMultiplyToolUnit(ToolsUnitTests):
|
||||
|
||||
@property
|
||||
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
|
||||
have {"name", "id", "args"} keys.
|
||||
@ -33,8 +32,7 @@ class TestParrotMultiplyToolIntegration(ToolsIntegrationTests):
|
||||
|
||||
@property
|
||||
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
|
||||
have {"name", "id", "args"} keys.
|
||||
|
Loading…
Reference in New Issue
Block a user