🧙 A simple, typed and monad-based Result type for Python.

Overview

meiga 🧙 version ci pypi

A simple, typed and monad-based Result type for Python.

Table of Contents

Installation 💻

pip install meiga

Getting Started 📈

meiga 🧙 provides a simple and clear way of handling errors in Python without using Exceptions. This package can help you to dry your code helping on modeling the output of your classes and method.

This package provides a new type class, the Result[Type, Type] This Result type allows to simplify a wide range of problems, like handling potential undefined values, or reduce complexity handling exceptions. Additionally, code can be simplified following a semantic pipeline reducing the visual noise of checking data types, controlling runtime flow and side-effects.

This package is based in another solutions from another modern languages as this swift-based Result implementation.

Example

The best way to illustrate how meiga can help you is with an example.

Consider the following example of a function that tries to extract a String (str) for a given key from a Dict.

from meiga import Result, Error


class NoSuchKey(Error):
    pass


class TypeMismatch(Error):
    pass


def string_from_key(dictionary: dict, key: str) -> Result[str, Error]:
    if key not in dictionary.keys():
        return Result(failure=NoSuchKey())

    value = dictionary[key]
    if not isinstance(value, str):
        return Result(failure=TypeMismatch())

    return Result(success=value)

Returned value Result type provides a robust wrapper around the functions and methods. Rather than throw an exception, it returns a Result that either contains the str value for the given key, or an typed Error detailing what went wrong (Result[str, Error]).

Features

Result

Result[T, Error] 👉 A discriminated union that encapsulates successful outcome with a value of type T or a failure with an arbitrary Error exception.

Functions

Functions Definition
throw() Throws the encapsulated failure value if this instance derive from Error or BaseException.
unwrap() Returns the encapsulated value if this instance represents success or None if it is failure.
unwrap_or_throw() Returns the encapsulated value if this instance represents success or throws the encapsulated exception if it is failure.
unwrap_or_return() Returns the encapsulated value if this instance represents success or return Result as long as @meiga decorator wraps the function.
unwrap_or(failure_value) Returns the encapsulated value if this instance represents success or the selected failure_value if it is failure.
unwrap_or_else(on_failure) Returns the encapsulated value if this instance represents success or execute the on_failure function when it is failure.
unwrap_and(on_success) Returns the encapsulated value if this instance represents success and execute the on_success function when it is success.
handle(on_success,on_failure) Returns itself and execute the on_successfunction when the instance represemts success and the on_failure function when it is failure.
map(transform) Returns a transformed result applying transform function applied to encapsulated value if this instance represents success or failure

Properties

Properties Definition
value Returns the encapsulated value whether it's success or failure
is_success Returns true if this instance represents successful outcome. In this case is_failure returns false.
is_failure Returns true if this instance represents failed outcome. In this case is_success returns false

Let's image we have a dictionary that represent a user info data

>>> user_info = {"first_name": "Rosalia", "last_name": "De Castro", "age": 60}

And we try to obtain first_name

>>> result = string_from_key(dictionary=user_info, key="first_name")
Result[status: success | value: Rosalia]

You can check the status of the result

>>> result.is_success
True
>>> result.is_failure
False

If the result is a success you can get the expected value

>>> result.value
Rosalia 

Otherwise, if we try to access an invalid key or a non string value, returned result will be a failure.

>>> result = string_from_key(dictionary=user_info, key="invalid_key")
Result[status: failure | value: NoSuchKey]
>>> result.is_failure
True
>>> result.value
NoSuchKey() // Error 

Or

>>> result = string_from_key(dictionary=user_info, key="age")
Result[status: failure | value: TypeMismatch]
>>> result.is_failure
True
>>> result.value
TypeMismatch() // Error 

Alias

Use meiga aliases to improve the semantics of your code.

For success result you can use:

result = Result(success="Rosalia")
result = Success("Rosalia") # it is equivalent

If return value is a bool you can use:

result = Success()
result = Success(True)
result = isSuccess

For failure results:

class NoSuchKey(Error):
    pass

result = Result(failure=NoSuchKey())
result = Failure(NoSuchKey())

If you don't want to specify the error, you can use default value with:

result = Failure()
result = Failure(Error())
result = isFailure # Only valid for a failure result with non-specific Error() value

Bringing previous example back. that is the way you can use the alias:

from meiga import Result, Error, Success, Failure,


class NoSuchKey(Error):
    pass


class TypeMismatch(Error):
    pass


def string_from_key(dictionary: dict, key: str) -> Result[str, Error]:
    if key not in dictionary.keys():
        return Failure(NoSuchKey())

    value = dictionary[key]
    if not isinstance(value, str):
        return Failure(TypeMismatch())

    return Success(value)

Furthermore, there is a available a useful alias: NotImplementedMethodError

Use it when define abstract method that returns Result type

from meiga import Result, Error, NotImplementedMethodError

from abc import ABCMeta, abstractmethod

