Source code for towhee.functional.option

# Copyright 2021 Zilliz. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from typing import Callable, Generic
from typing import Any, TypeVar

A = TypeVar('A', covariant=True)
B = TypeVar('B')
T = TypeVar('T')


class _Reason:
    """The reason for the current value.

        Args:
            x (Any): The value.
            e (Exception): The Exception that caused it.
        """
    def __init__(self, x: Any, e: Exception) -> None:
        self._value = x
        self._exception = e

    @property
    def value(self):
        return self._value

    @property
    def exception(self):
        return self._exception


[docs]class Option(Generic[A]): """Functional-style error handling. Option[A] = Some(A) or Empty[A] 1. Some(A): just a container for result; 2. Empty[A]: result is empty, because of input error or computation error; Examples: >>> a = Some(10) >>> a.map(lambda x: x/2.0) Some(5.0) >>> a.map(lambda x: x/0) Empty() >>> b = Empty() >>> b.map(lambda x: x/2.0) Empty() """
[docs] @staticmethod def of(x: T): """Return a boxed value. Args: x (T): The input value. Returns: Some(T): The boxed value. """ return Some(x)
[docs] @staticmethod def empty(): """Return an empty value. Returns: Empty: The empty value. """ return Empty()
[docs] def flat_map(self, f: Callable[[A], 'Option[B]']) -> 'Option[B]': """Apply boxed version of callable. Args: f (Callable[[A], Option[B]]): Boxed version of callable Returns: Option[B]: The boxed value. Examples: >>> Option.of(1).flat_map(lambda x: x+1) 2 >>> Option.empty().flat_map(lambda x: x+1) Empty() """ if isinstance(self, Some): return f(self._value) else: return self
[docs] def map(self, f: Callable[[A], 'B']) -> 'Option[B]': """Apply a function to a value. Args: f (Callable[[A], B]): A unboxed callable. Returns: Option[B]: The boxed return value. """ def wrapper(x): try: return Some(f(x)) except Exception as e: # pylint: disable=broad-except return Empty(x, e) return self.flat_map(wrapper)
[docs] def is_empty(self): """Return True if the value is empty. Returns: bool: True if empty. """ return isinstance(self, Empty)
[docs] def is_some(self): """Return True if the value is boxed value. Returns: bool: True if boxed. """ return isinstance(self, Some)
[docs] def get_or_else(self, default): """Return unboxed value, or default if the value is empty. Args: default (any): The default value to return. Returns: any: The unboxed value, or default if empty. Examples: >>> Option.of(0).get_or_else(1) 0 >>> Option.empty().get_or_else(1) 1 """ if self.is_some(): return self.get() return default
[docs]class Some(Option[A]): """`Some` value for `Option` """
[docs] def __init__(self, x: A) -> None: self._value = x
[docs] def __repr__(self) -> str: return 'Some({})'.format(self._value)
[docs] def flat_map(self, f: Callable[[A], 'Option[B]']) -> 'Option[B]': return f(self._value)
[docs] def get(self): """Return unboxed value """ return self._value
[docs]class Empty(Option[A]): """`Empty` value for `Option` Args: x (Any, optional): The value. Defaults to None. e (Exception, optional): The reasone for value. Defaults to None. """
[docs] def __init__(self, x: Any = None, e: Exception = None) -> None: self._reason = _Reason(x, e)
[docs] def __repr__(self) -> str: """The repr function that returns default 'Empty()'. Returns: str: Returns 'Empty()'. """ return 'Empty()'
[docs] def flat_map(self, f: Callable[[A], 'Option[B]']) -> 'Option[B]': return self
[docs] def get(self): """Return the reason of the empty value. Returns: _Reason: Reason for empty. """ return self._reason
empty = Empty()