Coverage for src/monadc/decorators.py: 100%

1"""

2 Decorators for automatic monad wrapping of function returns.

3"""

4 from functools import wraps

5 from typing import Callable, TypeVar, Any, TYPE_CHECKING

6 from .option import Option

7

8 if TYPE_CHECKING:

9 from .try_ import Try

10 from .result import Result

11

12 T = TypeVar('T')

13

14

15 def option(func: Callable[..., T]) -> Callable[..., 'Option[T]']:

16 """

17 Decorator that wraps function return values in Option.

18

19 - Returns Some(result) for non-None values

20 - Returns Nil() for None values

21 - Exceptions propagate normally (not caught)

22

23 Example:

24 @option

25 def find_user(user_id: str) -> User:

26 return database.get(user_id) # Returns Option[User]

27 """

28 @wraps(func)

29 def wrapper(*args: Any, **kwargs: Any) -> 'Option[T]':

30 result = func(*args, **kwargs)

31 return Option(result)

32

33 return wrapper

34

35

36 def try_decorator(func: Callable[..., T]) -> Callable[..., 'Try[T]']:

37 """

38 Decorator that wraps function return values in Try monad.

39

40 - Returns Success(result) for successful execution

41 - Returns Failure(exception) if function raises any exception

42

43 Example:

44 @try_decorator

45 def parse_int(s: str) -> int:

46 return int(s) # Returns Success(42) or Failure(ValueError)

47 """

48 @wraps(func)

49 def wrapper(*args: Any, **kwargs: Any) -> 'Try[T]':

50 try:

51 result = func(*args, **kwargs)

52 from .try_ import Success

53 return Success(result)

54 except Exception as e:

55 from .try_ import Failure

56 return Failure(e)

57

58 return wrapper

59

60

61# Alias for more natural usage

62 try_ = try_decorator

63

64

65 def result(func: Callable[..., T]) -> Callable[..., 'Result[T, Exception]']:

66 """

67 Decorator that wraps function return values in Result monad.

68

69 - Returns Ok(result) for successful execution

70 - Returns Err(exception) if function raises any exception

71

72 Example:

73 @result

74 def divide(a: float, b: float) -> float:

75 return a / b # Returns Ok(2.0) or Err(ZeroDivisionError)

76 """

77 @wraps(func)

78 def wrapper(*args: Any, **kwargs: Any) -> 'Result[T, Exception]':

79 try:

80 result = func(*args, **kwargs)

81 from .result import Ok

82 return Ok(result)

83 except Exception as e:

84 from .result import Err

85 return Err(e)

86

87 return wrapper