From 8a47e136c3934e278830f98684f6709b2dbc3103 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antonio=20Jos=C3=A9=20Checa=20Bustos?= Date: Mon, 2 Sep 2024 13:20:49 +0200 Subject: [PATCH] Add static method from_optional (#20) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add static method from_optional * Move Option.from_optional to option_from function. * Fix mypy List typing. * Update prelude.py Undo remove line jump. * Remove incompatible generic type on option_from. * Update codecov action and include token. --------- Co-authored-by: Álex Cabeza Romero --- .github/workflows/ci.yml | 6 ++++-- examples/patmat_option.py | 3 ++- rusty_results/prelude.py | 14 ++++++++++++-- rusty_results/tests/option/test_option.py | 13 +++++++++++++ 4 files changed, 31 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 55d63ba..e82dad0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -36,7 +36,9 @@ jobs: - name: Build coverage file run: pytest --cache-clear --cov=rusty_results --cov-report=xml:pytest-coverage.xml ./rusty_results - name: Upload coverage to Codecov - uses: codecov/codecov-action@v1 + uses: codecov/codecov-action@v4 + env: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} with: files: ./pytest-coverage.xml - fail_ci_if_error: true \ No newline at end of file + fail_ci_if_error: true diff --git a/examples/patmat_option.py b/examples/patmat_option.py index ff5fc10..cabe62f 100644 --- a/examples/patmat_option.py +++ b/examples/patmat_option.py @@ -1,11 +1,12 @@ """ Example on pattern matching handling of Option """ +from typing import List from rusty_results import Option, Some, Empty -def find_index(l: [str], value: str) -> Option[int]: +def find_index(l: List[str], value: str) -> Option[int]: for i, e in enumerate(l): if e == value: return Some(i) diff --git a/rusty_results/prelude.py b/rusty_results/prelude.py index a555ecf..ccc4161 100644 --- a/rusty_results/prelude.py +++ b/rusty_results/prelude.py @@ -1,6 +1,6 @@ from abc import abstractmethod from dataclasses import dataclass -from typing import cast, TypeVar, Union, Callable, Generic, Iterator, Tuple, Dict, Any +from typing import cast, TypeVar, Union, Callable, Generic, Iterator, Tuple, Dict, Any, Optional from rusty_results.exceptions import UnwrapException, EarlyReturnException try: @@ -540,6 +540,16 @@ def __get_validators__(cls): Option = Union[Some[T], Empty] +def option_from(value: Optional[T]) -> Option[T]: + """ + :param value: Value from any type to be converted to an Option + :return: The value wrapped in an Option or the original Option if it is already an Option + """ + if value is None: + return Empty() + return Some(value).flatten_one() + + class ResultProtocol(Generic[T, E]): @property @abstractmethod @@ -1043,4 +1053,4 @@ def __get_validators__(cls): yield from ResultProtocol.__get_validators__() -Result = Union[Ok[T, E], Err[T, E]] \ No newline at end of file +Result = Union[Ok[T, E], Err[T, E]] diff --git a/rusty_results/tests/option/test_option.py b/rusty_results/tests/option/test_option.py index 30d860c..3d53e15 100644 --- a/rusty_results/tests/option/test_option.py +++ b/rusty_results/tests/option/test_option.py @@ -32,3 +32,16 @@ def test_option_contains(): def test_option_iter(): assert list(iter(Empty())) == [] assert list(iter(Some(1))) == [1] + + +def test_option_from(): + assert Some(0) == option_from(0) + assert Empty() == option_from(None) + example_dictionary = {"data": 5} + assert Empty() == option_from(example_dictionary.get("key_not_found")) + assert Some(5) == option_from(example_dictionary.get("data")) + opt = Some(3) + assert opt == option_from(opt) + assert Empty() == option_from(Empty()) + nested_opt = Some(Some(Some(Some(3)))) + assert nested_opt == option_from(nested_opt)