class AuthService:

    __metaclass__ = ABCMeta

    @abstractmethod
    def __init__(self, base_url: str):
        self.base_url = base_url

    @abstractmethod
    def create_token(self, client: str, client_id: str) -> Result[str, Error]:
        return NotImplementedMethodError

Advance Usage 🚀

Decorator

Use @meiga as a decorator to protect your results and prevent from unexpected exceptions. It allways returns a Result object.

@meiga
def create_user(user_id: UserId) -> BoolResult:
     user = user_creator.execute(user_id).unwrap_or_return()
     return repository.save(user)

When decorate staticmethod and classmethod check the order, otherwise it will raise an error (UnexpectedDecorationOrderError) as these kind of methods are not callable

class UserCreatorFactory:

    @staticmethod
    @meiga
    def from_version(version: str) -> Result[UserCreator, Error]:
        if version == "migration_v1":
            creator = UserCreator.build()
        else:
            creator = LegacyUserCreator.build()
        return Success(creator)

Unwrap Result

If you wrap a Result object, its will return a valid value if it is success. Otherwise, it will return None.

result = Result(success="Hi!")
value = result.unwrap()
assert value == "Hi!"

result = Failure(Error())
value = result.unwrap()

assert value is None

You can use unwrap_or_returnin combination with @meiga decorator. If something wrong happens unwraping your Result, the unwrap_or_return function will raise an Exception (ReturnErrorOnFailure). @meiga decorator allows to handle the exception in case of error and unwrap the value in case of success. The following example illustrate this:

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).unwrap_or_return() 
    # Do whatever with the name
    name = first_name.lower()
    return Result(success=name)

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

If you need to return a specific value if fails, you can do it with meiga:

first_name = string_from_key(dictionary=user_info, key=key).unwrap_or_return(return_value_on_failure=isSuccess) 

Handle Result

This framework also allows a method for handling Result type. handle method returns itself and execute the on_success function when the instance represemts success and the on_failure function when it is failure.

When the operations is executed with its happy path, handle function returns the success value, as with result.value.

>>> result = string_from_key(dictionary=user_info, key="first_name")
Result[status: success | value: Rosalia]
>>> first_name = result.handle()
Rosalia

In addition, you can call another function after evaluate the result. Use optional parameters success_handler and failure_handler (Callable functions).

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(on_success=success_handler, on_failure=failure_handler)
Additional parameters

If you need to add some arguments as a parameters, use success_args and failure_args:

def success_handler(param_1):
    print(f"param_1: {param_1}")

def failure_handler(param_1, param_2):
    print(f"param_1: {param_1}")
    print(f"param_2: {param_2}")


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

result.handle(on_success=success_handler, 
              on_failure=failure_handler,
              success_args=1,
              failure_args=(1, 2))
Additional parameters in combination with the Result itself

Sometimes a handle function will need information about external parameters and also about the result itself. Now, is possible this combination thanks to Result.__id__ identifier.

    parameters = (1, Result.__id__, 2)

    def on_success(param_1: int, result: Result, param_2: int):
        assert param_1 == 1
        assert isinstance(result, Result)
        assert result.value is True
        assert param_2 == 2

    def on_failure(param_1: int, result: Result, param_2: int):
        assert param_1 == 1
        assert isinstance(result, Result)
        assert result.value == Error()
        assert param_2 == 2

    @meiga
    def run():
        result.handle(
            on_success=on_success,
            on_failure=on_failure,
            success_args=parameters,
            failure_args=parameters,
        )

    run()

Test Assertions

To help us on testing functions that returns Result, meiga provide us two functions: assert_success and access_failure.

Check the following pytest-based test for more information: tests/unit/test_result_assertions.py

Contact 📬

[email protected]

