Coverage for src/monadc/either/right.py: 100%
84 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 Callable, Union, Any, Optional, cast
2from .either import Either, L, R, U
5class Right(Either[L, R]):
6 """
7 Represents a successful computation in an Either monad.
9 Right is right-biased, meaning transformations (map, flat_map) operate on Right values
10 and pass through Left values unchanged.
11 """
13 __match_args__ = ("_value",)
15 def __new__(cls, value: R) -> 'Right[L, R]':
16 """Create a new Right instance directly, bypassing Either.__new__."""
17 return object.__new__(cls)
19 def __init__(self, value: Any = None, **kwargs: Any) -> None:
20 # If _value already exists, this is a second call from Python's object creation process
21 # We should ignore it since the object has already been properly initialized
22 if hasattr(self, '_value'):
23 return
25 # Handle factory construction: Either(right=x) calls Right.__init__(right_obj, right=x)
26 if 'right' in kwargs:
27 self._value = kwargs['right']
28 # Handle direct construction: Right(value)
29 else:
30 self._value = value
32 def __eq__(self, other: object) -> bool:
33 if isinstance(other, Right):
34 return self._value == other._value # type: ignore[no-any-return]
35 return False
37 def __repr__(self) -> str:
38 return f"Right({self._value!r})"
40 def __str__(self) -> str:
41 return self.__repr__()
43 # ========================================
44 # Rust / Scala Common API
45 # ========================================
47 def is_left(self) -> bool:
48 return False
50 def is_right(self) -> bool:
51 return True
53 def left(self) -> Any: # Returns Option[L]
54 from ..option import Nil
55 return Nil()
57 def right(self) -> Any: # Returns Option[R]
58 from ..option import Some
59 return Some(self._value)
61 def map(self, func: Callable[[Union[L, R]], U]) -> U:
62 return func(self._value)
64 def map_left(self, func: Callable[[L], U]) -> Either[U, R]:
65 # Right is unchanged by map_left
66 return cast(Either[U, R], self)
68 def map_right(self, func: Callable[[R], U]) -> Either[L, U]:
69 result = func(self._value)
70 return Right(result)
72 # ========================================
73 # RUST API
74 # ========================================
76 def either(self, left_func: Callable[[L], U], right_func: Callable[[R], U]) -> U:
77 """Apply left_func to Left value or right_func to Right value. Alias for fold."""
78 return self.fold(left_func, right_func)
80 def map_either(self, left_func: Callable[[L], U], right_func: Callable[[R], U]) -> U:
81 return right_func(self._value)
83 def unwrap_left(self) -> L:
84 raise ValueError("Cannot unwrap left value from Right")
86 def unwrap_right(self) -> R:
87 return self._value # type: ignore[no-any-return]
89 def expect_left(self, message: str) -> L:
90 raise ValueError(message)
92 def expect_right(self, message: str) -> R:
93 return self._value # type: ignore[no-any-return]
95 def left_or(self, other: Either[U, R]) -> Either[U, R]:
96 # Return other since self is Right
97 return other
99 def right_or(self, other: Either[L, U]) -> Either[L, U]:
100 # Return self (Right) rather than other
101 return cast(Either[L, U], self)
103 def left_or_else(self, func: Callable[[], Either[U, R]]) -> Either[U, R]:
104 # Call func and return result since self is Right
105 return func()
107 def right_or_else(self, func: Callable[[], Either[L, U]]) -> Either[L, U]:
108 # Return self (Right) rather than calling func
109 return cast(Either[L, U], self)
111 def left_and_then(self, func: Callable[[L], Either[U, R]]) -> Either[U, R]:
112 # Right passes through unchanged
113 return cast(Either[U, R], self)
115 def right_and_then(self, func: Callable[[R], Either[L, U]]) -> Either[L, U]:
116 return func(self._value)
118 def flip(self) -> Either[R, L]:
119 from .left import Left
120 return Left(self._value)
122 # ========================================
123 # SCALA API
124 # ========================================
126 def swap(self) -> Either[R, L]:
127 from .left import Left
128 return Left(self._value)
130 def fold(self, if_left: Callable[[L], U], if_right: Callable[[R], U]) -> U:
131 return if_right(self._value)
133 def foreach(self, func: Callable[[R], Any]) -> None:
134 func(self._value)
136 def get(self) -> R:
137 return self._value # type: ignore[no-any-return]
139 def get_or_else(self, default: Union[R, Callable[[], R]]) -> R:
140 # Return the Right value, ignore default
141 return self._value # type: ignore[no-any-return]
143 def to_option(self) -> Any: # Returns Option[R]
144 from ..option import Option
145 return Option(self._value)
147 def contains(self, value: Any) -> bool:
148 return self._value == value # type: ignore[no-any-return]
150 def exists(self, predicate: Callable[[R], bool]) -> bool:
151 return predicate(self._value)
153 def or_else(self, other: Union['Either[L, U]', Callable[[], 'Either[L, U]']]) -> 'Either[L, Union[R, U]]':
154 # Return self since this is a Right
155 return cast('Either[L, Union[R, U]]', self)