Skip to content

Commit 0114f0a

Browse files
committed
PR Clean-up
1 parent 1a72bfa commit 0114f0a

File tree

1 file changed

+137
-75
lines changed

1 file changed

+137
-75
lines changed

tests/tools/test_tool_transform.py

Lines changed: 137 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
import pytest
66
from dirty_equals import IsList
7+
from inline_snapshot import snapshot
78
from mcp.types import TextContent
89
from pydantic import BaseModel, Field, TypeAdapter
910
from typing_extensions import TypedDict
@@ -1055,38 +1056,6 @@ def add(x: int, y: int = 10) -> int:
10551056
await client.call_tool("new_add", {"x": 1, "y": 2})
10561057

10571058

1058-
def test_arg_transform_examples_in_schema(add_tool):
1059-
# Simple example
1060-
new_tool = Tool.from_tool(
1061-
add_tool,
1062-
transform_args={
1063-
"old_x": ArgTransform(examples=[1, 2, 3]),
1064-
},
1065-
)
1066-
prop = get_property(new_tool, "old_x")
1067-
assert prop["examples"] == [1, 2, 3]
1068-
1069-
# Nested example (e.g., for array type)
1070-
new_tool2 = Tool.from_tool(
1071-
add_tool,
1072-
transform_args={
1073-
"old_x": ArgTransform(examples=[["a", "b"], ["c", "d"]]),
1074-
},
1075-
)
1076-
prop2 = get_property(new_tool2, "old_x")
1077-
assert prop2["examples"] == [["a", "b"], ["c", "d"]]
1078-
1079-
# If not set, should not be present
1080-
new_tool3 = Tool.from_tool(
1081-
add_tool,
1082-
transform_args={
1083-
"old_x": ArgTransform(),
1084-
},
1085-
)
1086-
prop3 = get_property(new_tool3, "old_x")
1087-
assert "examples" not in prop3
1088-
1089-
10901059
class TestTransformToolOutputSchema:
10911060
"""Test output schema handling in transformed tools."""
10921061

@@ -1504,10 +1473,40 @@ def test_tool_transform_config_removes_meta(sample_tool):
15041473
assert transformed.meta is None
15051474

15061475

1507-
# Tests for $defs and _find_referenced_defs functionality
1508-
class TestDefsAndReferences:
1476+
class TestInputSchema:
15091477
"""Test schema definition handling and reference finding."""
15101478

1479+
def test_arg_transform_examples_in_schema(self, add_tool: Tool):
1480+
# Simple example
1481+
new_tool = Tool.from_tool(
1482+
add_tool,
1483+
transform_args={
1484+
"old_x": ArgTransform(examples=[1, 2, 3]),
1485+
},
1486+
)
1487+
prop = get_property(new_tool, "old_x")
1488+
assert prop["examples"] == [1, 2, 3]
1489+
1490+
# Nested example (e.g., for array type)
1491+
new_tool2 = Tool.from_tool(
1492+
add_tool,
1493+
transform_args={
1494+
"old_x": ArgTransform(examples=[["a", "b"], ["c", "d"]]),
1495+
},
1496+
)
1497+
prop2 = get_property(new_tool2, "old_x")
1498+
assert prop2["examples"] == [["a", "b"], ["c", "d"]]
1499+
1500+
# If not set, should not be present
1501+
new_tool3 = Tool.from_tool(
1502+
add_tool,
1503+
transform_args={
1504+
"old_x": ArgTransform(),
1505+
},
1506+
)
1507+
prop3 = get_property(new_tool3, "old_x")
1508+
assert "examples" not in prop3
1509+
15111510
def test_merge_schema_with_defs_precedence(self):
15121511
"""Test _merge_schema_with_precedence merges $defs correctly."""
15131512
base_schema = {
@@ -1528,22 +1527,27 @@ def test_merge_schema_with_defs_precedence(self):
15281527
},
15291528
}
15301529