Comments
  • Enable match pattern [PEP 636 – Structural Pattern Matching]

    Enable match pattern [PEP 636 – Structural Pattern Matching]

    First Check

    • [X] I added a very descriptive title to this issue.
    • [X] I used the GitHub search to find a similar issue and didn't find it.
    • [X] I already read and followed all the documentation and didn't find an answer.

    Description & Wanted Solution

    Now, we have two ways to handle results:

    Checking the state of the result:

    from meiga import Result
    
    my_result = Result(success=True)
    
    if my_result.is_success:
           print("Success")
    else:
      if isinstance(my_result.value, NotUserFoundError)
           print("Failure: Not User Found")
      elif isinstance(my_result.value, AlreadyExistError)
           print("Failure: Already exist")
    

    Or using handlers:

    from meiga import OnSuccessHandler, OnFailureHandler
    
    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(
        on_success_handler=OnSuccessHandler(func=success_handler),
        on_failure_handler=OnFailureHandler(func=failure_handler)
    )
    

    I'd be nice to take advantage of new PEP 636 to handle and react to results

    Wanted Code

    from meiga import Result
    
    my_result = Result(success=True)
    
    match my_result:
       case Success(_):
           print("Success")
       case Failure(NotUserFoundError):
           print("Failure: Not User Found")
       case Failure(AlreadyExistError):
           print("Failure: Already exist")
    

    Alternatives

    No response

    Additional Context

    No response

    enhancement 
    opened by acostapazo 2
  • Import failing in 1.6.0 due to missing module

    Import failing in 1.6.0 due to missing module

    ❯ python3 -m venv venv
    ❯ . venv/bin/activate
    ❯ pip install meiga
    Collecting meiga
      Downloading meiga-1.6.0-py3-none-any.whl (13 kB)
    Installing collected packages: meiga
    Successfully installed meiga-1.6.0
    ❯ python3
    Python 3.10.5 (main, Aug  1 2022, 07:53:20) [GCC 12.1.0] on linux
    Type "help", "copyright", "credits" or "license" for more information.
    >>> from meiga import Error, Success, Failure, Result
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "/tmp/mmm/venv/lib/python3.10/site-packages/meiga/__init__.py", line 3, in <module>
        from meiga import public_api
      File "/tmp/mmm/venv/lib/python3.10/site-packages/meiga/public_api.py", line 6, in <module>
        from . import decorators
      File "/tmp/mmm/venv/lib/python3.10/site-packages/meiga/decorators/__init__.py", line 1, in <module>
        from .meiga_decorator import meiga
      File "/tmp/mmm/venv/lib/python3.10/site-packages/meiga/decorators/meiga_decorator.py", line 4, in <module>
        from typing_extensions import ParamSpec
    ModuleNotFoundError: No module named 'typing_extensions'
    

    1.5.1 works fine:

    ❯ pip install meiga==1.5.1
    Collecting meiga==1.5.1
      Downloading meiga-1.5.1-py3-none-any.whl (12 kB)
    Installing collected packages: meiga
      Attempting uninstall: meiga
        Found existing installation: meiga 1.6.0
        Uninstalling meiga-1.6.0:
          Successfully uninstalled meiga-1.6.0
    Successfully installed meiga-1.5.1
    ❯ python3
    Python 3.10.5 (main, Aug  1 2022, 07:53:20) [GCC 12.1.0] on linux
    Type "help", "copyright", "credits" or "license" for more information.
    >>> from meiga import Error, Success, Failure, Result
    >>> 
    

    Broken on both python 3.10 and 3.9 (caught that one in CI), seemingly by #27 .

    I presume like there should be an optional dependency typing-extensions for py < 3.10, and for 3.10 and above ParamSpec should be imported from typing instead - from my understanding, said typehint got merged from extensions into stdlib in 3.10 release.


    FYI: if you look at the GHA run corresponding to #27 https://github.com/alice-biometrics/meiga/runs/7740328032?check_suite_focus=true , typing-extensions is actually installed there as a dependency of lume:

    Run pip install lume
    Collecting lume
      Using cached lume-0.9.2-py3-none-any.whl (33 kB)
    ...
    Collecting typing-extensions>=3.7.4.3
    

    This is how it leaked to production.

    bug 
    opened by Artalus 2
  • Better typing on Derived Callables [Handlers]

    Better typing on Derived Callables [Handlers]

    meiga has available some method to define derived actions depending on the result value

    Example:

        def handle(
            self,
            on_success: Optional[Callable[..., None]] = None,
            on_failure: Optional[Callable[..., None]] = None,
            success_args: Optional[Any] = None,
            failure_args: Optional[Any] = None,
        ) -> "Result":
            if on_failure:
                self.unwrap_or_else(on_failure, failure_args)
            if on_success:
                self.unwrap_and(on_success, success_args)
            return self
    

    It should be useful to have typed the Callable input with the same type as the _args variable.

    First Attempt

    We've tried some alternatives to link the Callable input parameters to those of the arguments that we pass in (e.g success_args)

    from typing import ParamSpec
    
    PS = ParamSpec("PS")
    
    def unwrap_and(self, on_success: Callable[PS, None], success_args: Optional[PS] = None)
    

    unfortunately, we have not yet found a solution in this regard.

    Breaking Change Proposal/Alternative

    Perhaps the derived actions should have their own class to be more cohesive semantically. For example:

    from typing import Callable, Iterable
    
    class DerivedAction:
    
        def __init__(self, func: Callable[..., None], args: Iterable = None):
            self.func = func
            self.args = args
    
    
    class OnSuccessAction(DerivedAction):
        ...
    
    
    class OnFailureAction(DerivedAction):
        ...
    

    And then, we could simplify handle, unwrap_or_else and unwrap_and.

    Example

         def handle(
            self,
            on_success: OnSuccessAction = None,
            on_failure: OnFailureAction = None,
        ) -> "Result":
            if on_failure:
                self.unwrap_or_else(on_failure)
            if on_success:
                self.unwrap_and(on_success)
            return self
    

    With this solution we're not solving the typing issue but I think the Dev Experience would be improved.

    enhancement 
    opened by acostapazo 2
  • Add AnyResult type

    Add AnyResult type

    First Check

    • [X] I added a very descriptive title to this issue.
    • [X] I used the GitHub search to find a similar issue and didn't find it.
    • [X] I already read and followed all the documentation and didn't find an answer.

    Description & Wanted Solution

    Create an alias for Result[Any, Error] when you don't want to type your success value (useful for declaring abstractmethods)

    Wanted Code

    from abc import ABC, abstractmethod
    from meiga import AnyResult
    
    class MyInterface(ABC):
    
        @abstractmethod
        def execute(self) -> AnyResult:
            pass
    

    Alternatives

    There is an ongoing PEP where they are working on default TypeVars. This could help meiga on generic definitions:

    TS = TypeVar("TS", default=Any)  # Success Type
    TF = TypeVar("TF", default=Error)  # Failure Type
    TEF = TypeVar("TEF")  # External Failure Type
    
    
    class Result(Generic[TS, TF]):
       ...
    

    Additional Context

    No response

    enhancement 
    opened by acostapazo 1
  • Could class typing of Success and Failure be improved?

    Could class typing of Success and Failure be improved?

    Success and Failure inherits from Result

    class Success(Result):
        def __init__(self, value=True) -> None:
            Result.__init__(self, success=value)
    
    
    class Failure(Result):
        def __init__(self, error=Error()) -> None:
            Result.__init__(self, failure=error)
    

    Thanks to the brand new type hints, the IDEs (Pycharm, VSCode,..) is able to assist us inspecting and checking the types of our objects.

    Example:

    my_result = Result[int, Error](2)
    value = my_result.unwrap()
     ^
      ---------- it is a int 
    

    However, when we use Success and Failure this does not work as we are not specifiying the type. I guess is not possible to update the type generic in runtime, but we should think about some alternative to improve the dev experience using these aliases.

    enhancement 
    opened by acostapazo 1
  • Result methods need more type hints

    Result methods need more type hints

    This library is awesome and I am so glad I stumbled upon it before diving into writing something similar on my own :)


    It feels to me that the core Result[...] class's methods kinda lack typization, making it harder to use with autocompletion and linters. For example:

    from typing import NamedTuple, cast
    
    from meiga import Result, Error
    
    class MyOutcome(NamedTuple):
        x: int
    
    def foo(fail: bool) -> Result[MyOutcome, Error]:
        if fail:
            return Result(failure=Error())
        return Result(success=MyOutcome(x=11))
    
    def test_type_check() -> None:
        a = foo(True)
        assert a.is_success
        av = a.unwrap_or_throw()
        assert av.x == 11
        assert cast(MyOutcome, av).x == 11
    

    Here av = a.unwrap_or_throw() should provide me with MyOutcome - since its very semantic is to either return a valid result, or raise exception - but VS Code (and probably other editors and IDEs that integrate with mypy) shows that the type is actually Any | None. Furthermore, accessing av.x causes x is not a known member of None warning. I then have to use cast(MyOutcome, av) to get typing back on tracks.

    If I understood it correctly, the problem arise because

    • Result.unwrap_or_throw is not annotated with type hints at all;
    • Result.throw (used inside the former) throws on condition, making the type checker think "it usually returns None".

    It seems that changing unwrap_or_throw to this:

        def unwrap_or_throw(self) -> TS:
            if self._is_success:
                return cast(TS, self.value)
            raise self.value
    

    fixes the problem, as the return type is specified and the raise is explicit.

    I just chose unwrap_or_throw() as the simplest example; all other methods are untyped too - either causing "use of untyped function in typed context" warnings from mypy, or confusing it into thinking that the returned values are Any instead of success- or error-types specified in Result[...] hint.

    enhancement 
    opened by Artalus 1
  • Review __eq__, __ne__ and __hash__

    Review __eq__, __ne__ and __hash__

    First Check

    • [X] I added a very descriptive title to this issue.
    • [X] I used the GitHub search to find a similar issue and didn't find it.
    • [X] I already read and followed all the documentation and didn't find an answer.

    Description

    I'd be nice to review __eq__, __ne__ and __hash__ of Result class to works as expected.

    Some tests are required here!

    Operating System

    macOS

    Operating System Details

    No response

    meiga Version

    v1.7.0

    Python Version

    all

    Additional Context

    No response

    bug 
    opened by acostapazo 0
  • feat(performance): add __slots__ to Result class

    feat(performance): add __slots__ to Result class

    Benchmark code:

    from __future__ import annotations
    
    from timeit import timeit
    
    from meiga import Error, Failure, Result, Success
    
    
    class NoSuchKey(Error):
        ...
    
    
    class TypeMismatch(Error):
        ...
    
    
    def string_from_key(
        dictionary: dict, key: str
    ) -> Result[str, NoSuchKey | TypeMismatch]:
        if key not in dictionary.keys():
            return Failure(NoSuchKey())
    
        value = dictionary[key]
        if not isinstance(value, str):
            return Failure(TypeMismatch())
    
        return Success(value)
    
    
    dictionary = {
        "key1": "value",
        "key2": 2,
        "key3": "value",
        "key4": 2,
        "key5": "value",
        "key6": 2,
        "key7": "value",
        "key8": 2,
        "key9": "value",
        "key10": 2,
        "key11": "value",
        "key12": 2,
    }
    
    time_success = timeit(lambda: string_from_key(dictionary=dictionary, key="key1"))
    print(f"time when success: {time_success}")
    
    time_failure_no_such_key = timeit(
        lambda: string_from_key(dictionary=dictionary, key="invalid_key")
    )
    print(f"time when failure (no such key): {time_failure_no_such_key}")
    
    time_failure_type_missmatch = timeit(
        lambda: string_from_key(dictionary=dictionary, key="key2")
    )
    print(f"time when failure (type missmatch): {time_failure_type_missmatch}")
    
    

    Result without slots:

    $ python benchmark/time_result.py
    time when success: 0.5478533749992494
    time when failure (no such key): 0.5760475420102011
    time when failure (type missmatch): 0.6188615420251153
    

    Result with slots:

    $ python benchmark/time_result.py
    time when success: 0.5113824579748325
    time when failure (no such key): 0.550075833016308
    time when failure (type missmatch): 0.5880016250011977
    

    Improvements

    Improvement when success: ~7% faster (x1.071318279412337) Improvement when failure (no such key): ~5% faster (x1.047214779190496) Improvement failure (type missmatch): ~5% faster (x1.052482707039891)

    opened by acostapazo 0
  • Create decorator to convert a function without meiga to return a Result

    Create decorator to convert a function without meiga to return a Result

    First Check

    • [X] I added a very descriptive title to this issue.
    • [X] I used the GitHub search to find a similar issue and didn't find it.
    • [X] I already read and followed all the documentation and didn't find an answer.

    Description

    I'd be nice to have a decorator to convert a function return value to Result

    Wanted Solution

    A new decorator @to_result to convert exceptions to failures and returned value as success

    Wanted Code

    from meiga import to_result
    
    class NoSuchKey(Exception): ...
    class TypeMismatch(Exception): ...
    
    @to_result
    def string_from_key(dictionary: dict, key: str) -> str:
        if key not in dictionary.keys():
            raise NoSuchKey()
    
        value = dictionary[key]
        if not isinstance(value, str):
            raise TypeMismatch()
    
        return value
    
    
    dictionary = {"key1": "value", "key2": 2}
    key = "key1"
    result: Result[str, NoSuchKey | TypeMismatch] = string_from_key(dictionary, key)
    

    Alternatives

    Also to_result decorator should be called as a function converter

    from meiga import to_result
    
    class NoSuchKey(Exception): ...
    class TypeMismatch(Exception): ...
    
    def string_from_key(dictionary: dict, key: str) -> str:
        if key not in dictionary.keys():
            raise NoSuchKey()
    
        value = dictionary[key]
        if not isinstance(value, str):
            raise TypeMismatch()
    
        return value
    
    
    dictionary = {"key1": "value", "key2": 2}
    key = "key1"
    result: Result[str, NoSuchKey | TypeMismatch] = to_result(string_from_key(dictionary, key))
    

    Additional Context

    No response

    enhancement 
    opened by acostapazo 0
  • Rename @meiga decorator

    Rename @meiga decorator

    First Check

    • [X] I added a very descriptive title to this issue.
    • [X] I used the GitHub search to find a similar issue and didn't find it.
    • [X] I already read and followed all the documentation and didn't find an answer.

    Description

    As explained in https://alice-biometrics.github.io/meiga/usage/decorator/, we use @meiga decorator in combination with unwrap_or_return.

    Wanted Solution

    We should change @meiga decorator name to mitigate confusion with the name of the package:

    This does not work

    import meiga
    
    @meiga
    def my_func():
      pass
    

    Name proposed: @early_return

    Wanted Code

    from meiga import early_return, BoolResult, isSuccess
    
    @early_return
    def update_user(user_id: UserId, new_name: str) -> BoolResult:
         user = repository.retrieve(user_id).unwrap_or_return()
         user.update_name(new_name)
         repository.save(user).unwrap_or_return()
         event_bus.publish(user.pull_domain_events()).unwrap_or_return()
         return isSuccess
    

    Alternatives

    No response

    Additional Context

    No response

    enhancement 
    opened by acostapazo 0
  • Use __slots__ for faster attribute access and space savings in memory

    Use __slots__ for faster attribute access and space savings in memory

    First Check

    • [X] I added a very descriptive title to this issue.
    • [X] I used the GitHub search to find a similar issue and didn't find it.
    • [X] I already read and followed all the documentation and didn't find an answer.

    Description

    Result class do not define slots for value.

    Wanted Solution

    meiga should define slots and then benchmark it to measure the improvements in terms of:

    • faster attribute access and
    • space savings in memory

    See this

    Wanted Code

    class Result(Generic[TS, TF]):
        __id__ = "__meiga_result_identifier__"
        __slots__ = "_value_success", "_value_failure" # This
    
        def __init__(
            self,
            success: Union[TS, Type[NoGivenValue]] = NoGivenValue,
            failure: Union[TF, Type[NoGivenValue]] = NoGivenValue,
        ) -> None:
            self._value_success = success
            self._value_failure = failure
            self._assert_values()
    
       ...
    

    Alternatives

    No response

    Additional Context

    No response

    enhancement 
    opened by acostapazo 0
