Coverage for src/monadc/option/option.py: 60%

110 statements  

« 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, Iterator 

2 

3T = TypeVar('T') 

4U = TypeVar('U') 

5V = TypeVar('V') 

6E = TypeVar('E') 

7 

8 

9class Option(Generic[T]): 

10 """ 

11 Rust and Scala inspired Option monad representing optional values with dual Scala/Rust API. 

12 

13 Option[T] represents a value that may or may not exist: 

14 - Some[T]: Contains a value of type T 

15 - Nil: Represents no value (equivalent to None in Rust and Scala) 

16 """ 

17 

18 def __new__(cls, value: Optional[T] = None) -> 'Option[T]': 

19 """Factory constructor: Option(x) creates Some(x) or Nil()""" 

20 if cls is not Option: 

21 # Direct subclass instantiation (Some, Nil) 

22 return super().__new__(cls) 

23 

24 # Option(x) factory behavior 

25 if value is None: 

26 from .nil import Nil 

27 return Nil() 

28 else: 

29 from .some import Some 

30 return Some(value) 

31 

32 # ======================================== 

33 # Rust / Scala Common API 

34 # ======================================== 

35 

36 def or_else(self, alternative: Union['Option[T]', Callable[[], 'Option[T]']]) -> 'Option[T]': 

37 """ 

38 Return this Option if defined, otherwise use alternative. 

39 - Rust: the alternative is a callable. 

40 - Scala: the alternative is a value. 

41 """ 

42 raise NotImplementedError("Use Some or Nil, not Option directly") 

43 

44 def filter(self, predicate: Callable[[T], bool]) -> 'Option[T]': 

45 """Keep value if predicate is true, otherwise return empty Option.""" 

46 raise NotImplementedError("Use Some or Nil, not Option directly") 

47 

48 def map(self, func: Callable[[T], U]) -> 'Option[U]': 

49 """Transform the value if present, otherwise return empty Option.""" 

50 raise NotImplementedError("Use Some or Nil, not Option directly") 

51 

52 def flatten(self) -> 'Option[Any]': 

53 """Flatten Option[Option[T]] to Option[T].""" 

54 raise NotImplementedError("Use Some or Nil, not Option directly") 

55 

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

57 """Rust-style: Transpose Option[Result[T, E]] to Result[Option[T], E].""" 

58 raise NotImplementedError("Use Some or Nil, not Option directly") 

59 

60 def zip(self, other: 'Option[U]') -> 'Option[tuple[T, U]]': 

61 """Rust-style: Zip with another Option to create Option of tuple.""" 

62 raise NotImplementedError("Use Some or Nil, not Option directly") 

63 

64 def unzip(self) -> 'tuple[Option[Any], Option[Any]]': 

65 """Unzip Option[tuple[A, B]] to tuple[Option[A], Option[B]].""" 

66 raise NotImplementedError("Use Some or Nil, not Option directly") 

67 

68 # ======================================== 

69 # RUST API 

70 # ======================================== 

71 

72 def is_some(self) -> bool: 

73 """Rust-style: True if this is Some.""" 

74 raise NotImplementedError("Use Some or Nil, not Option directly") 

75 

76 def is_none(self) -> bool: 

77 """Rust-style: True if this is Nil.""" 

78 raise NotImplementedError("Use Some or Nil, not Option directly") 

79 

80 def unwrap(self) -> T: 

81 """Rust-style: Get the value. Panics if this is Nil.""" 

82 raise NotImplementedError("Use Some or Nil, not Option directly") 

83 

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

85 """Rust-style: Get the value or return default if Nil.""" 

86 raise NotImplementedError("Use Some or Nil, not Option directly") 

87 

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

89 """Rust-style: Get the value or compute default if Nil.""" 

90 raise NotImplementedError("Use Some or Nil, not Option directly") 

91 

92 def expect(self, message: str) -> T: 

93 """Rust-style: Get the value or raise error with custom message.""" 

94 raise NotImplementedError("Use Some or Nil, not Option directly") 

95 

96 def and_then(self, func: Callable[[T], 'Option[U]']) -> 'Option[U]': 

97 """Rust-style: Transform Some value to Option.""" 

98 raise NotImplementedError("Use Some or Nil, not Option directly") 

99 

100 def or_else_with(self, func: Callable[[], 'Option[T]']) -> 'Option[T]': 

101 """Rust-style: Return self if Some, otherwise call func.""" 

102 raise NotImplementedError("Use Some or Nil, not Option directly") 

103 

104 def and_(self, other: 'Option[U]') -> 'Option[U]': 

105 """Rust-style: Return other if self is Some, otherwise return Nil.""" 

106 raise NotImplementedError("Use Some or Nil, not Option directly") 

107 

108 def or_(self, other: 'Option[T]') -> 'Option[T]': 

109 """Rust-style: Return self if Some, otherwise return other.""" 

110 raise NotImplementedError("Use Some or Nil, not Option directly") 

111 

112 def xor(self, other: 'Option[T]') -> 'Option[T]': 

113 """Rust-style: Return Some if exactly one of self or other is Some.""" 

114 raise NotImplementedError("Use Some or Nil, not Option directly") 

115 

116 

117 def zip_with(self, other: 'Option[U]', func: Callable[[T, U], V]) -> 'Option[V]': 

118 """Rust-style: Zip with another Option and apply function.""" 

119 raise NotImplementedError("Use Some or Nil, not Option directly") 

120 

121 def inspect(self, func: Callable[[T], Any]) -> 'Option[T]': 

122 """Rust-style: Call function with value if Some, return self unchanged.""" 

123 raise NotImplementedError("Use Some or Nil, not Option directly") 

124 

125 def get_or_insert(self, value: T) -> T: 

126 """Rust-style: Get the value or insert and return default if Nil.""" 

127 raise NotImplementedError("Use Some or Nil, not Option directly") 

128 

129 def get_or_insert_with(self, func: Callable[[], T]) -> T: 

130 """Rust-style: Get the value or insert result of func and return it if Nil.""" 

131 raise NotImplementedError("Use Some or Nil, not Option directly") 

132 

133 def insert(self, value: T) -> T: 

134 """Rust-style: Insert value and return it.""" 

135 raise NotImplementedError("Use Some or Nil, not Option directly") 

136 

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

138 """Rust-style: Apply func to Some value or return default if Nil.""" 

139 raise NotImplementedError("Use Some or Nil, not Option directly") 

140 

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

142 """Rust-style: Apply func to Some value or call default_func if Nil.""" 

143 raise NotImplementedError("Use Some or Nil, not Option directly") 

144 

145 def ok_or(self, error: E) -> 'Any': # Returns Result[T, E] 

146 """Rust-style: Convert Some(v) to Ok(v) or Nil to Err(error).""" 

147 raise NotImplementedError("Use Some or Nil, not Option directly") 

148 

149 def ok_or_else(self, func: Callable[[], E]) -> 'Any': # Returns Result[T, E] 

150 """Rust-style: Convert Some(v) to Ok(v) or Nil to Err(func()).""" 

151 raise NotImplementedError("Use Some or Nil, not Option directly") 

152 

153 # ======================================== 

154 # SCALA API 

155 # ======================================== 

156 

157 def is_defined(self) -> bool: 

158 """Returns True if this Option has a value, False otherwise.""" 

159 raise NotImplementedError("Use Some or Nil, not Option directly") 

160 

161 def is_empty(self) -> bool: 

162 """Returns True if this Option is empty, False otherwise.""" 

163 raise NotImplementedError("Use Some or Nil, not Option directly") 

164 

165 def get(self) -> T: 

166 """Get the value of this Option. Raises exception if empty.""" 

167 raise NotImplementedError("Use Some or Nil, not Option directly") 

168 

169 def get_or_else(self, default: Union[T, Callable[[], T]]) -> T: 

170 """Get the value or return default if empty.""" 

171 raise NotImplementedError("Use Some or Nil, not Option directly") 

172 

173 def filter_not(self, predicate: Callable[[T], bool]) -> 'Option[T]': 

174 """Keep value if predicate is false, otherwise return empty Option.""" 

175 raise NotImplementedError("Use Some or Nil, not Option directly") 

176 

177 def flat_map(self, func: Callable[[T], 'Option[U]']) -> 'Option[U]': 

178 """Transform the value to Option if present, otherwise return empty Option.""" 

179 raise NotImplementedError("Use Some or Nil, not Option directly") 

180 

181 def fold(self, if_empty: U, func: Callable[[T], U]) -> U: 

182 """Apply func to value if present, otherwise return if_empty.""" 

183 raise NotImplementedError("Use Some or Nil, not Option directly") 

184 

185 def foreach(self, func: Callable[[T], Any]) -> None: 

186 """Scala-style: Apply func to value if present.""" 

187 raise NotImplementedError("Use Some or Nil, not Option directly") 

188 

189 def exists(self, predicate: Callable[[T], bool]) -> bool: 

190 """True if value exists and satisfies predicate.""" 

191 raise NotImplementedError("Use Some or Nil, not Option directly") 

192 

193 def forall(self, predicate: Callable[[T], bool]) -> bool: 

194 """Scala-style: True if empty or value satisfies predicate.""" 

195 raise NotImplementedError("Use Some or Nil, not Option directly") 

196 

197 def contains(self, value: Any) -> bool: 

198 """Scala-style: True if Option contains the specified value.""" 

199 raise NotImplementedError("Use Some or Nil, not Option directly") 

200 

201 def non_empty(self) -> bool: 

202 """Scala-style: True if this Option is not empty.""" 

203 raise NotImplementedError("Use Some or Nil, not Option directly") 

204 

205 def or_null(self) -> Optional[T]: 

206 """Scala-style: Return value if defined, None if empty.""" 

207 raise NotImplementedError("Use Some or Nil, not Option directly") 

208 

209 def or_none(self) -> Optional[T]: 

210 """Return value if defined, None if empty. Alias for or_null.""" 

211 raise NotImplementedError("Use Some or Nil, not Option directly") 

212 

213 def to_list(self) -> list[T]: 

214 """Convert to list - empty list if empty, single-item list if defined.""" 

215 raise NotImplementedError("Use Some or Nil, not Option directly") 

216 

217 def to_optional(self) -> Optional[T]: 

218 """Convert to Optional - None if empty, value if defined.""" 

219 raise NotImplementedError("Use Some or Nil, not Option directly") 

220 

221 

222 # ======================================== 

223 # PYTHON SPECIAL METHODS 

224 # ======================================== 

225 

226 def __bool__(self) -> bool: 

227 raise NotImplementedError("Use Some or Nil, not Option directly") 

228 

229 def __iter__(self) -> Iterator[T]: 

230 raise NotImplementedError("Use Some or Nil, not Option directly") 

231 

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

233 raise NotImplementedError("Use Some or Nil, not Option directly") 

234 

235 def __repr__(self) -> str: 

236 raise NotImplementedError("Use Some or Nil, not Option directly") 

237 

238 def __str__(self) -> str: 

239 raise NotImplementedError("Use Some or Nil, not Option directly")