mirror of
https://github.com/PrefectHQ/fastmcp.git
synced 2026-08-09 15:19:10 +02:00
222 lines
6 KiB
Python
222 lines
6 KiB
Python
import functools
|
|
from collections.abc import Callable
|
|
from typing import Any
|
|
|
|
import pytest
|
|
|
|
from fastmcp.utilities.decorators import DecoratedFunction
|
|
|
|
DECORATOR_CALLED = []
|
|
|
|
|
|
def decorator(fn: Callable[..., Any]) -> DecoratedFunction[..., Any]:
|
|
@functools.wraps(fn)
|
|
def wrapper(*args: Any, **kwargs: Any) -> Any:
|
|
DECORATOR_CALLED.append((args, kwargs))
|
|
return fn(*args, **kwargs)
|
|
|
|
return DecoratedFunction(wrapper)
|
|
|
|
|
|
@pytest.fixture(autouse=True)
|
|
def reset_decorator_called():
|
|
DECORATOR_CALLED.clear()
|
|
yield
|
|
DECORATOR_CALLED.clear()
|
|
|
|
|
|
@decorator
|
|
def add(a: int, b: int) -> int:
|
|
return a + b
|
|
|
|
|
|
@decorator
|
|
async def add_async(a: int, b: int) -> int:
|
|
return a + b
|
|
|
|
|
|
class DecoratedClass:
|
|
def __init__(self, x: int):
|
|
self.x = x
|
|
|
|
@decorator
|
|
def add(self, a: int, b: int) -> int:
|
|
return a + b + self.x
|
|
|
|
@decorator
|
|
async def add_async(self, a: int, b: int) -> int:
|
|
return a + b + self.x
|
|
|
|
@classmethod
|
|
@decorator
|
|
def add_classmethod(cls, a: int, b: int) -> int:
|
|
return a + b
|
|
|
|
@staticmethod
|
|
@decorator
|
|
def add_staticmethod(a: int, b: int) -> int:
|
|
return a + b
|
|
|
|
@classmethod
|
|
@decorator
|
|
async def add_classmethod_async(cls, a: int, b: int) -> int:
|
|
return a + b
|
|
|
|
@staticmethod
|
|
@decorator
|
|
async def add_staticmethod_async(a: int, b: int) -> int:
|
|
return a + b
|
|
|
|
@decorator
|
|
@classmethod
|
|
def add_classmethod_reverse_decorator_order(cls, a: int, b: int) -> int:
|
|
return a + b
|
|
|
|
@decorator
|
|
@staticmethod
|
|
def add_staticmethod_reverse_decorator_order(a: int, b: int) -> int:
|
|
return a + b
|
|
|
|
@decorator
|
|
@classmethod
|
|
async def add_classmethod_async_reverse_decorator_order(cls, a: int, b: int) -> int:
|
|
return a + b
|
|
|
|
@decorator
|
|
@staticmethod
|
|
async def add_staticmethod_async_reverse_decorator_order(a: int, b: int) -> int:
|
|
return a + b
|
|
|
|
|
|
def test_add():
|
|
assert add(1, 2) == 3
|
|
assert DECORATOR_CALLED == [((1, 2), {})]
|
|
DECORATOR_CALLED.clear()
|
|
|
|
# Test with keyword arguments
|
|
assert add(a=3, b=4) == 7
|
|
assert DECORATOR_CALLED == [((), {"a": 3, "b": 4})]
|
|
|
|
|
|
async def test_add_async():
|
|
assert await add_async(1, 2) == 3
|
|
assert DECORATOR_CALLED == [((1, 2), {})]
|
|
DECORATOR_CALLED.clear()
|
|
|
|
# Test with keyword arguments
|
|
assert await add_async(a=3, b=4) == 7
|
|
assert DECORATOR_CALLED == [((), {"a": 3, "b": 4})]
|
|
|
|
|
|
def test_instance_method():
|
|
obj = DecoratedClass(10)
|
|
assert obj.add(2, 3) == 15
|
|
assert DECORATOR_CALLED == [((obj, 2, 3), {})]
|
|
DECORATOR_CALLED.clear()
|
|
|
|
# Test with keyword arguments
|
|
assert obj.add(a=4, b=5) == 19
|
|
assert DECORATOR_CALLED == [((obj,), {"a": 4, "b": 5})]
|
|
|
|
|
|
async def test_instance_method_async():
|
|
obj = DecoratedClass(10)
|
|
assert await obj.add_async(2, 3) == 15
|
|
assert DECORATOR_CALLED == [((obj, 2, 3), {})]
|
|
DECORATOR_CALLED.clear()
|
|
|
|
# Test with keyword arguments
|
|
assert await obj.add_async(a=4, b=5) == 19
|
|
assert DECORATOR_CALLED == [((obj,), {"a": 4, "b": 5})]
|
|
|
|
|
|
def test_classmethod():
|
|
assert DecoratedClass.add_classmethod(1, 2) == 3
|
|
assert DECORATOR_CALLED == [((DecoratedClass, 1, 2), {})]
|
|
DECORATOR_CALLED.clear()
|
|
|
|
# Test with keyword arguments
|
|
assert DecoratedClass.add_classmethod(a=3, b=4) == 7
|
|
assert DECORATOR_CALLED == [((DecoratedClass,), {"a": 3, "b": 4})]
|
|
DECORATOR_CALLED.clear()
|
|
|
|
# Test via instance
|
|
obj = DecoratedClass(10)
|
|
assert obj.add_classmethod(5, 6) == 11
|
|
assert DECORATOR_CALLED == [((DecoratedClass, 5, 6), {})]
|
|
|
|
|
|
async def test_classmethod_async():
|
|
assert await DecoratedClass.add_classmethod_async(1, 2) == 3
|
|
assert DECORATOR_CALLED == [((DecoratedClass, 1, 2), {})]
|
|
DECORATOR_CALLED.clear()
|
|
|
|
# Test with keyword arguments
|
|
assert await DecoratedClass.add_classmethod_async(a=3, b=4) == 7
|
|
assert DECORATOR_CALLED == [((DecoratedClass,), {"a": 3, "b": 4})]
|
|
DECORATOR_CALLED.clear()
|
|
|
|
# Test via instance
|
|
obj = DecoratedClass(10)
|
|
assert await obj.add_classmethod_async(5, 6) == 11
|
|
assert DECORATOR_CALLED == [((DecoratedClass, 5, 6), {})]
|
|
|
|
|
|
def test_classmethod_wrong_order():
|
|
with pytest.raises(
|
|
TypeError,
|
|
match="To apply this decorator to a classmethod, apply the decorator first, then @classmethod on top.",
|
|
):
|
|
DecoratedClass.add_classmethod_reverse_decorator_order(1, 2)
|
|
|
|
|
|
async def test_classmethod_async_wrong_order():
|
|
with pytest.raises(
|
|
TypeError,
|
|
match="To apply this decorator to a classmethod, apply the decorator first, then @classmethod on top.",
|
|
):
|
|
await DecoratedClass.add_classmethod_async_reverse_decorator_order(1, 2)
|
|
|
|
|
|
def test_staticmethod():
|
|
assert DecoratedClass.add_staticmethod(1, 2) == 3
|
|
assert DECORATOR_CALLED == [((1, 2), {})]
|
|
DECORATOR_CALLED.clear()
|
|
|
|
# Test with keyword arguments
|
|
assert DecoratedClass.add_staticmethod(a=3, b=4) == 7
|
|
assert DECORATOR_CALLED == [((), {"a": 3, "b": 4})]
|
|
DECORATOR_CALLED.clear()
|
|
|
|
# Test via instance
|
|
obj = DecoratedClass(10)
|
|
assert obj.add_staticmethod(5, 6) == 11
|
|
assert DECORATOR_CALLED == [((5, 6), {})]
|
|
|
|
|
|
async def test_staticmethod_async():
|
|
assert await DecoratedClass.add_staticmethod_async(1, 2) == 3
|
|
assert DECORATOR_CALLED == [((1, 2), {})]
|
|
DECORATOR_CALLED.clear()
|
|
|
|
# Test with keyword arguments
|
|
assert await DecoratedClass.add_staticmethod_async(a=3, b=4) == 7
|
|
assert DECORATOR_CALLED == [((), {"a": 3, "b": 4})]
|
|
DECORATOR_CALLED.clear()
|
|
|
|
# Test via instance
|
|
obj = DecoratedClass(10)
|
|
assert await obj.add_staticmethod_async(5, 6) == 11
|
|
assert DECORATOR_CALLED == [((5, 6), {})]
|
|
|
|
|
|
def test_staticmethod_wrong_order():
|
|
assert DecoratedClass.add_staticmethod_reverse_decorator_order(1, 2) == 3
|
|
assert DECORATOR_CALLED == [((1, 2), {})]
|
|
|
|
|
|
async def test_staticmethod_async_wrong_order():
|
|
assert (
|
|
await DecoratedClass.add_staticmethod_async_reverse_decorator_order(1, 2) == 3
|
|
)
|
|
assert DECORATOR_CALLED == [((1, 2), {})]
|