Coverage for src/monadc/result/ok.py: 100%

1 from typing import Callable, Union, Any, Optional, cast

2 from .result import Result, T, E, U

3

4

5 class Ok(Result[T, E]):

6 """

7 Represents a successful computation in a Result monad.

8

9 Ok contains the successful result value, following Rust conventions.

10 Ok is result-biased, meaning transformations (map, and_then) operate on Ok values

11 and pass through Err values unchanged.

12 """

13

14 __match_args__ = ("_value",)

15

16 def __new__(cls, value: T) -> 'Ok[T, E]':

17 """Create a new Ok instance directly, bypassing Result.__new__."""

18 return object.__new__(cls)

19

20 def __init__(self, value: Any = None, **kwargs: Any) -> None:

21 # If _value already exists, this is a second call from Python's object creation process

22 # We should ignore it since the object has already been properly initialized

23 if hasattr(self, '_value'):

24 return

25

26 # Handle factory construction: Result(ok_value=x) calls Ok.__init__(ok_obj, ok_value=x)

27 if 'ok_value' in kwargs:

28 self._value = kwargs['ok_value']

29 # Handle direct construction: Ok(value)

30 else:

31 self._value = value

32

33 def is_ok(self) -> bool:

34 return True

35

36 def is_err(self) -> bool:

37 return False

38

39 def __bool__(self) -> bool:

40 """Ok is truthy (following Rust conventions)."""

41 return True

42

43 def ok(self) -> Any: # Returns Some(value)

44 from ..option import Some

45 return Some(self._value)

46

47 def err(self) -> Any: # Returns Nil()

48 from ..option import Nil

49 return Nil()

50

51 def unwrap(self) -> T:

52 return self._value # type: ignore[no-any-return]

53

54 def unwrap_err(self) -> E:

55 raise ValueError("Called unwrap_err() on an Ok value")

56

57 def unwrap_or(self, default: T) -> T:

58 return self._value # type: ignore[no-any-return]

59

60 def unwrap_or_else(self, func: Callable[[E], T]) -> T:

61 return self._value # type: ignore[no-any-return]

62

63 def map(self, func: Callable[[T], U]) -> Result[U, E]:

64 result = func(self._value)

65 return Ok(result)

66

67 def map_err(self, func: Callable[[E], U]) -> Result[T, U]:

68 # Ok is unchanged by map_err

69 return cast(Result[T, U], self)

70

71 def and_then(self, func: Callable[[T], Result[U, E]]) -> Result[U, E]:

72 return func(self._value)

73

74 def or_else(self, func: Callable[[E], Result[T, U]]) -> Result[T, U]:

75 # Ok doesn't need alternative

76 return cast(Result[T, U], self)

77

78 def map_or(self, default: U, func: Callable[[T], U]) -> U:

79 # Apply func to Ok value

80 return func(self._value)

81

82 def map_or_else(self, default_func: Callable[[E], U], func: Callable[[T], U]) -> U:

83 # Apply func to Ok value (ignore default_func)

84 return func(self._value)

85

86 def flatten(self) -> 'Result[Any, E]':

87 # If the Ok value is itself a Result, unwrap it

88 if isinstance(self._value, Result):

89 return self._value # type: ignore[return-value]

90 # Otherwise return self unchanged

91 return self # type: ignore[return-value]

92

93 def transpose(self) -> 'Any': # Returns Option[Result[T, E]]

94 # If the Ok value is an Option, transpose Result[Option[T], E] to Option[Result[T, E]]

95 from ..option import Option, Some, Nil

96 if hasattr(self._value, 'is_empty') and callable(getattr(self._value, 'is_empty')): # Duck typing for Option

97 if self._value.is_empty():

98 return Nil()

99 else:

100 # Extract value from Some and wrap in Ok

101 return Some(Ok(self._value.unwrap()))

102 # If not an Option, wrap self in Some

103 return Some(self)

104

105 def and_(self, other: Result[U, E]) -> Result[U, E]:

106 return other

107

108 def or_(self, other: Result[T, U]) -> Result[T, U]:

109 return cast(Result[T, U], self)

110

111 def inspect(self, func: Callable[[T], Any]) -> Result[T, E]:

112 func(self._value)

113 return self

114

115 def inspect_err(self, func: Callable[[E], Any]) -> Result[T, E]:

116 # Ok has no error to inspect

117 return self

118

119 def to_option(self) -> Any: # Returns Option[T]

120 from ..option import Option

121 return Option(self._value)

122

123 def to_try(self) -> Any: # Returns Try[T]

124 from ..try_ import Success

125 return Success(self._value)

126

127 def __eq__(self, other: object) -> bool:

128 if isinstance(other, Ok):

129 return self._value == other._value # type: ignore[no-any-return]

130 return False

131

132 def __repr__(self) -> str:

133 return f"Ok({self._value! r})"

134

135 def __str__(self) -> str:

136 return self.__repr__()