Skip to content

Commit

Permalink
Added success_handler and failure_handler when unwrap values with Res…
Browse files Browse the repository at this point in the history
…ult handle function. Improved Error string representation
  • Loading branch information
acostapazo committed Dec 18, 2019
1 parent 919b3ab commit 39d606f
Show file tree
Hide file tree
Showing 7 changed files with 125 additions and 7 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -79,3 +79,4 @@ target/

*.idea
.pytest_cache
upload_to_pypi.sh
35 changes: 33 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -198,9 +198,25 @@ Result[status: success | value: Rosalia]
Rosalia
```

On the other hand, if something wrong happens handle function will raise an Exception (ReturnErrorOnFailure)
In addition, you can call another function depending on the result with the optional parameters **success_handler** and **failure_handler**.

```python
def success_handler():
print("Do my successful stuff here!")

def failure_handler():
print("Do my failure stuff here!")


result = string_from_key(dictionary=user_info, key="first_name")

result.handle(success_handler=success_handler, failure_handler=failure_handler)
```


On the other hand, if something wrong happens handle function will raise an Exception (ReturnErrorOnFailure).
Meiga has available a decorator to allow to handle the exception in case of error and unwrap the value in case of success.

Additionally, handle a Result with the meiga decorator allows to return a typed error when a sub-function fails.

```python
from meiga import Result, Error
Expand All @@ -217,6 +233,21 @@ def handling_result(key: str) -> Result:

If key is valid success value would be returned. Otherwise, an Error would be returned.


```python
from meiga import Result, Error
from meiga.decorators import meiga

@meiga
def handling_result(key: str) -> Result:
user_info = {"first_name": "Rosalia", "last_name": "De Castro", "age": 60}
first_name = string_from_key(dictionary=user_info, key=key).handle()
# Do whatever with the name
name = first_name.lower()
return Result(success=name)
```


### Assertions

To help us on testing functions that returns Result, meiga provide us two functions: **assert_success** and **access_failure**.
Expand Down
6 changes: 5 additions & 1 deletion meiga/error.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,8 @@ def __eq__(self, other):
return False

def __repr__(self):
return f"Error: {self.__class__.__name__}"
suffix = ""
if hasattr(self, "message"):
suffix = f": {self.message}"

return f"{self.__class__.__name__}{suffix}"
12 changes: 9 additions & 3 deletions meiga/result.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import TypeVar, Generic, Any
from typing import TypeVar, Generic, Any, Callable

from meiga.no_given_value import NoGivenValue, NoGivenValueClass
from meiga.return_error_on_failure import ReturnErrorOnFailure
Expand All @@ -17,7 +17,7 @@ def __init__(self, success: TS = NoGivenValue, failure: TF = NoGivenValue) -> No

def __repr__(self):
status = "failure"
value = self.value.__class__.__name__
value = self.value.__repr__()
if self._is_success:
status = "success"
value = self.value
Expand Down Expand Up @@ -61,10 +61,16 @@ def is_success(self):
def is_failure(self):
return not self._is_success

def handle(self) -> Any:
def handle(
self, success_handler: Callable = None, failure_handler: Callable = None
) -> Any:
if not self._is_success:
if failure_handler:
failure_handler()
raise ReturnErrorOnFailure(self)
else:
if success_handler:
success_handler()
return self._value_success

value = property(get_value)
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

CURRENT_DIR = os.path.abspath(os.path.dirname(__file__))
PACKAGE_NAME = "meiga"
VERSION = "0.1.1"
VERSION = "0.1.2"

# The text of the README file
with open(os.path.join(CURRENT_DIR, "README.md")) as fid:
Expand Down
27 changes: 27 additions & 0 deletions tests/unit/test_error.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import pytest

from meiga import Result, Error


@pytest.mark.unit
def test_should_repr_as_expected_default_error():

result = Result(failure=Error())

assert "Result[status: failure | value: Error]" == result.__repr__()


@pytest.mark.unit
def test_should_repr_as_expected_an_error_with_message():
given_any_message = "any message"

class ErrorWithMessage(Error):
def __init__(self, message: str):
self.message = message

result = Result(failure=ErrorWithMessage(given_any_message))

assert (
f"Result[status: failure | value: ErrorWithMessage: {given_any_message}]"
== result.__repr__()
)
49 changes: 49 additions & 0 deletions tests/unit/test_result.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import pytest

from meiga import Result, Error
from meiga.return_error_on_failure import ReturnErrorOnFailure


@pytest.mark.unit
Expand Down Expand Up @@ -108,3 +109,51 @@ def test_should_eq_two_different_failure_result():
result_2 = Result(failure=Exception())

assert result_1 != result_2


@pytest.mark.unit
def test_should_execute_success_handler():
global called_success_handler
called_success_handler = False

global called_failure_handler
called_failure_handler = False

def success_handler():
global called_success_handler
called_success_handler = True

def failure_handler():
global called_failure_handler
called_failure_handler = True

result = Result(success="Hi!")
result.handle(success_handler=success_handler, failure_handler=failure_handler)

assert called_success_handler is True
assert called_failure_handler is False


@pytest.mark.unit
def test_should_execute_failure_handler():
global called_success_handler
called_success_handler = False

global called_failure_handler
called_failure_handler = False

def success_handler():
global called_success_handler
called_success_handler = True

def failure_handler():
global called_failure_handler
called_failure_handler = True

result = Result(failure=Error())

with pytest.raises(ReturnErrorOnFailure):
result.handle(success_handler=success_handler, failure_handler=failure_handler)

assert called_success_handler is False
assert called_failure_handler is True

0 comments on commit 39d606f

Please sign in to comment.