Releases(v1.8.1)
  • v1.8.1(Nov 29, 2022)

    What's Changed

    • Feature/add pyupgrade by @acostapazo in https://github.com/alice-biometrics/meiga/pull/49
    • feat: add str implementation for Error class by @acostapazo in https://github.com/alice-biometrics/meiga/pull/50

    Full Changelog: https://github.com/alice-biometrics/meiga/compare/v1.8.0...v1.8.1

    Source code(tar.gz)
    Source code(zip)
  • v1.8.0(Oct 27, 2022)

    What's Changed

    • feat(performance): add slots to Result class (up to 7% faster) by @acostapazo in https://github.com/alice-biometrics/meiga/pull/41
    • feat(rename): use early_return instead of meiga decorator by @acostapazo in https://github.com/alice-biometrics/meiga/pull/42
    • chore: review and test object type attributes by @acostapazo in https://github.com/alice-biometrics/meiga/pull/46
    • feat(to_result): add new decorator to_result by @acostapazo in https://github.com/alice-biometrics/meiga/pull/44
    • chore(requirements): update dev requirements by @acostapazo in https://github.com/alice-biometrics/meiga/pull/47
    • feat(match): add match pattern feature (available from Python 3.10) by @acostapazo in https://github.com/alice-biometrics/meiga/pull/43

    Full Changelog: https://github.com/alice-biometrics/meiga/compare/v1.7.0...v1.8.0

    Source code(tar.gz)
    Source code(zip)
  • v1.7.0(Oct 10, 2022)

    What's Changed

    • Feature/improve doc by @acostapazo in https://github.com/alice-biometrics/meiga/pull/30
    • chore(docs): add first version of documentation (exploring mkdocs) by @acostapazo in https://github.com/alice-biometrics/meiga/pull/32
      • https://alice-biometrics.github.io/meiga/
    • 33 add assert success and assert failure to result class by @acostapazo in https://github.com/alice-biometrics/meiga/pull/34
    • feat(alias): make the aliases Success and Failure callables to return… by @acostapazo in https://github.com/alice-biometrics/meiga/pull/36

    Full Changelog: https://github.com/alice-biometrics/meiga/compare/v1.6.1...v1.7.0

    Source code(tar.gz)
    Source code(zip)
  • v1.6.1(Aug 25, 2022)

  • v1.6.0(Aug 9, 2022)

    What's Changed

    • feat: improve result aliases … by @acostapazo in https://github.com/alice-biometrics/meiga/pull/24
    • feat: add AnyResult new alias by @acostapazo in https://github.com/alice-biometrics/meiga/pull/26
    • chore(types): add type hints to meiga decorator by @acostapazo in https://github.com/alice-biometrics/meiga/pull/27

    Full Changelog: https://github.com/alice-biometrics/meiga/compare/v1.5.1...v1.6.0

    Source code(tar.gz)
    Source code(zip)
  • v1.5.1(Aug 5, 2022)

    What's Changed

    • fix: check message attribute in error representation by @franciscorode in https://github.com/alice-biometrics/meiga/pull/25

    New Contributors

    • @franciscorode made their first contribution in https://github.com/alice-biometrics/meiga/pull/25

    Full Changelog: https://github.com/alice-biometrics/meiga/compare/v1.5.0...v1.5.1

    Source code(tar.gz)
    Source code(zip)
  • v1.5.0(Aug 1, 2022)

    What's Changed

    • feat(mypy): simplify type hints by @acostapazo in https://github.com/alice-biometrics/meiga/pull/20
    • Adding new backward-compatible handlers by @acostapazo in https://github.com/alice-biometrics/meiga/pull/22

    Full Changelog: https://github.com/alice-biometrics/meiga/compare/v1.4.0...v1.5.0

    Source code(tar.gz)
    Source code(zip)
  • v1.4.0(Jul 26, 2022)

    What's Changed

    • fix: improve type hints by @fgsalomon in https://github.com/alice-biometrics/meiga/pull/17
    • chore(github-actions): update checkout and setup-python versions by @acostapazo in https://github.com/alice-biometrics/meiga/pull/18
    • feat(mypy): add py.typed to ship typing information by @acostapazo in https://github.com/alice-biometrics/meiga/pull/19

    New Contributors

    • @fgsalomon made their first contribution in https://github.com/alice-biometrics/meiga/pull/17

    Acknowledgments

    Thanks to @Artalus for giving us valuable feedback in https://github.com/alice-biometrics/meiga/issues/16 to improve meiga type hints.

    Full Changelog: https://github.com/alice-biometrics/meiga/compare/v1.3.2...v1.4.0

    Source code(tar.gz)
    Source code(zip)
  • v1.3.2(Jun 10, 2022)

    What's Changed

    • fix(warning): solve warning when VERSION file is not closed when read… by @acostapazo in https://github.com/alice-biometrics/meiga/pull/14
    • Bugfix/uploading to pypi missing requirements by @acostapazo in https://github.com/alice-biometrics/meiga/pull/15

    Full Changelog: https://github.com/alice-biometrics/meiga/compare/v1.3.1...v1.3.2

    Source code(tar.gz)
    Source code(zip)
  • v1.3.1(Apr 6, 2022)

    What's Changed

    • feat: update black version by @acostapazo in https://github.com/alice-biometrics/meiga/pull/12
    • feat: update pypi workflow. Use PYPI token instead former password by @acostapazo in https://github.com/alice-biometrics/meiga/pull/13

    Full Changelog: https://github.com/alice-biometrics/meiga/compare/v1.3.0...v1.3.1

    Source code(tar.gz)
    Source code(zip)
  • v1.3.0(Jan 10, 2022)

    What's Changed

    • Add static analysis and improve typing. by @acostapazo in https://github.com/alice-biometrics/meiga/pull/11
    • Add some missing tests. by @acostapazo in https://github.com/alice-biometrics/meiga/pull/11
    • Add coverage integration (Codecov) by @acostapazo in https://github.com/alice-biometrics/meiga/pull/11
    • Remove unused decorators (logs) by @acostapazo in https://github.com/alice-biometrics/meiga/pull/11

    Full Changelog: https://github.com/alice-biometrics/meiga/compare/v1.2.13...v1.3.0

    Source code(tar.gz)
    Source code(zip)
  • v1.2.13(Jan 3, 2022)

    What's Changed

    • Feature/update dev tools and modernize by @acostapazo in https://github.com/alice-biometrics/meiga/pull/10

    Full Changelog: https://github.com/alice-biometrics/meiga/compare/v1.2.12...v1.2.13

    Source code(tar.gz)
    Source code(zip)
  • v1.2.12(Dec 3, 2020)

  • v1.2.11(Nov 24, 2020)

    • Add new feature on unwrap_or_return Result method. Now, is possible to return a specific value on failure.
      • result.unwrap_or_return(return_value_on_failure=isSuccess)
    Source code(tar.gz)
    Source code(zip)
  • v1.2.10(Oct 7, 2020)

  • v1.2.9(Jun 9, 2020)

  • v1.2.8(May 21, 2020)

  • v1.2.7(Apr 22, 2020)

  • v1.2.6(Apr 17, 2020)

  • v1.2.5(Apr 17, 2020)

  • v1.2.4(Mar 27, 2020)

  • v1.2.3(Mar 11, 2020)

  • v1.2.2(Feb 5, 2020)

  • v1.2.1(Feb 5, 2020)

  • v1.2.0(Jan 23, 2020)

  • v1.1.2(Jan 22, 2020)

  • v1.1.0(Jan 21, 2020)

    • Added unwrap_and

    • Refactored handle. Now it returns itself.

      def on_success(value):
        print(f"on_success: {value}")
      
      def on_failure(value):
        print(f"on_failure: {value}")
      
      result = Success("Hi!")
      value = result.handle(on_success, on_failure).unwrap()
      
    Source code(tar.gz)
    Source code(zip)
  • v1.0.0(Jan 20, 2020)

    • Functions refactor and stabilization

    Properties

    | Properties | Definition | | --------------- |:--------------------------------------------------------------| | value | Returns the encapsulated value whether it's success or failure | | is_success | Returns true if this instance represents successful outcome. In this case is_failure returns false.|
    | is_failure | Returns true if this instance represents failed outcome. In this case is_success returns false |

    Functions

    | Functions | Definition | | --------------------------------|:-------------------------------------------------------------------------------------------- | | unwrap() | Returns the encapsulated value if this instance represents success or None if it is failure. | | unwrap_or(failure_value) | Returns the encapsulated value if this instance represents success or the selected failure_value if it is failure. |
    | unwrap_or_throw() | Returns the encapsulated value if this instance represents success or throws the encapsulated exception if it is failure. |
    | unwrap_or_else(on_failure) | Returns the encapsulated value if this instance represents success or execute the on_failure function when it is failure. |
    | handle(on_success,on_failure) | Returns itself and execute the on_successfunction when the instance represemts success and the on_failure function when it is failure. |
    | map(transform) | Returns a transformed result applying transform function applied to encapsulated value if this instance represents success or failure |

    Source code(tar.gz)
    Source code(zip)
