File: future.py

package info (click to toggle)
python-returns 0.26.0-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 2,652 kB
  • sloc: python: 11,000; makefile: 18
file content (149 lines) | stat: -rw-r--r-- 4,631 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
"""
Represents the base interfaces for types that do fearless async operations.

This type means that ``Future`` cannot fail.
Don't use this type for async that can. Instead, use
:class:`returns.interfaces.specific.future_result.FutureResultBasedN` type.
"""

from __future__ import annotations

from abc import abstractmethod
from collections.abc import Awaitable, Callable, Generator
from typing import TYPE_CHECKING, Any, Generic, TypeVar

from typing_extensions import Never

from returns.interfaces.specific import io
from returns.primitives.hkt import KindN

if TYPE_CHECKING:
    from returns.future import Future  # noqa: WPS433

_FirstType = TypeVar('_FirstType')
_SecondType = TypeVar('_SecondType')
_ThirdType = TypeVar('_ThirdType')
_UpdatedType = TypeVar('_UpdatedType')

_FutureLikeType = TypeVar('_FutureLikeType', bound='FutureLikeN')
_AsyncFutureType = TypeVar('_AsyncFutureType', bound='AwaitableFutureN')


class FutureLikeN(io.IOLikeN[_FirstType, _SecondType, _ThirdType]):
    """
    Base type for ones that does look like ``Future``.

    But at the time this is not a real ``Future`` and cannot be awaited.
    """

    __slots__ = ()

    @abstractmethod
    def bind_future(
        self: _FutureLikeType,
        function: Callable[[_FirstType], Future[_UpdatedType]],
    ) -> KindN[_FutureLikeType, _UpdatedType, _SecondType, _ThirdType]:
        """Allows to bind ``Future`` returning function over a container."""

    @abstractmethod
    def bind_async_future(
        self: _FutureLikeType,
        function: Callable[[_FirstType], Awaitable[Future[_UpdatedType]]],
    ) -> KindN[_FutureLikeType, _UpdatedType, _SecondType, _ThirdType]:
        """Allows to bind async ``Future`` returning function over container."""

    @abstractmethod
    def bind_async(
        self: _FutureLikeType,
        function: Callable[
            [_FirstType],
            Awaitable[
                KindN[_FutureLikeType, _UpdatedType, _SecondType, _ThirdType],
            ],
        ],
    ) -> KindN[_FutureLikeType, _UpdatedType, _SecondType, _ThirdType]:
        """Binds async function returning the same type of container."""

    @abstractmethod
    def bind_awaitable(
        self: _FutureLikeType,
        function: Callable[[_FirstType], Awaitable[_UpdatedType]],
    ) -> KindN[_FutureLikeType, _UpdatedType, _SecondType, _ThirdType]:
        """Allows to bind async function over container."""

    @classmethod
    @abstractmethod
    def from_future(
        cls: type[_FutureLikeType],
        inner_value: Future[_UpdatedType],
    ) -> KindN[_FutureLikeType, _UpdatedType, _SecondType, _ThirdType]:
        """Unit method to create new containers from successful ``Future``."""


#: Type alias for kinds with one type argument.
FutureLike1 = FutureLikeN[_FirstType, Never, Never]

#: Type alias for kinds with two type arguments.
FutureLike2 = FutureLikeN[_FirstType, _SecondType, Never]

#: Type alias for kinds with three type arguments.
FutureLike3 = FutureLikeN[_FirstType, _SecondType, _ThirdType]


class AwaitableFutureN(Generic[_FirstType, _SecondType, _ThirdType]):
    """
    Type that provides the required API for ``Future`` to be async.

    Should not be used directly. Use ``FutureBasedN`` instead.
    """

    __slots__ = ()

    @abstractmethod
    def __await__(
        self: _AsyncFutureType,
    ) -> Generator[
        Any,
        Any,
        io.IOLikeN[_FirstType, _SecondType, _ThirdType],
    ]:
        """Magic method to allow ``await`` expression."""

    @abstractmethod
    async def awaitable(
        self: _AsyncFutureType,
    ) -> io.IOLikeN[_FirstType, _SecondType, _ThirdType]:
        """Underling logic under ``await`` expression."""


#: Type alias for kinds with one type argument.
AsyncFuture1 = AwaitableFutureN[_FirstType, Never, Never]

#: Type alias for kinds with two type arguments.
AsyncFuture2 = AwaitableFutureN[_FirstType, _SecondType, Never]

#: Type alias for kinds with three type arguments.
AsyncFuture3 = AwaitableFutureN[_FirstType, _SecondType, _ThirdType]


class FutureBasedN(
    FutureLikeN[_FirstType, _SecondType, _ThirdType],
    AwaitableFutureN[_FirstType, _SecondType, _ThirdType],
):
    """
    Base type for real ``Future`` objects.

    They can be awaited.
    """

    __slots__ = ()


#: Type alias for kinds with one type argument.
FutureBased1 = FutureBasedN[_FirstType, Never, Never]

#: Type alias for kinds with two type arguments.
FutureBased2 = FutureBasedN[_FirstType, _SecondType, Never]

#: Type alias for kinds with three type arguments.
FutureBased3 = FutureBasedN[_FirstType, _SecondType, _ThirdType]