1531-
result = TransformedTool._merge_schema_with_precedence(
1530+
transformed_tool_schema = TransformedTool._merge_schema_with_precedence(
15321531
base_schema, override_schema
15331532
)
15341533

1535-
# Should have both field1 and field2
1536-
assert "field1" in result["properties"]
1537-
assert "field2" in result["properties"]
1538-
1539-
# Should only include referenced defs
1540-
defs = result.get("$defs", {})
1541-
assert "BaseType" in defs # Referenced by field1
1542-
assert "OverrideType" in defs # Referenced by field2
1543-
1544-
# SharedType should use override version, but only if referenced
1545-
# Since it's not referenced by either field, it shouldn't be included
1546-
assert "SharedType" not in defs
1534+
# SharedType should no longer be present on the schema
1535+
assert "SharedType" not in transformed_tool_schema["$defs"]
1536+
1537+
assert transformed_tool_schema == snapshot(
1538+
{
1539+
"type": "object",
1540+
"properties": {
1541+
"field1": {"$ref": "#/$defs/BaseType"},
1542+
"field2": {"$ref": "#/$defs/OverrideType"},
1543+
},
1544+
"required": [],
1545+
"$defs": {
1546+
"BaseType": {"type": "string", "description": "base"},
1547+
"OverrideType": {"type": "boolean"},
1548+
},
1549+
}
1550+
)
15471551

15481552
def test_transform_tool_with_complex_defs_pruning(self):
15491553
"""Test that tool transformation properly prunes unused $defs."""
@@ -1561,20 +1565,29 @@ def complex_tool(
15611565
return used_param.value
15621566

15631567
# Transform to hide unused_param
1564-
transformed = Tool.from_tool(
1568+
transformed_tool: TransformedTool = Tool.from_tool(
15651569
complex_tool, transform_args={"unused_param": ArgTransform(hide=True)}
15661570
)
15671571

1568-
# Only UsedType should be in $defs, not UnusedType
1569-
defs = transformed.parameters.get("$defs", {})
1570-
type_names = set(defs.keys())
1571-
1572-
# Should contain UsedType but not UnusedType
1573-
used_type_found = any("UsedType" in name for name in type_names)
1574-
unused_type_found = any("UnusedType" in name for name in type_names)
1575-
1576-
assert used_type_found, f"UsedType not found in defs: {type_names}"
1577-
assert not unused_type_found, f"UnusedType should not be in defs: {type_names}"
1572+
assert "UnusedType" not in transformed_tool.parameters["$defs"]
1573+
1574+
assert transformed_tool.parameters == snapshot(
1575+
{
1576+
"type": "object",
1577+
"properties": {
1578+
"used_param": {"$ref": "#/$defs/UsedType", "title": "Used Param"}
1579+
},
1580+
"required": ["used_param"],
1581+
"$defs": {
1582+
"UsedType": {
1583+
"properties": {"value": {"title": "Value", "type": "string"}},
1584+
"required": ["value"],
1585+
"title": "UsedType",
1586+
"type": "object",
1587+
}
1588+
},
1589+
}
1590+
)
15781591

15791592
def test_transform_with_custom_function_preserves_needed_defs(self):
15801593
"""Test that custom transform functions preserve necessary $defs."""
@@ -1599,12 +1612,26 @@ async def transform_function(renamed_input: InputType):
15991612
transform_args={"input_data": ArgTransform(name="renamed_input")},
16001613
)
16011614

1602-
# Both InputType and OutputType should be preserved in defs
1603-
defs = transformed.parameters.get("$defs", {})
1604-
type_names = set(defs.keys())
1605-
1606-
input_type_found = any("InputType" in name for name in type_names)
1607-
assert input_type_found, f"InputType not found in defs: {type_names}"
1615+
assert transformed.parameters == snapshot(
1616+
{
1617+
"type": "object",
1618+
"properties": {
1619+
"renamed_input": {
1620+
"$ref": "#/$defs/InputType",
1621+
"title": "Input Data",
1622+
}
1623+
},
1624+
"required": ["renamed_input"],
1625+
"$defs": {
1626+
"InputType": {
1627+
"properties": {"data": {"title": "Data", "type": "string"}},
1628+
"required": ["data"],
1629+
"title": "InputType",
1630+
"type": "object",
1631+
}
1632+
},
1633+
}
1634+
)
16081635

16091636
def test_chained_transforms_preserve_correct_defs(self):
16101637
"""Test that chained transformations preserve correct $defs."""
@@ -1628,20 +1655,55 @@ def base_tool(param_a: TypeA, param_b: TypeB, param_c: TypeC) -> str:
16281655
transform_args={"param_c": ArgTransform(hide=True, default=TypeC(c=True))},
16291656
)
16301657

1658+
assert transform1.parameters == snapshot(
1659+
{
1660+
"type": "object",
1661+
"properties": {
1662+
"param_a": {"$ref": "#/$defs/TypeA", "title": "Param A"},
1663+
"param_b": {"$ref": "#/$defs/TypeB", "title": "Param B"},
1664+
},
1665+
"required": IsList("param_b", "param_a", check_order=False),
1666+
"$defs": {
1667+
"TypeA": {
1668+
"properties": {"a": {"title": "A", "type": "string"}},
1669+
"required": ["a"],
1670+
"title": "TypeA",
1671+
"type": "object",
1672+
},
1673+
"TypeB": {
1674+
"properties": {"b": {"title": "B", "type": "integer"}},
1675+
"required": ["b"],
1676+
"title": "TypeB",
1677+
"type": "object",
1678+
},
1679+
},
1680+
}
1681+
)
1682+
1683+
assert "TypeA" in transform1.parameters["$defs"]
1684+
16311685
# Second transform: hide param_b
16321686
transform2 = Tool.from_tool(
16331687
transform1,
16341688
transform_args={"param_b": ArgTransform(hide=True, default=TypeB(b=42))},
16351689
)
16361690

1637-
# Final schema should only have TypeA in $defs
1638-
defs = transform2.parameters.get("$defs", {})
1639-
type_names = set(defs.keys())
1640-
1641-
type_a_found = any("TypeA" in name for name in type_names)
1642-
type_b_found = any("TypeB" in name for name in type_names)
1643-
type_c_found = any("TypeC" in name for name in type_names)
1644-
1645-
assert type_a_found, f"TypeA should be in defs: {type_names}"
1646-
assert not type_b_found, f"TypeB should not be in defs: {type_names}"
1647-
assert not type_c_found, f"TypeC should not be in defs: {type_names}"
1691+
assert "TypeB" not in transform2.parameters["$defs"]
1692+
1693+
assert transform2.parameters == snapshot(
1694+
{
1695+
"type": "object",
1696+
"properties": {
1697+
"param_a": {"$ref": "#/$defs/TypeA", "title": "Param A"}
1698+
},
1699+
"required": ["param_a"],
1700+
"$defs": {
1701+
"TypeA": {
1702+
"properties": {"a": {"title": "A", "type": "string"}},
1703+
"required": ["a"],
1704+
"title": "TypeA",
1705+
"type": "object",
1706+
}
1707+
},
1708+
}
1709+
)

0 commit comments

Comments
 (0)