Owner
Alice Biometrics
Make You Unique
Alice Biometrics
learn python in 100 days, a simple step could be follow from beginner to master of every aspect of python programming and project also include side project which you can use as demo project for your personal portfolio

learn python in 100 days, a simple step could be follow from beginner to master of every aspect of python programming and project also include side project which you can use as demo project for your

BDFD 6 Nov 05, 2022
Spin-off Notice: the modules and functions used by our research notebooks have been refactored into another repository

Fecon235 - Notebooks for financial economics. Keywords: Jupyter notebook pandas Federal Reserve FRED Ferbus GDP CPI PCE inflation unemployment wage income debt Case-Shiller housing asset portfolio eq

Adriano 825 Dec 27, 2022
Pydantic model generator for easy conversion of JSON, OpenAPI, JSON Schema, and YAML data sources.

datamodel-code-generator This code generator creates pydantic model from an openapi file and others. Help See documentation for more details. Supporte

Koudai Aono 1.3k Dec 29, 2022
A Json Schema Generator

JSON Schema Generator Author : Eru Michael About A Json Schema Generator. This is a generic program that: Reads a JSON file similar to what's present

1 Nov 10, 2021
An ongoing curated list of OS X best applications, libraries, frameworks and tools to help developers set up their macOS Laptop.

