Skip to content

Commit

Permalink
Replace TypeGuard with TypeIs
Browse files Browse the repository at this point in the history
  • Loading branch information
kreathon committed Aug 15, 2024
1 parent f4d5c07 commit f20e323
Show file tree
Hide file tree
Showing 7 changed files with 91 additions and 102 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ Possible log types:

## [Unreleased]

- `[changed]` Improve type narrowing for `is_ok` and `is_err` type guards by
replacing `typing.TypeGuard` with `typing.TypeIs` (#193)

## [0.17.0] - 2024-06-02

- `[added]` Add `inspect()` and `inspect_err()` methods (#185)
Expand Down
21 changes: 0 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -156,27 +156,6 @@ False
True
```

The benefit of `isinstance` is better type checking that type guards currently
do not offer,

```python
res1: Result[int, str] = some_result()
if isinstance(res1, Err):
print("Error...:", res1.err_value) # res1 is narrowed to an Err
return
res1.ok()

res2: Result[int, str] = some_result()
if res1.is_err():
print("Error...:", res2.err_value) # res1 is NOT narrowed to an Err here
return
res1.ok()
```

There is a proposed [PEP 724 – Stricter Type Guards](https://peps.python.org/pep-0724/)
which may allow the `is_ok` and `is_err` type guards to work as expected in
future versions of Python.

Convert a `Result` to the value or `None`:

``` python
Expand Down
4 changes: 2 additions & 2 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@
- [`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
- [`result.is_err`](./result.md#function-is_err): A type guard to check if a result is an Err
- [`result.is_ok`](./result.md#function-is_ok): A type guard to check if a result is an Ok


---
Expand Down
128 changes: 64 additions & 64 deletions docs/result.md

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ classifiers =
[options]
include_package_data = True
install_requires =
typing_extensions;python_version<'3.10'
typing_extensions>=4.10.0;python_version<'3.13'
package_dir =
=src
packages = find:
Expand Down
14 changes: 8 additions & 6 deletions src/result/result.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,12 @@
Union,
)

from typing_extensions import TypeIs

if sys.version_info >= (3, 10):
from typing import ParamSpec, TypeAlias, TypeGuard
from typing import ParamSpec, TypeAlias
else:
from typing_extensions import ParamSpec, TypeAlias, TypeGuard
from typing_extensions import ParamSpec, TypeAlias


T = TypeVar("T", covariant=True) # Success type
Expand Down Expand Up @@ -527,8 +529,8 @@ async def async_wrapper(*args: P.args, **kwargs: P.kwargs) -> Result[R, TBE]:
return decorator


def is_ok(result: Result[T, E]) -> TypeGuard[Ok[T]]:
"""A typeguard to check if a result is an Ok
def is_ok(result: Result[T, E]) -> TypeIs[Ok[T]]:
"""A type guard to check if a result is an Ok
Usage:
Expand All @@ -544,8 +546,8 @@ def is_ok(result: Result[T, E]) -> TypeGuard[Ok[T]]:
return result.is_ok()


def is_err(result: Result[T, E]) -> TypeGuard[Err[E]]:
"""A typeguard to check if a result is an Err
def is_err(result: Result[T, E]) -> TypeIs[Err[E]]:
"""A type guard to check if a result is an Err
Usage:
Expand Down
21 changes: 13 additions & 8 deletions tests/type_checking/test_result.yml
Original file line number Diff line number Diff line change
Expand Up @@ -85,11 +85,16 @@
- case: map_result
disable_cache: false
main: |
from result import Ok, Err, is_ok, is_err
result = Ok(1)
err = Err("error")
if is_ok(result):
reveal_type(result) # N: Revealed type is "result.result.Ok[builtins.int]"
elif is_err(err):
reveal_type(err) # N: Revealed type is "result.result.Err[builtins.str]"
from result import Result, Ok, Err, is_ok, is_err
res1: Result[int, str] = Ok(1)
if is_ok(res1):
reveal_type(res1) # N: Revealed type is "result.result.Ok[builtins.int]"
else:
reveal_type(res1) # N: Revealed type is "result.result.Err[builtins.str]"
res2: Result[int, str] = Err("error")
if is_err(res2):
reveal_type(res2) # N: Revealed type is "result.result.Err[builtins.str]"
else:
reveal_type(res2) # N: Revealed type is "result.result.Ok[builtins.int]"

0 comments on commit f20e323

Please sign in to comment.