A functional programming library for Python that brings type-safe error handling through the Result monad pattern
Project description
result-py
A functional programming library for Python.
Features
- Type-Safe Error Handling: Errors are values, not exceptions. Your type checker knows exactly what can go wrong.
- Railway-Oriented Programming: Chain operations elegantly with
.pipe()and handle both success and failure paths. - Rich Collection Operations:
map,filter,reduce,flat_map, and more—all within the Either context. - Modern Python: Built for Python 3.14+ with full type annotations and generics.
- Functional Composition: Build complex pipelines from simple, testable functions.
Installation
pip install fn-result-py
Or with Poetry:
poetry add fn-result-py
Quick Start
Basic Usage
from result_py import Either
# Create success and failure values
success = Either.right(42) # Right = success
failure = Either.left("Error") # Left = failure
# Chain operations - failures short-circuit automatically
result = (
Either.right(10)
.pipe(lambda x: x * 2) # 20
.pipe(lambda x: x + 5) # 25
)
print(result) # Either(_left=None, _right=25)
Error Handling Made Explicit
from result_py import Either
def divide(a: float, b: float) -> Either[str, float]:
if b == 0:
return Either.left("Division by zero!")
return Either.right(a / b)
def sqrt(x: float) -> Either[str, float]:
if x < 0:
return Either.left("Cannot take sqrt of negative number!")
return Either.right(x ** 0.5)
# Chain operations - first error stops the pipeline
result = (
Either.right(16.0)
.pipe(lambda x: divide(x, 2)) # Right(8.0)
.pipe(sqrt) # Right(2.83...)
)
# Handle both cases with match
message = result.match(
left=lambda err: f"Failed: {err}",
right=lambda val: f"Result: {val:.2f}"
)
print(message) # "Result: 2.83"
Working with Collections
from result_py import Either
# Transform collections within Either context
result = (
Either.right([1, 2, 3, 4, 5])
.filter(lambda x: x % 2 == 0) # [2, 4]
.map(lambda x: x * 10) # [20, 40]
.to_list()
)
print(result) # Either(_left=None, _right=[20, 40])
# Filter and transform in one step
result = (
Either.right([1, 2, 3, 4, 5])
.filter_map(lambda x: x * 2 if x > 2 else None)
.to_list()
)
print(result) # Either(_left=None, _right=[6, 8, 10])
Wrapping External Code
Use wrap_external to safely wrap functions that might throw exceptions:
from result_py import wrap_external
import json
# Wrap a function that might raise exceptions
safe_json_loads = wrap_external(json.loads, json.JSONDecodeError)
result = safe_json_loads('{"valid": "json"}')
print(result) # Either(_left=None, _right={'valid': 'json'})
result = safe_json_loads('not valid json')
print(result) # Either(_left=JSONDecodeError(...), _right=None)
Using the @throws Decorator
Declare which exceptions your function might throw, and have them automatically converted to Either.left:
from result_py import Either, throws
@throws(ValueError, KeyError)
def risky_operation(data: dict, key: str) -> Either[ValueError | KeyError, int]:
value = data[key] # Might raise KeyError
if value < 0:
raise ValueError("Value must be positive")
return Either.right(value * 2)
result = risky_operation({"x": 10}, "x")
print(result) # Either(_left=None, _right=20)
result = risky_operation({}, "x")
print(result) # Either(_left=KeyError('x'), _right=None)
API Reference
Creating Either Values
| Method | Description |
|---|---|
Either.right(value) |
Create a success value |
Either.left(error) |
Create a failure value |
Either.success(value) |
Alias for right |
Either.failure(error) |
Alias for left |
Transformations
| Method | Description |
|---|---|
.pipe(f) |
Apply function to right value, supports both T -> U and T -> Either[E, U] |
.and_then(f) |
Monadic bind: chain T -> Either[E2, U] functions (alias-like to pipe for Either-returning fns) |
.map(f) |
Apply function to each item in an iterable |
.map_left(f) |
Transform the left (error) value |
.filter(f) |
Filter items in an iterable |
.filter_map(f) |
Filter and map in one step (None values filtered out) |
.flat_map(f) |
Map and flatten nested iterables |
.flatten() |
Flatten nested iterables |
Tuple Unpacking Variants
| Method | Description |
|---|---|
.n_pipe(f) |
Unpack tuple and apply multi-argument function |
.n_map(f) |
Map with tuple unpacking (lazy generator) |
.n_filter_map(f) |
Filter-map with tuple unpacking (lazy generator) |
Aggregations
| Method | Description |
|---|---|
.reduce(f, initial) |
Reduce iterable to single value |
.map_reduce(f, initial) |
Map then reduce |
.to_list() |
Convert iterable to list |
.to_set() |
Convert iterable to set |
.to_counter() |
Count occurrences of items |
Combining & Matching
| Method | Description |
|---|---|
.zip(other) |
Combine two Eithers into tuple |
.then(other) |
Chain to next Either if current is Right |
.or_else(f) |
Recover from error with E -> Either[E2, T] function |
.match(left, right) |
Pattern match on Left/Right |
.unwrap_or(default) |
Get right value or default |
Properties
| Property | Description |
|---|---|
.is_right |
True if this is a Right value |
.is_left |
True if this is a Left value |
Utilities
| Method | Description |
|---|---|
.partition(f) |
Split iterable into two based on predicate |
.to_json() |
Convert right value to JSON string |
.write_json_out(path) |
Write Pydantic model to JSON file |
.ctx_pipe(f) |
Apply side-effect function, keep original value |
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file fn_result_py-0.2.2.tar.gz.
File metadata
- Download URL: fn_result_py-0.2.2.tar.gz
- Upload date:
- Size: 11.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
080c88b8589a6b8c3b9cdc235573fc3c046ec7f5a8e64722db1230f17dc3df21
|
|
| MD5 |
7c0282e58fcdb175cc21de6f08b0df95
|
|
| BLAKE2b-256 |
ec6f74d50ed12f265d4b528da6d2cd41b9c7468c174e83359c862ebc4eb3c217
|
Provenance
The following attestation bundles were made for fn_result_py-0.2.2.tar.gz:
Publisher:
publish.yaml on KaiErikNiermann/result-py
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
fn_result_py-0.2.2.tar.gz -
Subject digest:
080c88b8589a6b8c3b9cdc235573fc3c046ec7f5a8e64722db1230f17dc3df21 - Sigstore transparency entry: 985875313
- Sigstore integration time:
-
Permalink:
KaiErikNiermann/result-py@aa7479a9cdc76c2bd0ccd38cd25961955e3977b7 -
Branch / Tag:
refs/tags/v0.2.2 - Owner: https://github.com/KaiErikNiermann
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yaml@aa7479a9cdc76c2bd0ccd38cd25961955e3977b7 -
Trigger Event:
release
-
Statement type:
File details
Details for the file fn_result_py-0.2.2-py3-none-any.whl.
File metadata
- Download URL: fn_result_py-0.2.2-py3-none-any.whl
- Upload date:
- Size: 10.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
662bffb9f9e60b17e451aa5becce1b63a62dc79c6087377889bdd0f3862c1b5a
|
|
| MD5 |
2b77e35b136d1c7a0daf5d9d43df427e
|
|
| BLAKE2b-256 |
5528a6205140259acd0a366e9008db51bd4bb5f06e41fba800551308e64f8ab8
|
Provenance
The following attestation bundles were made for fn_result_py-0.2.2-py3-none-any.whl:
Publisher:
publish.yaml on KaiErikNiermann/result-py
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
fn_result_py-0.2.2-py3-none-any.whl -
Subject digest:
662bffb9f9e60b17e451aa5becce1b63a62dc79c6087377889bdd0f3862c1b5a - Sigstore transparency entry: 985875356
- Sigstore integration time:
-
Permalink:
KaiErikNiermann/result-py@aa7479a9cdc76c2bd0ccd38cd25961955e3977b7 -
Branch / Tag:
refs/tags/v0.2.2 - Owner: https://github.com/KaiErikNiermann
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yaml@aa7479a9cdc76c2bd0ccd38cd25961955e3977b7 -
Trigger Event:
release
-
Statement type: