Spaces:
Running
Running
William Easton commited on
Fix method-bound tools (#1360)
Browse files
src/fastmcp/utilities/types.py
CHANGED
|
@@ -101,7 +101,12 @@ def get_cached_typeadapter(cls: T) -> TypeAdapter[T]:
|
|
| 101 |
new_func.__module__ = cls.__module__
|
| 102 |
new_func.__qualname__ = getattr(cls, "__qualname__", cls.__name__)
|
| 103 |
new_func.__annotations__ = processed_hints
|
| 104 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 105 |
|
| 106 |
return TypeAdapter(cls)
|
| 107 |
|
|
|
|
| 101 |
new_func.__module__ = cls.__module__
|
| 102 |
new_func.__qualname__ = getattr(cls, "__qualname__", cls.__name__)
|
| 103 |
new_func.__annotations__ = processed_hints
|
| 104 |
+
|
| 105 |
+
if inspect.ismethod(cls):
|
| 106 |
+
new_method = types.MethodType(new_func, cls.__self__)
|
| 107 |
+
return TypeAdapter(new_method)
|
| 108 |
+
else:
|
| 109 |
+
return TypeAdapter(new_func)
|
| 110 |
|
| 111 |
return TypeAdapter(cls)
|
| 112 |
|
tests/utilities/test_typeadapter.py
CHANGED
|
@@ -37,6 +37,19 @@ class SomeComplexModel(BaseModel):
|
|
| 37 |
y: dict[int, str]
|
| 38 |
|
| 39 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 40 |
def complex_arguments_fn(
|
| 41 |
an_int: int,
|
| 42 |
must_be_none: None,
|
|
@@ -242,3 +255,19 @@ def test_str_vs_int():
|
|
| 242 |
type_adapter = get_cached_typeadapter(func_with_str_and_int)
|
| 243 |
result = type_adapter.validate_python({"a": "123", "b": 123})
|
| 244 |
assert result == "123"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 37 |
y: dict[int, str]
|
| 38 |
|
| 39 |
|
| 40 |
+
class ClassWithMethods:
|
| 41 |
+
def do_something(self, x: int) -> int:
|
| 42 |
+
return x
|
| 43 |
+
|
| 44 |
+
def do_something_annotated(
|
| 45 |
+
self, x: Annotated[int, Field(description="A description")]
|
| 46 |
+
) -> int:
|
| 47 |
+
return x
|
| 48 |
+
|
| 49 |
+
def do_something_return_none(self) -> None:
|
| 50 |
+
return None
|
| 51 |
+
|
| 52 |
+
|
| 53 |
def complex_arguments_fn(
|
| 54 |
an_int: int,
|
| 55 |
must_be_none: None,
|
|
|
|
| 255 |
type_adapter = get_cached_typeadapter(func_with_str_and_int)
|
| 256 |
result = type_adapter.validate_python({"a": "123", "b": 123})
|
| 257 |
assert result == "123"
|
| 258 |
+
|
| 259 |
+
|
| 260 |
+
def test_class_with_methods():
|
| 261 |
+
"""Test that class methods are not included in the schema"""
|
| 262 |
+
class_with_methods = ClassWithMethods()
|
| 263 |
+
type_adapter = get_cached_typeadapter(class_with_methods.do_something)
|
| 264 |
+
schema = type_adapter.json_schema()
|
| 265 |
+
assert "self" not in schema["properties"]
|
| 266 |
+
|
| 267 |
+
type_adapter = get_cached_typeadapter(class_with_methods.do_something_annotated)
|
| 268 |
+
schema = type_adapter.json_schema()
|
| 269 |
+
assert "self" not in schema["properties"]
|
| 270 |
+
|
| 271 |
+
type_adapter = get_cached_typeadapter(class_with_methods.do_something_return_none)
|
| 272 |
+
schema = type_adapter.json_schema()
|
| 273 |
+
assert "self" not in schema["properties"]
|