Coverage for src/monadc/try_/try_.py: 73%
55 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
1from typing import TypeVar, Generic, Callable, Union, Any, Optional, Type
3T = TypeVar('T') # Success type
4U = TypeVar('U') # Result type
5E = TypeVar('E', bound=Exception) # Exception type
8class Try(Generic[T]):
9 """
10 Scala inspired Try monad for representing computations that may throw exceptions.
12 Try[T] represents a computation that either:
13 - Success[T]: A successful computation with result of type T
14 - Failure: A failed computation that caught an exception
16 Try automatically catches exceptions and wraps them in Failure.
17 """
19 def __new__(cls, func: Callable[[], T]) -> 'Try[T]':
20 """Factory constructor that executes function and catches exceptions."""
21 if cls is not Try:
22 # Direct subclass instantiation (Success, Failure)
23 return super().__new__(cls)
25 try:
26 result = func()
27 from .success import Success
28 return Success(result)
29 except Exception as e:
30 from .failure import Failure
31 return Failure(e)
33 @classmethod
34 def of_value(cls, value: T) -> 'Try[T]':
35 """Create a Success directly from a value without function execution."""
36 from .success import Success
37 return Success(value)
39 # Type checking methods
40 def is_success(self) -> bool:
41 """Returns True if this Try is a Success, False otherwise."""
42 raise NotImplementedError("Use Success or Failure, not Try directly")
44 def is_failure(self) -> bool:
45 """Returns True if this Try is a Failure, False otherwise."""
46 raise NotImplementedError("Use Success or Failure, not Try directly")
48 # Value extraction
49 def get(self) -> T:
50 """Get the value. Raises the original exception if this is a Failure."""
51 raise NotImplementedError("Use Success or Failure, not Try directly")
53 def get_or_else(self, default: Union[T, Callable[[], T]]) -> T:
54 """Get the value or return default if this is a Failure."""
55 raise NotImplementedError("Use Success or Failure, not Try directly")
57 # Exception access
58 def exception(self) -> Optional[Exception]:
59 """Get the exception if this is a Failure, None otherwise."""
60 raise NotImplementedError("Use Success or Failure, not Try directly")
62 # Transformations
63 def map(self, func: Callable[[T], U]) -> 'Try[U]':
64 """Transform the Success value if present, otherwise return unchanged Failure."""
65 raise NotImplementedError("Use Success or Failure, not Try directly")
67 def flat_map(self, func: Callable[[T], 'Try[U]']) -> 'Try[U]':
68 """Transform Success value to Try if present, otherwise return unchanged Failure."""
69 raise NotImplementedError("Use Success or Failure, not Try directly")
71 def filter(self, predicate: Callable[[T], bool]) -> 'Try[T]':
72 """Keep Success if predicate matches, otherwise return Failure."""
73 raise NotImplementedError("Use Success or Failure, not Try directly")
75 # Recovery operations
76 def recover(self, func: Callable[[Exception], T]) -> 'Try[T]':
77 """Recover from Failure by applying function to exception."""
78 raise NotImplementedError("Use Success or Failure, not Try directly")
80 def recover_with(self, func: Callable[[Exception], 'Try[T]']) -> 'Try[T]':
81 """Recover from Failure by applying function that returns Try."""
82 raise NotImplementedError("Use Success or Failure, not Try directly")
84 def or_else(self, alternative: Union['Try[T]', Callable[[], 'Try[T]']]) -> 'Try[T]':
85 """Return self if Success, otherwise return alternative Try."""
86 raise NotImplementedError("Use Success or Failure, not Try directly")
88 def flatten(self) -> 'Try[Any]':
89 """Flatten nested Try[Try[T]] to Try[T]. Raises TypeError if not nested."""
90 raise NotImplementedError("Use Success or Failure, not Try directly")
92 def flatten_safe(self) -> 'Try[Any]':
93 """Safe flatten that returns self if not nested (idempotent behavior)."""
94 raise NotImplementedError("Use Success or Failure, not Try directly")
96 # Folding
97 def fold(self, if_failure: Callable[[Exception], U], if_success: Callable[[T], U]) -> U:
98 """Apply if_failure to exception or if_success to value."""
99 raise NotImplementedError("Use Success or Failure, not Try directly")
101 def transform(self, success_func: Callable[[T], 'Try[U]'],
102 failure_func: Callable[[Exception], 'Try[U]']) -> 'Try[U]':
103 """Transform both Success and Failure cases."""
104 raise NotImplementedError("Use Success or Failure, not Try directly")
106 # Side effects
107 def foreach(self, func: Callable[[T], Any]) -> None:
108 """Execute function on Success value, do nothing for Failure."""
109 raise NotImplementedError("Use Success or Failure, not Try directly")
111 # Conversions
112 def to_option(self) -> Any: # Returns Option[T]
113 """Convert Try to Option, losing exception information."""
114 raise NotImplementedError("Use Success or Failure, not Try directly")
116 def to_either(self) -> Any: # Returns Either[Exception, T]
117 """Convert Try to Either with exception as Left value."""
118 raise NotImplementedError("Use Success or Failure, not Try directly")