decorator.py 1.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950
  1. """Decorator utilities."""
  2. import functools
  3. from typing import Callable, ParamSpec, TypeVar
  4. T = TypeVar("T")
  5. def once(f: Callable[[], T]) -> Callable[[], T]:
  6. """A decorator that calls the function once and caches the result.
  7. Args:
  8. f: The function to call.
  9. Returns:
  10. A function that calls the function once and caches the result.
  11. """
  12. unset = object()
  13. value: object | T = unset
  14. def wrapper() -> T:
  15. nonlocal value
  16. value = f() if value is unset else value
  17. return value # pyright: ignore[reportReturnType]
  18. return wrapper
  19. P = ParamSpec("P")
  20. def debug(f: Callable[P, T]) -> Callable[P, T]:
  21. """A decorator that prints the function name, arguments, and result.
  22. Args:
  23. f: The function to call.
  24. Returns:
  25. A function that prints the function name, arguments, and result.
  26. """
  27. @functools.wraps(f)
  28. def wrapper(*args: P.args, **kwargs: P.kwargs) -> T:
  29. result = f(*args, **kwargs)
  30. print( # noqa: T201
  31. f"Calling {f.__name__} with args: {args} and kwargs: {kwargs}, result: {result}"
  32. )
  33. return result
  34. return wrapper