|
1 | | -from typing import Literal, Optional |
| 1 | +from typing import List, Literal, Optional |
2 | 2 |
|
3 | 3 | import pytest |
4 | 4 | from pydantic import BaseModel, Field |
@@ -157,6 +157,7 @@ def test_convert_pydantic_to_tool_spec_multiple_same_type(): |
157 | 157 | "user2": { |
158 | 158 | "type": ["object", "null"], |
159 | 159 | "description": "The second user", |
| 160 | + "title": "UserWithPlanet", |
160 | 161 | "properties": { |
161 | 162 | "name": {"description": "The name of the user", "title": "Name", "type": "string"}, |
162 | 163 | "age": { |
@@ -208,6 +209,85 @@ class NodeWithCircularRef(BaseModel): |
208 | 209 | convert_pydantic_to_tool_spec(NodeWithCircularRef) |
209 | 210 |
|
210 | 211 |
|
| 212 | +def test_convert_pydantic_with_circular_required_dependency(): |
| 213 | + """Test that the tool handles circular dependencies gracefully.""" |
| 214 | + |
| 215 | + class NodeWithCircularRef(BaseModel): |
| 216 | + """A node with a circular reference to itself.""" |
| 217 | + |
| 218 | + name: str = Field(description="The name of the node") |
| 219 | + parent: "NodeWithCircularRef" |
| 220 | + |
| 221 | + with pytest.raises(ValueError, match="Circular reference detected and not supported"): |
| 222 | + convert_pydantic_to_tool_spec(NodeWithCircularRef) |
| 223 | + |
| 224 | + |
| 225 | +def test_convert_pydantic_with_circular_optional_dependency(): |
| 226 | + """Test that the tool handles circular dependencies gracefully.""" |
| 227 | + |
| 228 | + class NodeWithCircularRef(BaseModel): |
| 229 | + """A node with a circular reference to itself.""" |
| 230 | + |
| 231 | + name: str = Field(description="The name of the node") |
| 232 | + parent: Optional["NodeWithCircularRef"] = None |
| 233 | + |
| 234 | + with pytest.raises(ValueError, match="Circular reference detected and not supported"): |
| 235 | + convert_pydantic_to_tool_spec(NodeWithCircularRef) |
| 236 | + |
| 237 | + |
| 238 | +def test_convert_pydantic_with_circular_optional_dependenc_not_using_optional_typing(): |
| 239 | + """Test that the tool handles circular dependencies gracefully.""" |
| 240 | + |
| 241 | + class NodeWithCircularRef(BaseModel): |
| 242 | + """A node with a circular reference to itself.""" |
| 243 | + |
| 244 | + name: str = Field(description="The name of the node") |
| 245 | + parent: "NodeWithCircularRef" = None |
| 246 | + |
| 247 | + with pytest.raises(ValueError, match="Circular reference detected and not supported"): |
| 248 | + convert_pydantic_to_tool_spec(NodeWithCircularRef) |
| 249 | + |
| 250 | + |
| 251 | +def test_conversion_works_with_fields_that_are_not_marked_as_optional_but_have_a_default_value_which_makes_them_optional(): # noqa E501 |
| 252 | + class Family(BaseModel): |
| 253 | + ages: List[str] = Field(default_factory=list) |
| 254 | + names: List[str] = Field(default_factory=list) |
| 255 | + |
| 256 | + converted_output = convert_pydantic_to_tool_spec(Family) |
| 257 | + expected_output = { |
| 258 | + "name": "Family", |
| 259 | + "description": "Family structured output tool", |
| 260 | + "inputSchema": { |
| 261 | + "json": { |
| 262 | + "type": "object", |
| 263 | + "properties": { |
| 264 | + "ages": { |
| 265 | + "items": {"type": "string"}, |
| 266 | + "title": "Ages", |
| 267 | + "type": ["array", "null"], |
| 268 | + }, |
| 269 | + "names": { |
| 270 | + "items": {"type": "string"}, |
| 271 | + "title": "Names", |
| 272 | + "type": ["array", "null"], |
| 273 | + }, |
| 274 | + }, |
| 275 | + "title": "Family", |
| 276 | + } |
| 277 | + }, |
| 278 | + } |
| 279 | + assert converted_output == expected_output |
| 280 | + |
| 281 | + |
| 282 | +def test_marks_fields_as_optional_for_model_w_fields_that_are_not_marked_as_optional_but_have_a_default_value_which_makes_them_optional(): # noqa E501 |
| 283 | + class Family(BaseModel): |
| 284 | + ages: List[str] = Field(default_factory=list) |
| 285 | + names: List[str] = Field(default_factory=list) |
| 286 | + |
| 287 | + converted_output = convert_pydantic_to_tool_spec(Family) |
| 288 | + assert "null" in converted_output["inputSchema"]["json"]["properties"]["ages"]["type"] |
| 289 | + |
| 290 | + |
211 | 291 | def test_convert_pydantic_with_custom_description(): |
212 | 292 | """Test that custom descriptions override model docstrings.""" |
213 | 293 |
|
|
0 commit comments