Skip to content
Pyrula

Either

Either is a result that’s one of two things: Ok with a value, or Err with an error. You return it instead of raising, and the caller decides what to do.

from pyrula import Either, Ok, Err
def parse_port(raw: str) -> Either:
if not raw.isdigit():
return Either.err(f"not a number: {raw!r}")
port = int(raw)
return Either.ok(port) if 0 < port < 65536 else Either.err(f"out of range: {port}")

map runs on the Ok side and skips Err. flat_map is the same but for functions that themselves return an Either, so you don’t end up with Ok(Ok(x)).

parse_port("8080").map(lambda p: p + 1) # Ok(8081)
parse_port("nope").map(lambda p: p + 1) # Err('not a number: ...'), untouched
parse_port("8080").flat_map(check_available) # check_available returns Either

map_err transforms the error side. recover turns an Err back into an Ok.

parse_port("8080").get_or_else(0) # 8080
parse_port("nope").get_or_else(0) # 0
parse_port("99999").fold(
lambda err: f"rejected: {err}",
lambda port: f"using {port}",
) # "rejected: out of range: 99999"
parse_port("nope").unwrap_or_raise(ValueError) # raises ValueError if Err

fold handles both sides at once and is usually what you want at the edge of a system, where the Either has to become a plain value.

CallResult
Either.ok(v) / Either.err(e)Ok / Err
Either.try_of(fn)Ok(fn()), or Err if fn raises
Either.cond(test, ok, err)Ok(ok) if test else Err(err)
Either.sequence([...])Ok of all values, or the first Err

to_option() drops the error and gives you a Some/Nothing.

Either[A, E] is a real generic, and Ok and Err are its subtypes. Annotate a result with Either[A, E] and return either case:

def parse_port(raw: str) -> Either[int, str]:
return Either.ok(int(raw)) if raw.isdigit() else Either.err(f"not a number: {raw!r}")

Ok[A] and Err[E] work as annotations too, and isinstance(x, Either) is true for both.

This is Scala’s right-biased Either[A, B]. Pyrula names the cases Ok/Err (Rust’s spelling) where Scala uses Right/Left, and Ok/Err subclass Either just as Right/Left do. The methods line up: map, flat_map (flatMap), fold, get_or_else (getOrElse), recover, and to_option (toOption).