Skip to content

Commit

Permalink
add to standard tests and override for Azure legacy tests
Browse files Browse the repository at this point in the history
  • Loading branch information
ccurme committed Jan 8, 2025
1 parent 1e66f69 commit 05e3a93
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 15 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"""Standard LangChain interface tests"""

import os
from typing import Type
from typing import Optional, Type

import pytest
from langchain_core.language_models import BaseChatModel
Expand Down Expand Up @@ -55,6 +55,10 @@ def chat_model_params(self) -> dict:
"azure_endpoint": OPENAI_API_BASE,
}

@property
def structured_output_method(self) -> Optional[str]:
return "function_calling"

@pytest.mark.xfail(reason="Not yet supported.")
def test_usage_metadata_streaming(self, model: BaseChatModel) -> None:
super().test_usage_metadata_streaming(model)
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import base64
import json
from typing import List, Optional, cast
from typing import Any, List, Optional, cast

import httpx
import pytest
Expand Down Expand Up @@ -191,6 +191,20 @@ def tool_choice_value(self) -> Optional[str]:
def has_structured_output(self) -> bool:
return True
.. dropdown:: structured_output_method
Optional string property that can be used to override the default ``method``
parameter for ``with_structured_output``. Useful for testing different
models.
Example:
.. code-block:: python
@property
def structured_output_method(self) -> Optional[str]:
return "function_calling"
.. dropdown:: supports_json_mode
Boolean property indicating whether the chat model supports JSON mode in
Expand Down Expand Up @@ -1126,20 +1140,21 @@ def has_tool_calling(self) -> bool:
if not self.has_tool_calling:
pytest.skip("Test requires tool calling.")

kwargs: dict[str, Any] = {}
if self.structured_output_method:
kwargs["method"] = self.structured_output_method

Joke = _get_joke_class()
# Pydantic class
# Type ignoring since the interface only officially supports pydantic 1
# or pydantic.v1.BaseModel but not pydantic.BaseModel from pydantic 2.
# We'll need to do a pass updating the type signatures.
chat = model.with_structured_output(Joke) # type: ignore[arg-type]
chat = model.with_structured_output(Joke, **kwargs)
result = chat.invoke("Tell me a joke about cats.")
assert isinstance(result, Joke)

for chunk in chat.stream("Tell me a joke about cats."):
assert isinstance(chunk, Joke)

# Schema
chat = model.with_structured_output(Joke.model_json_schema())
chat = model.with_structured_output(Joke.model_json_schema(), **kwargs)
result = chat.invoke("Tell me a joke about cats.")
assert isinstance(result, dict)
assert set(result.keys()) == {"setup", "punchline"}
Expand Down Expand Up @@ -1179,21 +1194,22 @@ def has_tool_calling(self) -> bool:
if not self.has_tool_calling:
pytest.skip("Test requires tool calling.")

kwargs: dict[str, Any] = {}
if self.structured_output_method:
kwargs["method"] = self.structured_output_method

Joke = _get_joke_class()

# Pydantic class
# Type ignoring since the interface only officially supports pydantic 1
# or pydantic.v1.BaseModel but not pydantic.BaseModel from pydantic 2.
# We'll need to do a pass updating the type signatures.
chat = model.with_structured_output(Joke) # type: ignore[arg-type]
chat = model.with_structured_output(Joke, **kwargs)
result = await chat.ainvoke("Tell me a joke about cats.")
assert isinstance(result, Joke)

async for chunk in chat.astream("Tell me a joke about cats."):
assert isinstance(chunk, Joke)

# Schema
chat = model.with_structured_output(Joke.model_json_schema())
chat = model.with_structured_output(Joke.model_json_schema(), **kwargs)
result = await chat.ainvoke("Tell me a joke about cats.")
assert isinstance(result, dict)
assert set(result.keys()) == {"setup", "punchline"}
Expand Down Expand Up @@ -1237,22 +1253,26 @@ def has_tool_calling(self) -> bool:
if not self.has_tool_calling:
pytest.skip("Test requires tool calling.")

kwargs: dict[str, Any] = {}
if self.structured_output_method:
kwargs["method"] = self.structured_output_method

class Joke(BaseModelV1): # Uses langchain_core.pydantic_v1.BaseModel
"""Joke to tell user."""

setup: str = FieldV1(description="question to set up a joke")
punchline: str = FieldV1(description="answer to resolve the joke")

# Pydantic class
chat = model.with_structured_output(Joke)
chat = model.with_structured_output(Joke, **kwargs)
result = chat.invoke("Tell me a joke about cats.")
assert isinstance(result, Joke)

for chunk in chat.stream("Tell me a joke about cats."):
assert isinstance(chunk, Joke)

# Schema
chat = model.with_structured_output(Joke.schema())
chat = model.with_structured_output(Joke.schema(), **kwargs)
result = chat.invoke("Tell me a joke about cats.")
assert isinstance(result, dict)
assert set(result.keys()) == {"setup", "punchline"}
Expand Down Expand Up @@ -1293,6 +1313,10 @@ def has_tool_calling(self) -> bool:
if not self.has_tool_calling:
pytest.skip("Test requires tool calling.")

kwargs = {}
if self.structured_output_method:
kwargs["method"] = self.structured_output_method

class Joke(BaseModel):
"""Joke to tell user."""

Expand All @@ -1301,7 +1325,7 @@ class Joke(BaseModel):
default=None, description="answer to resolve the joke"
)

chat = model.with_structured_output(Joke) # type: ignore[arg-type]
chat = model.with_structured_output(Joke, **kwargs) # type: ignore[arg-type]
setup_result = chat.invoke(
"Give me the setup to a joke about cats, no punchline."
)
Expand Down
19 changes: 19 additions & 0 deletions libs/standard-tests/langchain_tests/unit_tests/chat_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,11 @@ def has_structured_output(self) -> bool:
is not BaseChatModel.with_structured_output
)

@property
def structured_output_method(self) -> Optional[str]:
"""If specified, override default for with_structured_output."""
return None

@property
def supports_json_mode(self) -> bool:
"""(bool) whether the chat model supports JSON mode."""
Expand Down Expand Up @@ -299,6 +304,20 @@ def tool_choice_value(self) -> Optional[str]:
def has_structured_output(self) -> bool:
return True
.. dropdown:: structured_output_method
Optional string property that can be used to override the default ``method``
parameter for ``with_structured_output``. Useful for testing different
models.
Example:
.. code-block:: python
@property
def structured_output_method(self) -> Optional[str]:
return "function_calling"
.. dropdown:: supports_json_mode
Boolean property indicating whether the chat model supports JSON mode in
Expand Down

0 comments on commit 05e3a93

Please sign in to comment.