# Resultify
This is an opinionated, simplified fork of [dbrgn/result](https://github.com/dbrgn/result).
Result is a simple, type annotated Result type for Python 3.6+ inspired by [Rust](https://doc.rust-lang.org/std/result/).
The idea is that a result value can be either `Ok(value)` or `Err(error)`, with a way to differentiate between the two. `Ok` and `Err` are both classes wrapping an arbitrary value. `Result[T, E]` is a generic type alias for `typing.Union[Ok[T], Err[E]]`.
Requires Python 3.8 or higher!
NB: If you are using a Python version lower than 3.10, you will have to install `typing_extensions`!
### Caveats
Not all [methods](https://doc.rust-lang.org/std/result/enum.Result.html) have been implemented, only the ones that make sense in the Python context. For example, the `map` methods have been omitted, because they don't quite make sense without Rust's pattern matching.
Since Rust's Optional type does not meaningfully translate to Python in a way type checkers are able to understand, `ok()` corresponds to `unwrap()` and `err()` corresponds to `unwrap_err()`. On the other side, you don't have to return semantically unclear tuples anymore.
By using `.is_ok()` and `is_err()` to check for `Ok` or `Err` you get type safe access to the contained value. All of this in a package allowing easier handling of values that can be OK or not, without resorting to custom exceptions.
### API
Creating an instance:
```py
>>> from resultify import Ok, Err
>>> ok = Ok('yay')
>>> res2 = Err('nay')
```
Type safe checking whether a result is `Ok` or `Err`.
```py
>>> res = Ok('yay')
>>> res.is_ok()
True
>>> res.is_err()
False
```
Unwrap a `Result`, or raise if trying to extract a result from an error from a result or vice-versa:
```py
>>> ok = Ok('yay')
>>> err = Err('nay')
>>> ok.ok()
'yay'
>>> ok.err()
resultify.UnwrapError: Cannot unwrap error from Ok: Ok('yay')
>>> err.err()
'nay'
>>> err.ok()
resultify.UnwrapError: Cannot unwrap value from Err: Err('nay')
```
For your convenience, and to appease the type checkers, simply creating an `Ok` result without value is the same as using `True`:
```py
>>> ok = Ok()
>>> ok.ok()
True
```
To easily convert a function to return `Result`, you can use `resultify()`:
```py
>>> from resultify import resultify
>>> @resultify()
... def a():
... return "value"
...
>>> a()
Ok('value')
```
You can similarly auto-capture exceptions using `resultify(...)`. Please note that you can provide multiple exceptions, or none if you don't want to catch the exception! This is primarily useful when modeling code paths with a single good branch and multiple early `raise`s, where one does not have to concern oneself with annoying `try ... catch ...` statements.
```py
>>> @resultify(TypeError)
... def foo():
... raise TypeError()
...
>>> foo()
Err(TypeError())
```
You can `retry` a function that returns a `Result` type with a constant backoff.
```py
>>> from resultify import resultify, retry
... @retry(retries=2, delay=2, initial_delay=1):
... @resultify(Exception)
... def foo():
... # do something that needs retrying here
```
This example waits 1 second before executing the initial call, then attempts the initial call, then executes two retries, spaces out two seconds from the previous call. If any execution was a success, the `Ok` value will be returned. If the retries were exhausted and no `Ok` was returned, we return the `Err` value.
For those running Python 3.10, you can make use of Python's **structural pattern** matching like this:
```py
>>> from resultify import Ok, Err
>>> ok = Ok("ok!")
>>> match ok:
... case Ok(foo): print(f"Yay {foo}")
... case Err(foo): print(f"Nay {foo}")
...
Yay ok!
>>> no = Err("nope!")
>>> match no:
... case Ok(foo): print(f"Yay {foo}")
... case Err(foo): print(f"Nay {foo}")
...
Nay nope!
```
Since documentation always lies, please refer to the unit tests for examples of usage.
### License
MIT License
Raw data
{
"_id": null,
"home_page": "https://github.com/felixhammerl/resultify",
"name": "resultify",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.8",
"maintainer_email": null,
"keywords": "rust result",
"author": "Felix Hammerl",
"author_email": "felix.hammerl@gmail.com",
"download_url": "https://files.pythonhosted.org/packages/59/4c/8baede0e824a3c932bb7f559626ea2d4c487fc3da6cb1f5fd55bb5230815/resultify-1.3.1.tar.gz",
"platform": null,
"description": "# Resultify\n\nThis is an opinionated, simplified fork of [dbrgn/result](https://github.com/dbrgn/result).\n\nResult is a simple, type annotated Result type for Python 3.6+ inspired by [Rust](https://doc.rust-lang.org/std/result/).\n\nThe idea is that a result value can be either `Ok(value)` or `Err(error)`, with a way to differentiate between the two. `Ok` and `Err` are both classes wrapping an arbitrary value. `Result[T, E]` is a generic type alias for `typing.Union[Ok[T], Err[E]]`.\n\nRequires Python 3.8 or higher!\n\nNB: If you are using a Python version lower than 3.10, you will have to install `typing_extensions`!\n\n\n### Caveats\n\nNot all [methods](https://doc.rust-lang.org/std/result/enum.Result.html) have been implemented, only the ones that make sense in the Python context. For example, the `map` methods have been omitted, because they don't quite make sense without Rust's pattern matching.\n\nSince Rust's Optional type does not meaningfully translate to Python in a way type checkers are able to understand, `ok()` corresponds to `unwrap()` and `err()` corresponds to `unwrap_err()`. On the other side, you don't have to return semantically unclear tuples anymore.\n\nBy using `.is_ok()` and `is_err()` to check for `Ok` or `Err` you get type safe access to the contained value. All of this in a package allowing easier handling of values that can be OK or not, without resorting to custom exceptions.\n\n\n### API\n\nCreating an instance:\n\n```py\n>>> from resultify import Ok, Err\n>>> ok = Ok('yay')\n>>> res2 = Err('nay')\n```\n\nType safe checking whether a result is `Ok` or `Err`.\n\n```py\n>>> res = Ok('yay')\n>>> res.is_ok()\nTrue\n>>> res.is_err()\nFalse\n```\n\nUnwrap a `Result`, or raise if trying to extract a result from an error from a result or vice-versa:\n\n```py\n>>> ok = Ok('yay')\n>>> err = Err('nay')\n>>> ok.ok()\n'yay'\n>>> ok.err()\nresultify.UnwrapError: Cannot unwrap error from Ok: Ok('yay')\n>>> err.err()\n'nay'\n>>> err.ok()\nresultify.UnwrapError: Cannot unwrap value from Err: Err('nay')\n```\n\nFor your convenience, and to appease the type checkers, simply creating an `Ok` result without value is the same as using `True`:\n\n```py\n>>> ok = Ok()\n>>> ok.ok()\nTrue\n```\n\nTo easily convert a function to return `Result`, you can use `resultify()`:\n\n```py\n>>> from resultify import resultify\n>>> @resultify()\n... def a():\n... return \"value\"\n...\n>>> a()\nOk('value')\n```\n\nYou can similarly auto-capture exceptions using `resultify(...)`. Please note that you can provide multiple exceptions, or none if you don't want to catch the exception! This is primarily useful when modeling code paths with a single good branch and multiple early `raise`s, where one does not have to concern oneself with annoying `try ... catch ...` statements.\n\n```py\n>>> @resultify(TypeError)\n... def foo():\n... raise TypeError()\n...\n>>> foo()\nErr(TypeError())\n```\n\n\nYou can `retry` a function that returns a `Result` type with a constant backoff.\n\n```py\n>>> from resultify import resultify, retry\n... @retry(retries=2, delay=2, initial_delay=1):\n... @resultify(Exception)\n... def foo():\n... # do something that needs retrying here\n```\n\nThis example waits 1 second before executing the initial call, then attempts the initial call, then executes two retries, spaces out two seconds from the previous call. If any execution was a success, the `Ok` value will be returned. If the retries were exhausted and no `Ok` was returned, we return the `Err` value.\n\nFor those running Python 3.10, you can make use of Python's **structural pattern** matching like this:\n\n```py\n>>> from resultify import Ok, Err\n>>> ok = Ok(\"ok!\")\n>>> match ok:\n... case Ok(foo): print(f\"Yay {foo}\")\n... case Err(foo): print(f\"Nay {foo}\")\n...\nYay ok!\n>>> no = Err(\"nope!\")\n>>> match no:\n... case Ok(foo): print(f\"Yay {foo}\")\n... case Err(foo): print(f\"Nay {foo}\")\n...\nNay nope!\n```\n\n\nSince documentation always lies, please refer to the unit tests for examples of usage.\n\n\n### License\n\nMIT License\n\n",
"bugtrack_url": null,
"license": null,
"summary": "A rust-like result type for Python",
"version": "1.3.1",
"project_urls": {
"Homepage": "https://github.com/felixhammerl/resultify"
},
"split_keywords": [
"rust",
"result"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "7243a9d2c2cdf35e3112c77bef2c577cca64c508c45fa54bc03383a2cfebb134",
"md5": "e8b8892dae5334f7ce34901c951dd5d4",
"sha256": "a74fe4dd02f54e8953539dc32bafe0d9aef72e202fc35e0cb5602e1e778fbbdd"
},
"downloads": -1,
"filename": "resultify-1.3.1-py3-none-any.whl",
"has_sig": false,
"md5_digest": "e8b8892dae5334f7ce34901c951dd5d4",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.8",
"size": 5385,
"upload_time": "2024-07-31T07:50:18",
"upload_time_iso_8601": "2024-07-31T07:50:18.161356Z",
"url": "https://files.pythonhosted.org/packages/72/43/a9d2c2cdf35e3112c77bef2c577cca64c508c45fa54bc03383a2cfebb134/resultify-1.3.1-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "594c8baede0e824a3c932bb7f559626ea2d4c487fc3da6cb1f5fd55bb5230815",
"md5": "15c2ea63fbf2239e315acb8a89b97137",
"sha256": "3988931a97f233340894d7aee22f701b68a5248d5dea2ce1bc882cc585266c5c"
},
"downloads": -1,
"filename": "resultify-1.3.1.tar.gz",
"has_sig": false,
"md5_digest": "15c2ea63fbf2239e315acb8a89b97137",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.8",
"size": 5001,
"upload_time": "2024-07-31T07:50:19",
"upload_time_iso_8601": "2024-07-31T07:50:19.425604Z",
"url": "https://files.pythonhosted.org/packages/59/4c/8baede0e824a3c932bb7f559626ea2d4c487fc3da6cb1f5fd55bb5230815/resultify-1.3.1.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-07-31 07:50:19",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "felixhammerl",
"github_project": "resultify",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"lcname": "resultify"
}