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
« 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
3T = TypeVar('T')
4U = TypeVar('U')
5V = TypeVar('V')
6E = TypeVar('E')
9class Option(Generic[T]):
10 """
11 Rust and Scala inspired Option monad representing optional values with dual Scala/Rust API.
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 """
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)
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)
32 # ========================================
33 # Rust / Scala Common API
34 # ========================================
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")
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")
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")
52 def flatten(self) -> 'Option[Any]':
53 """Flatten Option[Option[T]] to Option[T]."""
54 raise NotImplementedError("Use Some or Nil, not Option directly")
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")
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")
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")
68 # ========================================
69 # RUST API
70 # ========================================
72 def is_some(self) -> bool:
73 """Rust-style: True if this is Some."""
74 raise NotImplementedError("Use Some or Nil, not Option directly")
76 def is_none(self) -> bool:
77 """Rust-style: True if this is Nil."""
78 raise NotImplementedError("Use Some or Nil, not Option directly")
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")
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")
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")
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")
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")
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")
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")
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")
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")
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")
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")
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")
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")
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")
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")
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")
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")
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")
153 # ========================================
154 # SCALA API
155 # ========================================
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")
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")
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")
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")
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")
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")
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")
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")
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")
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")
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")
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")
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")
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")
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")
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")
222 # ========================================
223 # PYTHON SPECIAL METHODS
224 # ========================================
226 def __bool__(self) -> bool:
227 raise NotImplementedError("Use Some or Nil, not Option directly")
229 def __iter__(self) -> Iterator[T]:
230 raise NotImplementedError("Use Some or Nil, not Option directly")
232 def __eq__(self, other: object) -> bool:
233 raise NotImplementedError("Use Some or Nil, not Option directly")
235 def __repr__(self) -> str:
236 raise NotImplementedError("Use Some or Nil, not Option directly")
238 def __str__(self) -> str:
239 raise NotImplementedError("Use Some or Nil, not Option directly")