Coverage for src/monadc/result/err.py: 100%
75 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 .result import Result, T, E, U
5class Err(Result[T, E]):
6 """
7 Represents a failed computation in a Result monad.
9 Err contains the error value, following Rust conventions.
10 Err values pass through transformations unchanged, allowing error information
11 to propagate through a chain of operations.
12 """
14 __match_args__ = ("_value",)
16 def __new__(cls, value: E) -> 'Err[T, E]':
17 """Create a new Err instance directly, bypassing Result.__new__."""
18 return object.__new__(cls)
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
26 # Handle factory construction: Result(err_value=x) calls Err.__init__(err_obj, err_value=x)
27 if 'err_value' in kwargs:
28 self._value = kwargs['err_value']
29 # Handle direct construction: Err(value)
30 else:
31 self._value = value
33 def is_ok(self) -> bool:
34 return False
36 def is_err(self) -> bool:
37 return True
39 def __bool__(self) -> bool:
40 """Err is falsy (following Rust conventions)."""
41 return False
43 def ok(self) -> Any: # Returns Nil()
44 from ..option import Nil
45 return Nil()
47 def err(self) -> Any: # Returns Some(error)
48 from ..option import Some
49 return Some(self._value)
51 def unwrap(self) -> T:
52 raise ValueError(f"Called unwrap() on an Err value: {self._value}")
54 def unwrap_err(self) -> E:
55 return self._value # type: ignore[no-any-return]
57 def unwrap_or(self, default: T) -> T:
58 return default
60 def unwrap_or_else(self, func: Callable[[E], T]) -> T:
61 return func(self._value)
63 def map(self, func: Callable[[T], U]) -> Result[U, E]:
64 # Err passes through unchanged
65 return cast(Result[U, E], self)
67 def map_err(self, func: Callable[[E], U]) -> Result[T, U]:
68 result = func(self._value)
69 return Err(result)
71 def and_then(self, func: Callable[[T], Result[U, E]]) -> Result[U, E]:
72 # Err passes through unchanged
73 return cast(Result[U, E], self)
75 def or_else(self, func: Callable[[E], Result[T, U]]) -> Result[T, U]:
76 return func(self._value)
78 def map_or(self, default: U, func: Callable[[T], U]) -> U:
79 # Return default for Err (ignore func)
80 return default
82 def map_or_else(self, default_func: Callable[[E], U], func: Callable[[T], U]) -> U:
83 # Apply default_func to Err value (ignore func)
84 return default_func(self._value)
86 def flatten(self) -> 'Result[Any, E]':
87 # Err values are unchanged by flatten
88 return self # type: ignore[return-value]
90 def transpose(self) -> 'Any': # Returns Option[Result[T, E]]
91 # Err values transpose to Some(Err(...))
92 from ..option import Some
93 return Some(self)
95 def and_(self, other: Result[U, E]) -> Result[U, E]:
96 return cast(Result[U, E], self)
98 def or_(self, other: Result[T, U]) -> Result[T, U]:
99 return other
101 def inspect(self, func: Callable[[T], Any]) -> Result[T, E]:
102 # Err has no ok value to inspect
103 return self
105 def inspect_err(self, func: Callable[[E], Any]) -> Result[T, E]:
106 func(self._value)
107 return self
109 def to_option(self) -> Any: # Returns Option[T]
110 from ..option import Nil
111 return Nil()
113 def to_try(self) -> Any: # Returns Try[T]
114 from ..try_ import Failure
115 # Convert error value to Exception if it's not already one
116 if isinstance(self._value, Exception):
117 return Failure(self._value)
118 else:
119 # Wrap non-exception errors in a RuntimeError
120 return Failure(RuntimeError(str(self._value)))
122 def __eq__(self, other: object) -> bool:
123 if isinstance(other, Err):
124 return self._value == other._value # type: ignore[no-any-return]
125 return False
127 def __repr__(self) -> str:
128 return f"Err({self._value!r})"
130 def __str__(self) -> str:
131 return self.__repr__()