macOS Development Setup Welcome to MacOS Local Development & Setup. An ongoing curated list of OS X best applications, libraries, frameworks and tools

Paul Veillard 3 Apr 03, 2022
VSCode extension that generates docstrings for python files

VSCode Python Docstring Generator Visual Studio Code extension to quickly generate docstrings for python functions. Features Quickly generate a docstr

Nils Werner 506 Jan 03, 2023
Build documentation in multiple repos into one site.

mkdocs-multirepo-plugin Build documentation in multiple repos into one site. Setup Install plugin using pip: pip install git+https://github.com/jdoiro

Joseph Doiron 47 Dec 28, 2022
Documentation of the QR code found on new Austrian ID cards.

Austrian ID Card QR Code This document aims to be a complete documentation of the format used in the QR area on the back of new Austrian ID cards (Per

Gabriel Huber 9 Dec 12, 2022
A simple document management REST based API for collaboratively interacting with documents

documan_api A simple document management REST based API for collaboratively interacting with documents.

Shahid Yousuf 1 Jan 22, 2022
Some of the best ways and practices of doing code in Python!

Pythonicness ❤ This repository contains some of the best ways and practices of doing code in Python! Features Properly formatted codes (PEP 8) for bet

Samyak Jain 2 Jan 15, 2022
A plugin to introduce a generic API for Decompiler support in GEF

decomp2gef A plugin to introduce a generic API for Decompiler support in GEF. Like GEF, the plugin is battery-included and requires no external depend

Zion 379 Jan 08, 2023
This is a template (starter kit) for writing Maturity Work with Sphinx / LaTeX at Collège du Sud

sphinx-tm-template Ce dépôt est un template de base utilisable pour écrire ton travail de maturité dans le séminaire d'informatique du Collège du Sud.

6 Dec 22, 2022
Easy OpenAPI specs and Swagger UI for your Flask API

Flasgger Easy Swagger UI for your Flask API Flasgger is a Flask extension to extract OpenAPI-Specification from all Flask views registered in your API

Flasgger 3.1k Dec 24, 2022
✨ Real-life Data Analysis and Model Training Workshop by Global AI Hub.

🎓 Data Analysis and Model Training Course by Global AI Hub Syllabus: Day 1 What is Data? Multimedia Structured and Unstructured Data Data Types Data

Global AI Hub 71 Oct 28, 2022
Create docsets for Dash.app-compatible API browser.

doc2dash: Create Docsets for Dash.app and Clones doc2dash is an MIT-licensed extensible Documentation Set generator intended to be used with the Dash.

Hynek Schlawack 498 Dec 30, 2022
This programm checks your knowlege about the capital of Japan

Introduction This programm checks your knowlege about the capital of Japan. Now, what does it actually do? After you run the programm you get asked wh

1 Dec 16, 2021
Searches a document for hash tags. Support multiple natural languages. Works in various contexts.

ht-getter Searches a document for hash tags. Supports multiple natural languages. Works in various contexts. This package uses a non-regex approach an

Rairye 1 Mar 01, 2022
OpenAPI (f.k.a Swagger) Specification code generator. Supports C#, PowerShell, Go, Java, Node.js, TypeScript, Python

AutoRest The AutoRest tool generates client libraries for accessing RESTful web services. Input to AutoRest is a spec that describes the REST API usin

Microsoft Azure 4.1k Jan 06, 2023
:blue_book: Automatic documentation from sources, for MkDocs.

mkdocstrings Automatic documentation from sources, for MkDocs. Features Python handler features Requirements Installation Quick usage Features Languag

Timothée Mazzucotelli 1.1k Dec 31, 2022
Template repo to quickly make a tested and documented GitHub action in Python with Poetry

Python + Poetry GitHub Action Template Getting started from the template Rename the src/action_python_poetry package. Globally replace instances of ac

Kevin Duff 89 Dec 25, 2022