diff --git a/returns/context/requires_context_ioresult.py b/returns/context/requires_context_ioresult.py index b976c17e0..781e60a58 100644 --- a/returns/context/requires_context_ioresult.py +++ b/returns/context/requires_context_ioresult.py @@ -249,11 +249,13 @@ def bind( Kind3[ RequiresContextIOResult, _NewValueType, - _ErrorType, + _ErrorType | _NewErrorType, _EnvType, ], ], - ) -> RequiresContextIOResult[_NewValueType, _ErrorType, _EnvType]: + ) -> RequiresContextIOResult[ + _NewValueType, _ErrorType | _NewErrorType, _EnvType, + ]: """ Composes this container with a function returning the same type. @@ -293,8 +295,12 @@ def bind( def bind_result( self, - function: Callable[[_ValueType], Result[_NewValueType, _ErrorType]], - ) -> RequiresContextIOResult[_NewValueType, _ErrorType, _EnvType]: + function: Callable[ + [_ValueType], Result[_NewValueType, _ErrorType | _NewErrorType], + ], + ) -> RequiresContextIOResult[ + _NewValueType, _ErrorType | _NewErrorType, _EnvType, + ]: """ Binds ``Result`` returning function to the current container. diff --git a/returns/context/requires_context_result.py b/returns/context/requires_context_result.py index 285a5d37a..aeb4956de 100644 --- a/returns/context/requires_context_result.py +++ b/returns/context/requires_context_result.py @@ -167,7 +167,8 @@ def swap(self) -> RequiresContextResult[_ErrorType, _ValueType, _EnvType]: return RequiresContextResult(lambda deps: self(deps).swap()) def map( - self, function: Callable[[_ValueType], _NewValueType], + self, + function: Callable[[_ValueType], _NewValueType], ) -> RequiresContextResult[_NewValueType, _ErrorType, _EnvType]: """ Composes successful container with a pure function. @@ -232,11 +233,13 @@ def bind( Kind3[ RequiresContextResult, _NewValueType, - _ErrorType, + _ErrorType | _NewErrorType, _EnvType, ], ], - ) -> RequiresContextResult[_NewValueType, _ErrorType, _EnvType]: + ) -> RequiresContextResult[ + _NewValueType, _ErrorType | _NewErrorType, _EnvType, + ]: """ Composes this container with a function returning the same type. @@ -274,8 +277,12 @@ def bind( def bind_result( self, - function: Callable[[_ValueType], Result[_NewValueType, _ErrorType]], - ) -> RequiresContextResult[_NewValueType, _ErrorType, _EnvType]: + function: Callable[ + [_ValueType], Result[_NewValueType, _ErrorType | _NewErrorType], + ], + ) -> RequiresContextResult[ + _NewValueType, _ErrorType | _NewErrorType, _EnvType, + ]: """ Binds ``Result`` returning function to current container. @@ -338,7 +345,8 @@ def bind_context( ) def alt( - self, function: Callable[[_ErrorType], _NewErrorType], + self, + function: Callable[[_ErrorType], _NewErrorType], ) -> RequiresContextResult[_ValueType, _NewErrorType, _EnvType]: """ Composes failed container with a pure function. @@ -455,7 +463,8 @@ def ask(cls) -> RequiresContextResult[_EnvType, _ErrorType, _EnvType]: @classmethod def from_result( - cls, inner_value: Result[_NewValueType, _NewErrorType], + cls, + inner_value: Result[_NewValueType, _NewErrorType], ) -> RequiresContextResult[_NewValueType, _NewErrorType, NoDeps]: """ Creates new container with ``Result`` as a unit value. @@ -481,7 +490,8 @@ def from_result( def from_typecast( cls, inner_value: RequiresContext[ - Result[_NewValueType, _NewErrorType], _EnvType, + Result[_NewValueType, _NewErrorType], + _EnvType, ], ) -> RequiresContextResult[_NewValueType, _NewErrorType, _EnvType]: """ @@ -510,7 +520,8 @@ def from_typecast( @classmethod def from_context( - cls, inner_value: RequiresContext[_NewValueType, _NewEnvType], + cls, + inner_value: RequiresContext[_NewValueType, _NewEnvType], ) -> RequiresContextResult[_NewValueType, Any, _NewEnvType]: """ Creates new container from ``RequiresContext`` as a success unit. @@ -528,7 +539,8 @@ def from_context( @classmethod def from_failed_context( - cls, inner_value: RequiresContext[_NewValueType, _NewEnvType], + cls, + inner_value: RequiresContext[_NewValueType, _NewEnvType], ) -> RequiresContextResult[Any, _NewValueType, _NewEnvType]: """ Creates new container from ``RequiresContext`` as a failure unit. @@ -548,7 +560,9 @@ def from_failed_context( def from_result_context( cls, inner_value: RequiresContextResult[ - _NewValueType, _NewErrorType, _NewEnvType, + _NewValueType, + _NewErrorType, + _NewEnvType, ], ) -> RequiresContextResult[_NewValueType, _NewErrorType, _NewEnvType]: """ @@ -572,7 +586,8 @@ def from_result_context( @classmethod def from_value( - cls, inner_value: _FirstType, + cls, + inner_value: _FirstType, ) -> RequiresContextResult[_FirstType, Any, NoDeps]: """ Creates new container with ``Success(inner_value)`` as a unit value. @@ -588,7 +603,8 @@ def from_value( @classmethod def from_failure( - cls, inner_value: _FirstType, + cls, + inner_value: _FirstType, ) -> RequiresContextResult[Any, _FirstType, NoDeps]: """ Creates new container with ``Failure(inner_value)`` as a unit value. @@ -607,7 +623,9 @@ def from_failure( #: Alias for a popular case when ``Result`` has ``Exception`` as error type. RequiresContextResultE: TypeAlias = RequiresContextResult[ - _ValueType, Exception, _EnvType, + _ValueType, + Exception, + _EnvType, ] #: Alias to save you some typing. Uses original name from Haskell. @@ -615,5 +633,7 @@ def from_failure( #: Alias to save you some typing. Has ``Exception`` as error type. ReaderResultE: TypeAlias = RequiresContextResult[ - _ValueType, Exception, _EnvType, + _ValueType, + Exception, + _EnvType, ] diff --git a/returns/future.py b/returns/future.py index 9195fef6d..6d35abedb 100644 --- a/returns/future.py +++ b/returns/future.py @@ -757,9 +757,9 @@ def bind( self, function: Callable[ [_ValueType], - Kind2['FutureResult', _NewValueType, _ErrorType], + Kind2['FutureResult', _NewValueType, _ErrorType | _NewErrorType], ], - ) -> 'FutureResult[_NewValueType, _ErrorType]': + ) -> 'FutureResult[_NewValueType, _ErrorType | _NewErrorType]': """ Applies 'function' to the result of a previous calculation. @@ -795,9 +795,11 @@ def bind_async( self, function: Callable[ [_ValueType], - Awaitable[Kind2['FutureResult', _NewValueType, _ErrorType]], + Awaitable[ + Kind2['FutureResult', _NewValueType, _ErrorType | _NewErrorType] + ], ], - ) -> 'FutureResult[_NewValueType, _ErrorType]': + ) -> 'FutureResult[_NewValueType, _ErrorType | _NewErrorType]': """ Composes a container and ``async`` function returning container. diff --git a/returns/io.py b/returns/io.py index 3cb4cb59d..409093091 100644 --- a/returns/io.py +++ b/returns/io.py @@ -437,9 +437,9 @@ def bind( self, function: Callable[ [_ValueType], - Kind2['IOResult', _NewValueType, _ErrorType], + Kind2['IOResult', _NewValueType, _ErrorType | _NewErrorType], ], - ) -> 'IOResult[_NewValueType, _ErrorType]': + ) -> 'IOResult[_NewValueType, _ErrorType | _NewErrorType]': """ Composes successful container with a function that returns a container. @@ -464,9 +464,9 @@ def bind_result( self, function: Callable[ [_ValueType], - Result[_NewValueType, _ErrorType], + Result[_NewValueType, _ErrorType | _NewErrorType], ], - ) -> 'IOResult[_NewValueType, _ErrorType]': + ) -> 'IOResult[_NewValueType, _ErrorType | _NewErrorType]': """ Composes successful container with a function that returns a container. diff --git a/returns/result.py b/returns/result.py index 293ede7e4..05060695a 100644 --- a/returns/result.py +++ b/returns/result.py @@ -119,9 +119,9 @@ def bind( self, function: Callable[ [_ValueType], - Kind2['Result', _NewValueType, _ErrorType], + Kind2['Result', _NewValueType, _ErrorType | _NewErrorType], ], - ) -> 'Result[_NewValueType, _ErrorType]': + ) -> 'Result[_NewValueType, _ErrorType | _NewErrorType]': """ Composes successful container with a function that returns a container. diff --git a/typesafety/test_context/test_requires_context_ioresult/test_requires_context_ioresult.yml b/typesafety/test_context/test_requires_context_ioresult/test_requires_context_ioresult.yml index b85df53fd..c69ed2cbd 100644 --- a/typesafety/test_context/test_requires_context_ioresult/test_requires_context_ioresult.yml +++ b/typesafety/test_context/test_requires_context_ioresult/test_requires_context_ioresult.yml @@ -164,3 +164,19 @@ first: RequiresContextIOResult[float, bool, int] reveal_type(first.modify_env(int)('1')) # N: Revealed type is "returns.io.IOResult[builtins.float, builtins.bool]" + + +- case: requires_context_ioresult_bind_composite_error + disable_cache: false + main: | + from returns.context import RequiresContextIOResult + + x: RequiresContextIOResult[int, float, str] + + def first_function(param: int) -> RequiresContextIOResult[bool, ValueError, str]: + ... + + def second_function(param: bool) -> RequiresContextIOResult[bool, KeyError, str]: + ... + + reveal_type(x.bind(first_function).bind(second_function)) # N: Revealed type is "returns.context.requires_context_ioresult.RequiresContextIOResult[builtins.bool, Union[builtins.float, builtins.ValueError, builtins.KeyError], builtins.str]" diff --git a/typesafety/test_context/test_requires_context_result/test_requires_context_result.yml b/typesafety/test_context/test_requires_context_result/test_requires_context_result.yml index 5b7a7ba25..b069a75aa 100644 --- a/typesafety/test_context/test_requires_context_result/test_requires_context_result.yml +++ b/typesafety/test_context/test_requires_context_result/test_requires_context_result.yml @@ -122,3 +122,19 @@ first: RequiresContextResult[float, bool, int] reveal_type(first.modify_env(int)('1')) # N: Revealed type is "returns.result.Result[builtins.float, builtins.bool]" + + +- case: requires_context_result_bind_composite_error + disable_cache: false + main: | + from returns.context import RequiresContextResult + + x: RequiresContextResult[int, float, str] + + def first_function(param: int) -> RequiresContextResult[bool, ValueError, str]: + ... + + def second_function(param: bool) -> RequiresContextResult[bool, KeyError, str]: + ... + + reveal_type(x.bind(first_function).bind(second_function)) # N: Revealed type is "returns.context.requires_context_result.RequiresContextResult[builtins.bool, Union[builtins.float, builtins.ValueError, builtins.KeyError], builtins.str]" diff --git a/typesafety/test_future/test_future_result_container/test_future_result_base.yml b/typesafety/test_future/test_future_result_container/test_future_result_base.yml index 436d369de..7cd12215f 100644 --- a/typesafety/test_future/test_future_result_container/test_future_result_base.yml +++ b/typesafety/test_future/test_future_result_container/test_future_result_base.yml @@ -155,3 +155,59 @@ first: FutureResult[int, str] reveal_type(first.lash(bind)) # N: Revealed type is "returns.future.FutureResult[builtins.int, builtins.float]" + + +- case: future_success_result_async_composite_error + disable_cache: false + main: | + from returns.future import FutureResult, FutureSuccess + + def returns_value_error(value: int) -> FutureResult[str, ValueError]: + ... + def returns_key_error(value: str) -> FutureResult[bool, KeyError]: + ... + + result = FutureSuccess(0).bind(returns_value_error).bind(returns_key_error) + reveal_type(result) # N: Revealed type is "returns.future.FutureResult[builtins.bool, Union[Any, builtins.ValueError, builtins.KeyError]]" + + +- case: future_failure_result_async_composite_error + disable_cache: false + main: | + from returns.future import FutureResult, FutureFailure + + def returns_value_error(value: int) -> FutureResult[str, ValueError]: + ... + def returns_key_error(value: str) -> FutureResult[bool, KeyError]: + ... + + result = FutureFailure(0).bind(returns_value_error).bind(returns_key_error) + reveal_type(result) # N: Revealed type is "returns.future.FutureResult[builtins.bool, Union[builtins.int, builtins.ValueError, builtins.KeyError]]" + + +- case: future_success_result_bind_async_composite_error + disable_cache: false + main: | + from returns.future import FutureResult, FutureSuccess + + async def returns_value_error(value: int) -> FutureResult[str, ValueError]: + ... + async def returns_key_error(value: str) -> FutureResult[bool, KeyError]: + ... + + result = FutureSuccess(0).bind_async(returns_value_error).bind_async(returns_key_error) + reveal_type(result) # N: Revealed type is "returns.future.FutureResult[builtins.bool, Union[Any, builtins.ValueError, builtins.KeyError]]" + + +- case: future_failure_result_bind_async_composite_error + disable_cache: false + main: | + from returns.future import FutureResult, FutureFailure + + async def returns_value_error(value: int) -> FutureResult[str, ValueError]: + ... + async def returns_key_error(value: str) -> FutureResult[bool, KeyError]: + ... + + result = FutureFailure(0).bind_async(returns_value_error).bind_async(returns_key_error) + reveal_type(result) # N: Revealed type is "returns.future.FutureResult[builtins.bool, Union[builtins.int, builtins.ValueError, builtins.KeyError]]" \ No newline at end of file diff --git a/typesafety/test_io/test_ioresult_container/test_construct_iofailure.yml b/typesafety/test_io/test_ioresult_container/test_construct_iofailure.yml index be0ddb86d..b34567aa2 100644 --- a/typesafety/test_io/test_ioresult_container/test_construct_iofailure.yml +++ b/typesafety/test_io/test_ioresult_container/test_construct_iofailure.yml @@ -24,3 +24,17 @@ from returns.io import IOFailure reveal_type(IOFailure(1).failure()) # N: Revealed type is "returns.io.IO[builtins.int]" + + +- case: iofailure_bind_composite_error + disable_cache: false + main: | + from returns.io import IOFailure, IOResult + + def returns_value_error(value: int) -> IOResult[str, ValueError]: + ... + def returns_key_error(value: str) -> IOResult[bool, KeyError]: + ... + + result = IOFailure(0).bind(returns_value_error).bind(returns_key_error) + reveal_type(result) # N: Revealed type is "returns.io.IOResult[builtins.bool, Union[builtins.int, builtins.ValueError, builtins.KeyError]]" \ No newline at end of file diff --git a/typesafety/test_io/test_ioresult_container/test_construct_iosucess.yml b/typesafety/test_io/test_ioresult_container/test_construct_iosucess.yml index daacece42..eb7323d4c 100644 --- a/typesafety/test_io/test_ioresult_container/test_construct_iosucess.yml +++ b/typesafety/test_io/test_ioresult_container/test_construct_iosucess.yml @@ -68,3 +68,18 @@ from returns.io import IOSuccess reveal_type(IOSuccess(1).unwrap()) # N: Revealed type is "returns.io.IO[builtins.int]" + + +- case: iosuccess_bind_composite_error + disable_cache: false + main: | + from returns.io import IOSuccess, IOResult + + def returns_value_error(param: int) -> IOResult[str, ValueError]: + ... + def returns_key_error(param: str) -> IOResult[str, KeyError]: + ... + + first: IOResult[int, Exception] = IOSuccess(1) + result = first.bind(returns_value_error).bind(returns_key_error) + reveal_type(result) # N: Revealed type is "returns.io.IOResult[builtins.str, Union[builtins.Exception, builtins.ValueError, builtins.KeyError]]" \ No newline at end of file diff --git a/typesafety/test_io/test_ioresult_container/test_ioresult_typecast.yml b/typesafety/test_io/test_ioresult_container/test_ioresult_typecast.yml index 148747ca5..071d7bc17 100644 --- a/typesafety/test_io/test_ioresult_container/test_ioresult_typecast.yml +++ b/typesafety/test_io/test_ioresult_container/test_ioresult_typecast.yml @@ -91,7 +91,7 @@ first: IOResult[int, Exception] second = first.bind(test) - reveal_type(second) # N: Revealed type is "returns.io.IOResult[builtins.int, builtins.Exception]" + reveal_type(second) # N: Revealed type is "returns.io.IOResult[builtins.int, Union[builtins.Exception, builtins.ValueError]]" - case: ioresult_correct_usage diff --git a/typesafety/test_result/test_construct_failure.yml b/typesafety/test_result/test_construct_failure.yml index f51e3837a..158d7a88b 100644 --- a/typesafety/test_result/test_construct_failure.yml +++ b/typesafety/test_result/test_construct_failure.yml @@ -24,3 +24,18 @@ from returns.result import Failure reveal_type(Failure(1).failure()) # N: Revealed type is "builtins.int" + + +- case: failure_bind_composite_error + disable_cache: false + main: | + from returns.result import Failure, Result + + def returns_value_error(value: int) -> Result[str, ValueError]: + ... + + def second_function(value: str) -> Result[bool, KeyError]: + ... + + result = Failure(0).bind(returns_value_error).bind(second_function) + reveal_type(result) # N: Revealed type is "returns.result.Result[builtins.bool, Union[builtins.int, builtins.ValueError, builtins.KeyError]]" diff --git a/typesafety/test_result/test_construct_success.yml b/typesafety/test_result/test_construct_success.yml index fddfde3dd..f9a27fd97 100644 --- a/typesafety/test_result/test_construct_success.yml +++ b/typesafety/test_result/test_construct_success.yml @@ -65,3 +65,18 @@ from returns.result import Success reveal_type(Success(1).unwrap()) # N: Revealed type is "builtins.int" + + +- case: success_bind_composite_error + disable_cache: false + main: | + from returns.result import Success, Result + + def returns_value_error(param: int) -> Result[str, ValueError]: + ... + + def returns_key_error(param: str) -> Result[str, KeyError]: + ... + + first: Result[int, Exception] = Success(1) + reveal_type(first.bind(returns_value_error).bind(returns_key_error)) # N: Revealed type is "returns.result.Result[builtins.str, Union[builtins.Exception, builtins.ValueError, builtins.KeyError]]" diff --git a/typesafety/test_result/test_result_type_cast.yml b/typesafety/test_result/test_result_type_cast.yml index f2fce9df7..92d78e502 100644 --- a/typesafety/test_result/test_result_type_cast.yml +++ b/typesafety/test_result/test_result_type_cast.yml @@ -109,7 +109,7 @@ first: Result[int, Exception] second = first.bind(test) - reveal_type(second) # N: Revealed type is "returns.result.Result[builtins.int, builtins.Exception]" + reveal_type(second) # N: Revealed type is "returns.result.Result[builtins.int, Union[builtins.Exception, builtins.ValueError]]" - case: result_correct_usage