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