Coverage for src/monadc/decorators.py: 100%
33 statements
« prev ^ index » next coverage.py v7.10.2, created at 2025-08-19 20:24 -0700
« prev ^ index » next coverage.py v7.10.2, created at 2025-08-19 20:24 -0700
1"""
2Decorators for automatic monad wrapping of function returns.
3"""
4from functools import wraps
5from typing import Callable, TypeVar, Any, TYPE_CHECKING
6from .option import Option
8if TYPE_CHECKING:
9 from .try_ import Try
10 from .result import Result
12T = TypeVar('T')
15def option(func: Callable[..., T]) -> Callable[..., 'Option[T]']:
16 """
17 Decorator that wraps function return values in Option.
19 - Returns Some(result) for non-None values
20 - Returns Nil() for None values
21 - Exceptions propagate normally (not caught)
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)
33 return wrapper
36def try_decorator(func: Callable[..., T]) -> Callable[..., 'Try[T]']:
37 """
38 Decorator that wraps function return values in Try monad.
40 - Returns Success(result) for successful execution
41 - Returns Failure(exception) if function raises any exception
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)
58 return wrapper
61# Alias for more natural usage
62try_ = try_decorator
65def result(func: Callable[..., T]) -> Callable[..., 'Result[T, Exception]']:
66 """
67 Decorator that wraps function return values in Result monad.
69 - Returns Ok(result) for successful execution
70 - Returns Err(exception) if function raises any exception
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)
87 return wrapper