Result

Result is obviously a result of some series of computations. It might succeed with some resulting value. Or it might return an error with some extra details.

Result consist of two types: Success and Failure. Success represents successful operation result and Failure indicates that something has failed.

from returns.result import Result, Success, Failure

def find_user(user_id: int) -> Result['User', str]:
    user = User.objects.filter(id=user_id)
    if user.exists():
        return Success(user[0])
    return Failure('User was not found')

user_search_result = find_user(1)
# => Success(User{id: 1, ...})

user_search_result = find_user(0)  # id 0 does not exist!
# => Failure('User was not found')

When is it useful? When you do not want to use exceptions to break your execution scope. Or when you do not want to use None to represent empty values, since it will raise TypeError somewhere and other None exception-friends.

Composition

Make sure to check out how to compose container with pipe and @pipeline! Read more about them if you want to compose your containers easily.

safe

safe is used to convert regular functions that can throw exceptions to functions that return Result type.

Supports both async and regular functions.

from returns.result import safe

@safe  # Will convert type to: Callable[[int], Result[float, Exception]]
def divide(number: int) -> float:
    return number / number

divide(1)
# => Success(1.0)

divide(0)
# => Failure(ZeroDivisionError)

Limitations

Typing will only work correctly if decorator_plugin is used. This happens due to mypy issue.

FAQ

How to create unit objects?

Use Success or Failure together with the explicit annotation. Python’s type system does not allow us to do much, so this is required:

def callback(arg: int) -> Result[float, int]:
    return Success(float(arg))

first: Result[int, int] = Success(1)
first.bind(callback)

Otherwise it would raise a mypy error:

first = Success(1)
first.bind(callback)
# Argument 1 to "bind" of "Result" has incompatible type
# "Callable[[int], Result[float, int]]";
# expected "Callable[[int], Result[float, NoReturn]]"

This happens because mypy is unable to implicitly cast NoReturn to any other type.

What is the difference between Success and _Success?

You might wonder why Success is a function and _Success is internal type, that should not be used directly.

Well, that’s a complicated question. Let’s find out.

Let’s begin with haskell definition:

Prelude> :t Left 1
Left 1 :: Num a => Either a b
Prelude> :t Right 1
Right 1 :: Num b => Either a b

As you can see: Left (Failure) and Right (Success) are type constructors: that return Either a b (Result[b, a]) value.

It means, that there’s no single type Left a that makes sense without Right b. Only their duality makes sence to us.

In python we have functions that can be used as type constructors. That’s why we use Success and Failure functions. But, when we need to implement the behaviour of these types - we use real classes inside. That’s how we know what to do in each particular case. In haskell we use pattern matching for this.

That’s why we have public type constructor functions: Success and Failure and internal implementation.

API Reference

graph TD; _Failure Result _Success Generic --> Result BaseContainer --> Result Result --> _Failure Result --> _Success
class Result(inner_value)[source]

Bases: typing.Generic, returns.primitives.container.BaseContainer

Base class for _Failure and _Success.

Result does not have

map(function)[source]

Abstract method to compose container with a pure function.

Return type

Result[~_NewValueType, +_ErrorType]

bind(function)[source]

Abstract method to compose a container with another container.

Return type

Result[~_NewValueType, +_ErrorType]

fix(function)[source]

Abstract method to compose failed container and a pure function.

This pure function should return a new state for a successful container.

Return type

Result[~_NewValueType, +_ErrorType]

alt(function)[source]

Abstract method to compose failed container and a pure function.

This pure function should return a new state for a new failed container.

Return type

Result[+_ValueType, ~_NewErrorType]

rescue(function)[source]

Abstract method to compose a failed container with another container.

This method is the oposite of .bind().

Return type

Result[+_ValueType, ~_NewErrorType]

value_or(default_value)[source]

Get value or default value.

Return type

Union[+_ValueType, ~_DefaultValueType]

unwrap()[source]

Get value or raise exception.

Return type

+_ValueType

failure()[source]

Get failed value or raise exception.

Return type

+_ErrorType

Success(inner_value)[source]

Public unit function of protected _Success type.

Return type

Result[+_ValueType]

Failure(inner_value)[source]

Public unit function of protected _Failure type.

Return type

Result[+_ErrorType]

safe(function)[source]

Decorator to covert exception throwing function to ‘Result’ container.

Should be used with care, since it only catches ‘Exception’ subclasses. It does not catch ‘BaseException’ subclasses.

Supports both async and regular functions.

>>> @safe
... def might_raise(arg: int) -> float:
...     return 1 / arg
...
>>> might_raise(1) == Success(1.0)
True
>>> isinstance(might_raise(0), _Failure)
True
IO Pipelines