diff --git a/Makefile b/Makefile index 19c18da..840bfc9 100644 --- a/Makefile +++ b/Makefile @@ -23,3 +23,9 @@ lint-mypy: phony test: phony pytest + +docs: phony + lazydocs \ + --overview-file README.md \ + --src-base-url https://github.com/rustedpy/result/blob/master/ \ + ./src/result diff --git a/README.md b/README.md index 9f0888b..3ee61a1 100644 --- a/README.md +++ b/README.md @@ -106,6 +106,9 @@ exceptions. ## API +Auto generated API docs are also available at +[./docs/README.md](./docs/README.md). + Creating an instance: ``` python @@ -434,7 +437,11 @@ from the non-unix shell you're using on Windows. - `make test` - `make lint` - You can also start a Python REPL and import `result` -5. Git commit and create a new PR. +5. Update documentation + - Edit any relevant docstrings, markdown files + - Run `make docs` +6. Add an entry to the [changelog](./CHANGELOG.md) +5. Git commit all your changes and create a new PR. [pydocs-venv]: https://docs.python.org/3/library/venv.html diff --git a/docs/.pages b/docs/.pages new file mode 100644 index 0000000..db48efa --- /dev/null +++ b/docs/.pages @@ -0,0 +1,4 @@ +title: API Reference +nav: + - Overview: README.md + - ... diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000..3b123fb --- /dev/null +++ b/docs/README.md @@ -0,0 +1,28 @@ + + +# API Overview + +## Modules + +- [`result`](./result.md#module-result) + +## Classes + +- [`result.DoException`](./result.md#class-doexception): This is used to signal to `do()` that the result is an `Err`, +- [`result.Err`](./result.md#class-err): A value that signifies failure and which stores arbitrary data for the error. +- [`result.Ok`](./result.md#class-ok): A value that indicates success and which stores arbitrary data for the return value. +- [`result.UnwrapError`](./result.md#class-unwraperror): Exception raised from ``.unwrap_<...>`` and ``.expect_<...>`` calls. + +## Functions + +- [`result.as_async_result`](./result.md#function-as_async_result): Make a decorator to turn an async function into one that returns a ``Result``. +- [`result.as_result`](./result.md#function-as_result): Make a decorator to turn a function into one that returns a ``Result``. +- [`result.do`](./result.md#function-do): Do notation for Result (syntactic sugar for sequence of `and_then()` calls). +- [`result.do_async`](./result.md#function-do_async): Async version of do. Example: +- [`result.is_err`](./result.md#function-is_err): A typeguard to check if a result is an Err +- [`result.is_ok`](./result.md#function-is_ok): A typeguard to check if a result is an Ok + + +--- + +_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/docs/result.md b/docs/result.md new file mode 100644 index 0000000..639f918 --- /dev/null +++ b/docs/result.md @@ -0,0 +1,758 @@ + + + + +# module `result` + + + + +**Global Variables** +--------------- +- **OkErr** + +--- + + + +## function `as_result` + +```python +as_result( + *exceptions: 'Type[TBE]' +) → Callable[[Callable[P, R]], Callable[P, Result[R, TBE]]] +``` + +Make a decorator to turn a function into one that returns a ``Result``. + +Regular return values are turned into ``Ok(return_value)``. Raised exceptions of the specified exception type(s) are turned into ``Err(exc)``. + + +--- + + + +## function `as_async_result` + +```python +as_async_result( + *exceptions: 'Type[TBE]' +) → Callable[[Callable[P, Awaitable[R]]], Callable[P, Awaitable[Result[R, TBE]]]] +``` + +Make a decorator to turn an async function into one that returns a ``Result``. Regular return values are turned into ``Ok(return_value)``. Raised exceptions of the specified exception type(s) are turned into ``Err(exc)``. + + +--- + + + +## function `is_ok` + +```python +is_ok(result: 'Result[T, E]') → TypeGuard[Ok[T]] +``` + +A typeguard to check if a result is an Ok + +Usage: ``` r: Result[int, str] = get_a_result()``` +``` if is_ok(r):``` ``` r # r is of type Ok[int]``` +``` elif is_err(r):``` ``` r # r is of type Err[str]``` + + + +--- + + + +## function `is_err` + +```python +is_err(result: 'Result[T, E]') → TypeGuard[Err[E]] +``` + +A typeguard to check if a result is an Err + +Usage: ``` r: Result[int, str] = get_a_result()``` +``` if is_ok(r):``` ``` r # r is of type Ok[int]``` +``` elif is_err(r):``` ``` r # r is of type Err[str]``` + + + +--- + + + +## function `do` + +```python +do(gen: 'Generator[Result[T, E], None, None]') → Result[T, E] +``` + +Do notation for Result (syntactic sugar for sequence of `and_then()` calls). + + + +Usage: ``` # This is similar to``` +use do_notation::m; +let final_result = m! { + x <- Ok("hello"); + y <- Ok(True); + Ok(len(x) + int(y) + 0.5) +}; + +``` final_result: Result[float, int] = do(``` Ok(len(x) + int(y) + 0.5) for x in Ok("hello") for y in Ok(True) ) + +NOTE: If you exclude the type annotation e.g. `Result[float, int]` your type checker might be unable to infer the return type. To avoid an error, you might need to help it with the type hint. + + +--- + + + +## function `do_async` + +```python +do_async( + gen: 'Union[Generator[Result[T, E], None, None], AsyncGenerator[Result[T, E], None]]' +) → Result[T, E] +``` + +Async version of do. Example: + +``` final_result: Result[float, int] = await do_async(``` + Ok(len(x) + int(y) + z) + for x in await get_async_result_1() + for y in await get_async_result_2() + for z in get_sync_result_3() + ) + +NOTE: Python makes generators async in a counter-intuitive way. +This is a regular generator: + async def foo(): ... + do(Ok(1) for x in await foo()) + +But this is an async generator: + async def foo(): ... + async def bar(): ... + do( + Ok(1) + for x in await foo() + for y in await bar() + ) + +We let users try to use regular `do()`, which works in some cases +of awaiting async values. If we hit a case like above, we raise +an exception telling the user to use `do_async()` instead. +See `do()`. + +However, for better usability, it's better for `do_async()` to also accept +regular generators, as you get in the first case: + +async def foo(): ... + do(Ok(1) for x in await foo()) + +Furthermore, neither mypy nor pyright can infer that the second case is +actually an async generator, so we cannot annotate `do_async()` +as accepting only an async generator. This is additional motivation +to accept either. + + + +--- + + + +## class `Ok` +A value that indicates success and which stores arbitrary data for the return value. + + + +### method `__init__` + +```python +__init__(value: 'T') → None +``` + + + + + + +--- + +#### property ok_value + +Return the inner value. + +--- + +#### property value + +Return the inner value. + +@deprecated Use `ok_value` or `err_value` instead. This method will be removed in a future version. + + + +--- + + + +### method `and_then` + +```python +and_then(op: 'Callable[[T], Result[U, E]]') → Result[U, E] +``` + +The contained result is `Ok`, so return the result of `op` with the original value passed in + +--- + + + +### method `and_then_async` + +```python +and_then_async(op: 'Callable[[T], Awaitable[Result[U, E]]]') → Result[U, E] +``` + +The contained result is `Ok`, so return the result of `op` with the original value passed in + +--- + + + +### method `err` + +```python +err() → None +``` + +Return `None`. + +--- + + + +### method `expect` + +```python +expect(_message: 'str') → T +``` + +Return the value. + +--- + + + +### method `expect_err` + +```python +expect_err(message: 'str') → NoReturn +``` + +Raise an UnwrapError since this type is `Ok` + +--- + + + +### method `is_err` + +```python +is_err() → Literal[False] +``` + + + + + +--- + + + +### method `is_ok` + +```python +is_ok() → Literal[True] +``` + + + + + +--- + + + +### method `map` + +```python +map(op: 'Callable[[T], U]') → Ok[U] +``` + +The contained result is `Ok`, so return `Ok` with original value mapped to a new value using the passed in function. + +--- + + + +### method `map_async` + +```python +map_async(op: 'Callable[[T], Awaitable[U]]') → Ok[U] +``` + +The contained result is `Ok`, so return the result of `op` with the original value passed in + +--- + + + +### method `map_err` + +```python +map_err(op: 'object') → Ok[T] +``` + +The contained result is `Ok`, so return `Ok` with the original value + +--- + + + +### method `map_or` + +```python +map_or(default: 'object', op: 'Callable[[T], U]') → U +``` + +The contained result is `Ok`, so return the original value mapped to a new value using the passed in function. + +--- + + + +### method `map_or_else` + +```python +map_or_else(default_op: 'object', op: 'Callable[[T], U]') → U +``` + +The contained result is `Ok`, so return original value mapped to a new value using the passed in `op` function. + +--- + + + +### method `ok` + +```python +ok() → T +``` + +Return the value. + +--- + + + +### method `or_else` + +```python +or_else(op: 'object') → Ok[T] +``` + +The contained result is `Ok`, so return `Ok` with the original value + +--- + + + +### method `unwrap` + +```python +unwrap() → T +``` + +Return the value. + +--- + + + +### method `unwrap_err` + +```python +unwrap_err() → NoReturn +``` + +Raise an UnwrapError since this type is `Ok` + +--- + + + +### method `unwrap_or` + +```python +unwrap_or(_default: 'U') → T +``` + +Return the value. + +--- + + + +### method `unwrap_or_else` + +```python +unwrap_or_else(op: 'object') → T +``` + +Return the value. + +--- + + + +### method `unwrap_or_raise` + +```python +unwrap_or_raise(e: 'object') → T +``` + +Return the value. + + +--- + + + +## class `DoException` +This is used to signal to `do()` that the result is an `Err`, which short-circuits the generator and returns that Err. Using this exception for control flow in `do()` allows us to simulate `and_then()` in the Err case: namely, we don't call `op`, we just return `self` (the Err). + + + +### method `__init__` + +```python +__init__(err: 'Err[E]') → None +``` + + + + + + + + + +--- + + + +## class `Err` +A value that signifies failure and which stores arbitrary data for the error. + + + +### method `__init__` + +```python +__init__(value: 'E') → None +``` + + + + + + +--- + +#### property err_value + +Return the inner value. + +--- + +#### property value + +Return the inner value. + +@deprecated Use `ok_value` or `err_value` instead. This method will be removed in a future version. + + + +--- + + + +### method `and_then` + +```python +and_then(op: 'object') → Err[E] +``` + +The contained result is `Err`, so return `Err` with the original value + +--- + + + +### method `and_then_async` + +```python +and_then_async(op: 'object') → Err[E] +``` + +The contained result is `Err`, so return `Err` with the original value + +--- + + + +### method `err` + +```python +err() → E +``` + +Return the error. + +--- + + + +### method `expect` + +```python +expect(message: 'str') → NoReturn +``` + +Raises an `UnwrapError`. + +--- + + + +### method `expect_err` + +```python +expect_err(_message: 'str') → E +``` + +Return the inner value + +--- + + + +### method `is_err` + +```python +is_err() → Literal[True] +``` + + + + + +--- + + + +### method `is_ok` + +```python +is_ok() → Literal[False] +``` + + + + + +--- + + + +### method `map` + +```python +map(op: 'object') → Err[E] +``` + +Return `Err` with the same value + +--- + + + +### method `map_async` + +```python +map_async(op: 'object') → Err[E] +``` + +The contained result is `Ok`, so return the result of `op` with the original value passed in + +--- + + + +### method `map_err` + +```python +map_err(op: 'Callable[[E], F]') → Err[F] +``` + +The contained result is `Err`, so return `Err` with original error mapped to a new value using the passed in function. + +--- + + + +### method `map_or` + +```python +map_or(default: 'U', op: 'object') → U +``` + +Return the default value + +--- + + + +### method `map_or_else` + +```python +map_or_else(default_op: 'Callable[[], U]', op: 'object') → U +``` + +Return the result of the default operation + +--- + + + +### method `ok` + +```python +ok() → None +``` + +Return `None`. + +--- + + + +### method `or_else` + +```python +or_else(op: 'Callable[[E], Result[T, F]]') → Result[T, F] +``` + +The contained result is `Err`, so return the result of `op` with the original value passed in + +--- + + + +### method `unwrap` + +```python +unwrap() → NoReturn +``` + +Raises an `UnwrapError`. + +--- + + + +### method `unwrap_err` + +```python +unwrap_err() → E +``` + +Return the inner value + +--- + + + +### method `unwrap_or` + +```python +unwrap_or(default: 'U') → U +``` + +Return `default`. + +--- + + + +### method `unwrap_or_else` + +```python +unwrap_or_else(op: 'Callable[[E], T]') → T +``` + +The contained result is ``Err``, so return the result of applying ``op`` to the error value. + +--- + + + +### method `unwrap_or_raise` + +```python +unwrap_or_raise(e: 'Type[TBE]') → NoReturn +``` + +The contained result is ``Err``, so raise the exception with the value. + + +--- + + + +## class `UnwrapError` +Exception raised from ``.unwrap_<...>`` and ``.expect_<...>`` calls. + +The original ``Result`` can be accessed via the ``.result`` attribute, but this is not intended for regular use, as type information is lost: ``UnwrapError`` doesn't know about both ``T`` and ``E``, since it's raised from ``Ok()`` or ``Err()`` which only knows about either ``T`` or ``E``, not both. + + + +### method `__init__` + +```python +__init__(result: 'Result[object, object]', message: 'str') → None +``` + + + + + + +--- + +#### property result + +Returns the original result. + + + + + + +--- + +_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/requirements-dev.txt b/requirements-dev.txt index 259b0fb..7e9ecef 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -6,3 +6,4 @@ pytest-cov mypy pytest-mypy-plugins pytest-asyncio +lazydocs