Bring some useful tools from Rust to Python
Project description
rusty-utils
Bringing useful tools from Rust to Python.
🚪 Portals
📥 Installation
rusty-utils is available on PyPI.
Install using pip:
pip install rusty-utils
Or with poetry:
poetry add rusty-utils
📚 Features
rusty-utils brings Rust-inspired constructs like Result and Option to Python, allowing developers to write cleaner
and more robust error-handling code.
For more details, check out the full documentation.
Result[T, E]
The Result type is inspired by Rust, enabling you to handle success (Ok) and failure (Err) in a clean, expressive
way.
from rusty_utils import Result, Ok, Err
# Success case
success: Result[int, Exception] = Ok(42)
# Failure case
failure: Result[int, Exception] = Err(Exception("An error occurred"))
Custom Result Types
You can alias your own custom Result types to suit your domain-specific needs.
from typing import TypeVar
from rusty_utils import Result, Ok, Err
class MyError(Exception): pass
_T = TypeVar("_T")
MyResult = Result[_T, MyError]
# Custom success and failure cases
success: MyResult[int] = Ok(42)
failure: MyResult[int] = Err(MyError("Something went wrong"))
? Operator
In Rust, the ? operator is used to easily propagate errors up the call stack, allowing you to return early if a
function fails, and to handle success (Ok) and failure (Err) values concisely.
fn side_effect() -> Resut<i32, Error> {
// some code that may fail
Ok(42)
}
fn process() -> Result<(), Error> {
let result = side_effect()?; // Propagates the error if it occurs
... // Other operation
}
In Python, you can't overload the ? operator (we even didn't treat ? as a valid operator in Python)
result = side_effect()? # What???
In Python, something has similar ability to throw the Err and remain the Ok value is:
Python built-in try-except.
from rusty_utils import Catch
def side_effect() -> float:
# Simulate a potential failure (e.g., division by zero)
return 42 / 0
@Catch(Exception, ZeroDivisionError)
def wrapped_side_effect() -> float:
return side_effect()
@Catch(Exception)
def process() -> None:
result1 = wrapped_side_effect().unwrap_or_raise() # You achieve same functionality with `unwrap_or_raise()`!
result2 = Catch(Exception, ZeroDivisionError, func=side_effect).unwrap_or_raise()
In this example:
- We use the
@Catch(Exception)decorator to make sure we can capture the raisedErrand return to the caller.- What the
@Catch(E)do is transform the function into a capturer which returnsResult[T, E]
- What the
- We can use the
Catchin this way (result2) to capture the result of a fallible function call into aResult. - The
wrapped_side_effect()function returns aResultthat might be an error (Err) or a valid value (Ok).- Since the function returns a
floatand we mark it might raise anException, so it actually returns aResult[float, Exception].
- Since the function returns a
- Then use
unwrap_or_raise()to handle the result: if it's an error, it raises the exception, effectively mimicking Rust's?operator.
This approach enables cleaner error propagation and handling in Python, much like in Rust, but using Python’s exception-handling style.
Although the
@Catchdecorator accpets multiple exception types, it's recommended to use it only for one type of exception at a time, or your linter might can't resolve the type hints correctly. (like it might think thewrapped_side_effectreturns aResult[float, Any])
API Overview
-
Querying Result Type:
is_ok(): ReturnsTrueif theResultisOk.is_err(): ReturnsTrueif theResultisErr.
-
Unwrapping Values:
expect(message): Unwraps the value or raisesUnwrapErrorwith a custom message.unwrap(): Unwraps the value or raisesUnwrapError.unwrap_or(default): Returns the provided default value ifErr.unwrap_or_else(func): Returns the result of the provided function ifErr.unwrap_or_raise(): Raises the exception contained inErr.
-
Transforming Results:
ok(): TransformsOktoOption[T]err(): TransformsErrtoOption[E]map(func): Appliesfuncto theOkvalue.map_err(func): Appliesfuncto theErrvalue.map_or(default, func): AppliesfunctoOkor returnsdefaultifErr.map_or_else(f_err, f_ok): Applies different functions depending on whether theResultisOkorErr.
-
Logical Operations:
and_(other): Returns the secondResultif the first isOk; otherwise returns the originalErr.or_(other): Returns the firstOk, or the secondResultif the first isErr.and_then(func): Chains another operation based on theOkvalue.or_else(func): Chains another operation based on theErrvalue.
Option[T]
The Option type expands Python's Optional, representing a value that may or may not be present (Some or None).
from rusty_utils import Option
some_value: Option[int] = Option(42)
none_value: Option[int] = Option()
API Overview
-
Querying Option Type:
is_some(): ReturnsTrueif theOptioncontains a value.is_none(): ReturnsTrueif theOptioncontains no value.
-
Unwrapping Values:
expect(message): Unwraps the value or raisesUnwrapErrorwith a custom message.unwrap(): Unwraps the value or raisesUnwrapError.unwrap_or(default): Returns the provided default value ifNone.unwrap_or_else(func): Returns the result of a provided function ifNone.
-
Transforming Options:
map(func): Transforms theSomevalue.map_or(default, func): Transforms theSomevalue or returns a default ifNone.map_or_else(default_func, func): Transforms theSomevalue or returns the result of a default function ifNone.
-
Logical Operations:
and_(other): Returns the secondOptionif the first isSome; otherwise returnsNone.or_(other): Returns the firstSome, or the secondOptionif the first isNone.and_then(func): Chains another operation based on theSomevalue.or_else(func): Chains another operation based on theNonevalue.
⚙️ Usage Examples
Here are more practical examples of using Result and Option in real-world scenarios.
Example: Handling API Responses
from rusty_utils import Result, Ok, Err
def fetch_data() -> Result[dict, Exception]:
try:
# Simulating an API call
data = {"id": 824, "name": "Kobe Bryant"}
return Ok(data)
except Exception as e:
return Err(e)
result = fetch_data()
if result.is_ok():
print("Success:", result.unwrap())
else:
print("Error:", result.unwrap_err())
Example: Safely Unwrapping Values
from rusty_utils import Option
def get_value() -> Option[int]:
return Option(42)
some_value = get_value()
print(some_value.unwrap_or(0)) # Outputs: 42
For more advanced use cases, consult the full documentation.
Project details
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 rusty_utils-0.1.5.tar.gz.
File metadata
- Download URL: rusty_utils-0.1.5.tar.gz
- Upload date:
- Size: 9.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/1.8.3 CPython/3.11.9 Linux/6.5.0-1025-azure
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1a470f74d0cafc9365e1d0b6b73bde11a247e020bae2950370375459dddd36c4
|
|
| MD5 |
96d7c8901a7d26fe22d430f05f8b0f7b
|
|
| BLAKE2b-256 |
5740048b3dceb8def27e049630728db16db5ef8d1d779d99d5ff92428fae1079
|
File details
Details for the file rusty_utils-0.1.5-py3-none-any.whl.
File metadata
- Download URL: rusty_utils-0.1.5-py3-none-any.whl
- Upload date:
- Size: 8.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/1.8.3 CPython/3.11.9 Linux/6.5.0-1025-azure
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d6e892c3fce8c7d96121a99d4087235e634f156fab32b94e8a1b31b0edb5c46f
|
|
| MD5 |
8089a3e4d42c004140cb71c8cff01271
|
|
| BLAKE2b-256 |
5e58a218e77aa4d5b6c3f7f767aca9b1fb600f0553cc3d653976f7170de901c7
|