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

1 from typing import TypeVar, Generic, Callable, Union, Any, Optional, Iterator

2

3 T = TypeVar('T')

4 U = TypeVar('U')

5 V = TypeVar('V')

6 E = TypeVar('E')

7

8

9 class 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")