resultify


Nameresultify JSON
Version 1.3.1 PyPI version JSON
download
home_pagehttps://github.com/felixhammerl/resultify
SummaryA rust-like result type for Python
upload_time2024-07-31 07:50:19
maintainerNone
docs_urlNone
authorFelix Hammerl
requires_python>=3.8
licenseNone
keywords rust result
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # 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"
}
        
Elapsed time: 0.29684s