From 4d1086da031fc1c56729b5dbcdca0161635c9e36 Mon Sep 17 00:00:00 2001 From: GNUSheep Date: Thu, 28 Dec 2023 11:53:03 +0100 Subject: [PATCH] Resolve errors shown in review --- docs/result.md | 83 ++++++++++++++++++++------------------------ src/result/result.py | 20 ++--------- 2 files changed, 39 insertions(+), 64 deletions(-) diff --git a/docs/result.md b/docs/result.md index def1d59..f156878 100644 --- a/docs/result.md +++ b/docs/result.md @@ -57,20 +57,18 @@ A typeguard to check if a result is an Ok Usage: -```python - +``` python 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` @@ -82,20 +80,18 @@ A typeguard to check if a result is an Err Usage: -```python - +``` python 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` @@ -110,7 +106,6 @@ Do notation for Result (syntactic sugar for sequence of `and_then()` calls). Usage: ``` rust - // This is similar to use do_notation::m; let final_result = m! { @@ -118,17 +113,14 @@ let final_result = m! { y <- Ok(True); Ok(len(x) + int(y) + 0.5) }; - ``` ``` rust - 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. @@ -136,7 +128,7 @@ NOTE: If you exclude the type annotation e.g. `Result[float, int]` your type che --- - + ## function `do_async` @@ -146,48 +138,47 @@ do_async( ) → Result[T, E] ``` -Async version of do. Example: ``` -``` python - -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. - -``` python +Async version of do. Example: -# This is a regular generator: async def foo(): ... do(Ok(1) for x in await foo()) - -``` - -``` python - -# 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()`. +``` python +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() + ) +``` -However, for better usability, it's better for `do_async()` to also accept -regular generators, as you get in the first case: +NOTE: Python makes generators async in a counter-intuitive way. -``` python +``` python +# This is a regular generator: + async def foo(): ... + do(Ok(1) for x in await foo()) +``` -async def foo(): ... do(Ok(1) for x in await foo()) +``` python +# 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()`. -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. +However, for better usability, it's better for `do_async()` to also accept regular generators, as you get in the first case: +``` python +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. + --- diff --git a/src/result/result.py b/src/result/result.py index cb50cb2..06b78b9 100644 --- a/src/result/result.py +++ b/src/result/result.py @@ -506,14 +506,12 @@ def is_ok(result: Result[T, E]) -> TypeGuard[Ok[T]]: Usage: - ```python - + ``` python 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] - ``` """ @@ -525,14 +523,12 @@ def is_err(result: Result[T, E]) -> TypeGuard[Err[E]]: Usage: - ```python - + ``` python 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] - ``` """ @@ -546,7 +542,6 @@ def do(gen: Generator[Result[T, E], None, None]) -> Result[T, E]: Usage: ``` rust - // This is similar to use do_notation::m; let final_result = m! { @@ -554,17 +549,14 @@ def do(gen: Generator[Result[T, E], None, None]) -> Result[T, E]: y <- Ok(True); Ok(len(x) + int(y) + 0.5) }; - ``` ``` rust - 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]` @@ -594,28 +586,23 @@ async def do_async( """Async version of do. Example: ``` python - 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. ``` python - # This is a regular generator: async def foo(): ... do(Ok(1) for x in await foo()) - ``` ``` python - # But this is an async generator: async def foo(): ... async def bar(): ... @@ -624,7 +611,6 @@ async def bar(): ... for x in await foo() for y in await bar() ) - ``` We let users try to use regular `do()`, which works in some cases @@ -636,10 +622,8 @@ async def bar(): ... regular generators, as you get in the first case: ``` python - async def foo(): ... do(Ok(1) for x in await foo()) - ``` Furthermore, neither mypy nor pyright can infer that the second case is