Try
Try[T] is Success(value) or Failure(exc). It moves an exception from control flow into a value.
from pyrula import Try, Success, Failure
Try.apply(lambda: int("42")) # Success(42)Try.apply(lambda: int("nope")) # Failure(ValueError(...))Work with the outcome
Section titled “Work with the outcome”result = Try.apply(lambda: int("42"))
result.map(lambda n: n * 2).get_or_else(0)result.fold(lambda exc: f"bad input: {exc}", lambda n: f"got {n}")result.recover(lambda exc: 0) # Failure becomes Success(0)recover_with(fn) recovers with another Try; or_else(fn) swaps in a fallback Try. get_or_else evaluates its argument eagerly; get_or_else_with(factory) calls the factory once, only on Failure.
to_either() gives Ok(value) or Err(exception). Chain .map_err(...) on the Either to turn the exception into an application error (Try itself has no map_err).
Exception boundaries
Section titled “Exception boundaries”Try.apply, Try.traverse, map and flat_map capture Exception. KeyboardInterrupt and SystemExit propagate. tap and tap_failure are observers: their exceptions propagate instead of becoming a Failure.
def broken(value: int) -> int: raise ValueError("callback failed")
assert isinstance(Success(1).map(broken), Failure)
try: Success(1).tap(broken)except ValueError: pass # observer errors are not capturedTraversal and sequencing
Section titled “Traversal and sequencing”traverse(values, fn) stops at the first Failure; sequence(values) collects existing Try values. Both return a list inside Success.
def parse(raw: str) -> Try[int]: return Try.apply(lambda: int(raw))
Try.traverse(["1", "2"], parse) # Success([1, 2])Try.traverse(["1", "nope", "3"], parse) # Failure(ValueError(...))Try.sequence([Success(1), Success(2)]) # Success([1, 2])traverse captures Exception from iteration or the callback as a Failure. A callback that returns a non-Try raises TypeError.
Matching and flattening
Section titled “Matching and flattening”match Try.apply(lambda: int("42")): case Success(value): message = f"parsed: {value}" case Failure(error): message = f"rejected: {error}"
assert message == "parsed: 42"Success(Success(5)).flatten() # Success(5)flatten raises TypeError if the Success does not hold a Try.
@do chains dependent Try calls. The JSON form is in JSON form.