Bloat free result type for Python. No dummy classes. Pure types magic.
Project description
Resultite
Minimalist Result Type Handling with Pure Python Typing
Tired of boilerplate classes just to represent success or failure? Looking for Rust-like Result expressiveness without adopting a whole new type system or custom classes?
Resultite offers a clean, lightweight approach using Python's native Union[T, Exception] type hint pattern. Capture function outcomes transparently, handle errors gracefully, and chain operations—all with standard Python functions and type safety. It's the Pythonic way to handle results.
✨ Features
- ✅ Purely Type-Based: Uses
typing.Union[T, Exception](aliased asResult[T]) – no custom classes needed. - ✅ Type-Safe: Leverages Python's type hinting for robust error handling patterns.
- ✅ Sync & Async: Seamlessly works with both synchronous and asynchronous functions.
- ✅ Composable: Functions designed for easy chaining and transformation of results.
- ✅ Minimal & Lightweight: No external dependencies beyond standard Python.
- ✅ Easy Handling: Utility functions to extract values, provide defaults, map results, or raise errors.
- ✅ Testable: Simple functional units make testing straightforward.
- ✅ Pythonic Philosophy: Embraces Python's built-in features over introducing complex abstractions.
📦 Installation
pip install resultite
Or using uv:
uv pip install resultite
🔧 Usage
Basic Sync Example:
from resultite import run_catching, get_or_throw, get_or_default, Result
def might_fail(data: str) -> int:
if not data:
raise ValueError("Input cannot be empty")
return int(data) * 2
# Capture the outcome
result: Result[int] = run_catching(might_fail, "10") # -> 20
error_result: Result[int] = run_catching(might_fail, "") # -> ValueError("Input cannot be empty")
# Handle the result
try:
value = get_or_throw(error_result) # Raises ValueError
except ValueError as e:
print(f"Caught expected error: {e}")
# Provide a default
safe_value = get_or_default(error_result, -1) # -> -1
print(f"Safe value: {safe_value}")
# Get None on error
maybe_value = get_or_none(result) # -> 20
maybe_error = get_or_none(error_result) # -> None
Async Example:
import asyncio
from resultite import async_run_catching, map_result_async, get_or_else_async
async def fetch_data(url: str) -> dict:
# In a real scenario, this would use a library like aiohttp
await asyncio.sleep(0.1)
if "error" in url:
raise ConnectionError("Failed to connect")
return {"data": url}
async def process_data(data: dict) -> str:
await asyncio.sleep(0.1)
return data.get("data", "default").upper()
async def main():
result: Result[dict] = await async_run_catching(fetch_data, "http://example.com")
# -> {"data": "http://example.com"}
error_result: Result[dict] = await async_run_catching(fetch_data, "http://error.com")
# -> ConnectionError("Failed to connect")
# Map the successful result asynchronously
processed_result: Result[str] = await map_result_async(result, process_data)
# -> "HTTP://EXAMPLE.COM"
# Handle error result with an async fallback
final_value = await get_or_else_async(
processed_result,
lambda e: f"Async fallback for error: {e}" # Fallback if process_data failed
)
print(f"Processed value: {final_value}") # -> Processed value: HTTP://EXAMPLE.COM
final_error_value = await get_or_else_async(
error_result, # Original fetch error
lambda e: f"Async fallback for error: {e}"
)
# -> Async fallback for error: Failed to connect
print(f"Processed error value: {final_error_value}")
asyncio.run(main())
🔁 API Overview
The core type is Result[T] = Union[T, Exception].
| Function | Description | Sync/Async |
|---|---|---|
run_catching(func, *args, **kwargs) |
Executes func(*args, **kwargs) and returns Result[T]. |
Sync |
async_run_catching(func, *args, **kwargs) |
Awaits func(*args, **kwargs) and returns Result[T]. |
Async |
get_or_throw(result) |
Returns T if result is T, otherwise raises the Exception. |
Sync |
get_or_none(result) |
Returns T if result is T, otherwise returns None. |
Sync |
get_or_default(result, default) |
Returns T if result is T, otherwise returns default. |
Sync |
get_or_else(result, func) |
Returns T if result is T, otherwise calls func(exception) to get a fallback T. |
Sync |
get_or_else_async(result, func) |
Returns T if result is T, otherwise awaits func(exception) to get a fallback T. |
Async |
map_result(result, func) |
If result is T, returns run_catching(func, result). If result is Exception, returns the exception. Output is Result[U]. |
Sync |
map_result_async(result, func) |
If result is T, returns await async_run_catching(func, result). If result is Exception, returns the exception. Output is Result[U]. |
Async |
✅ Testing
Tests use Python's built-in unittest module.
First, install test dependencies (e.g., if you need specific libraries for test functions):
# Using pip
pip install .[test]
# Using uv
uv pip install .[test]
(Note: Add a [test] extra in your pyproject.toml if you have test-specific dependencies).
Then, run tests:
# Discover and run tests using unittest's discovery
python -m unittest discover tests
# Or use pytest (it can run unittest tests)
pytest
🧪 Design Philosophy
No DSLs. No magic classes. No frameworks. Just Python's strengths, applied cleanly.
Resultite embraces Python's existing type system to provide a robust yet minimal way to handle function outcomes. It avoids introducing new abstractions often seen elsewhere, focusing instead on simple, composable functions that operate on the standard Union[T, Exception] pattern. Inspired by the clarity of Result patterns, but executed with Pythonic simplicity and pragmatism.
❤️ Credits
Crafted with a love for minimalism and functional programming principles in Python.
📄 License
MIT License
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 resultite-0.1.0.tar.gz.
File metadata
- Download URL: resultite-0.1.0.tar.gz
- Upload date:
- Size: 6.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.12.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9f4cb4be2c7dc609be6261fb8679c2162d3a3228a9ee62b9320acb064fde5378
|
|
| MD5 |
7e6a572dfee7484cc52cac22a42e7f86
|
|
| BLAKE2b-256 |
e1b05b0008bdca33ec85d73c683165ff5b1485ab12a0c3d42ba4db374057fe73
|
Provenance
The following attestation bundles were made for resultite-0.1.0.tar.gz:
Publisher:
publish.yml on LiYulin-s/resultite
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
resultite-0.1.0.tar.gz -
Subject digest:
9f4cb4be2c7dc609be6261fb8679c2162d3a3228a9ee62b9320acb064fde5378 - Sigstore transparency entry: 199912312
- Sigstore integration time:
-
Permalink:
LiYulin-s/resultite@2d10f0cd2cb3a1eeec42836b5a6081728f21dfc2 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/LiYulin-s
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@2d10f0cd2cb3a1eeec42836b5a6081728f21dfc2 -
Trigger Event:
push
-
Statement type:
File details
Details for the file resultite-0.1.0-py3-none-any.whl.
File metadata
- Download URL: resultite-0.1.0-py3-none-any.whl
- Upload date:
- Size: 5.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.12.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c7dc3de4bfaabeac5f73e89a865f4b767caa1bde57d605ed862a8737ed2094b4
|
|
| MD5 |
9df9b3225bf1372b32b80e883253c555
|
|
| BLAKE2b-256 |
86879ca39b0468ff40d4dc62998b297b17bb493c303cdb37e77afac09ba53676
|
Provenance
The following attestation bundles were made for resultite-0.1.0-py3-none-any.whl:
Publisher:
publish.yml on LiYulin-s/resultite
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
resultite-0.1.0-py3-none-any.whl -
Subject digest:
c7dc3de4bfaabeac5f73e89a865f4b767caa1bde57d605ed862a8737ed2094b4 - Sigstore transparency entry: 199912313
- Sigstore integration time:
-
Permalink:
LiYulin-s/resultite@2d10f0cd2cb3a1eeec42836b5a6081728f21dfc2 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/LiYulin-s
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@2d10f0cd2cb3a1eeec42836b5a6081728f21dfc2 -
Trigger Event:
push
-
Statement type: