Skip to content

Commit 7e117cc

Browse files
committed
Adds several .bind_ methods, refs #274
1 parent 282a61c commit 7e117cc

14 files changed

+436
-21
lines changed

returns/_generated/pointfree/bind_context.pyi

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ from typing_extensions import Protocol
44

55
from returns.context import (
66
RequiresContext,
7+
RequiresContextFutureResult,
78
RequiresContextIOResult,
89
RequiresContextResult,
910
)
@@ -38,6 +39,15 @@ class _BindContext(Protocol[_EnvType, _ValueType, _NewValueType]):
3839
) -> RequiresContextIOResult[_EnvType, _NewValueType, _ErrorType]:
3940
...
4041

42+
@overload
43+
def __call__(
44+
self,
45+
container: RequiresContextFutureResult[
46+
_EnvType, _ValueType, _ErrorType,
47+
],
48+
) -> RequiresContextFutureResult[_EnvType, _NewValueType, _ErrorType]:
49+
...
50+
4151

4252
def _bind_context(
4353
function: Callable[[_ValueType], RequiresContext[_EnvType, _NewValueType]],

returns/_generated/pointfree/bind_context_result.pyi

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
1-
from typing import Callable, TypeVar
1+
from typing import Callable, TypeVar, overload
22

33
from typing_extensions import Protocol
44

5-
from returns.context import RequiresContextIOResult, RequiresContextResult
5+
from returns.context import (
6+
RequiresContextFutureResult,
7+
RequiresContextIOResult,
8+
RequiresContextResult,
9+
)
610

711
_ValueType = TypeVar('_ValueType', contravariant=True)
812
_ErrorType = TypeVar('_ErrorType')
@@ -22,12 +26,22 @@ class _BindContextResult(
2226
It is also completely removed from typing with the help of the mypy plugin.
2327
"""
2428

29+
@overload
2530
def __call__(
2631
self,
2732
container: RequiresContextIOResult[_EnvType, _ValueType, _ErrorType],
2833
) -> RequiresContextIOResult[_EnvType, _NewValueType, _ErrorType]:
2934
...
3035

36+
@overload
37+
def __call__(
38+
self,
39+
container: RequiresContextFutureResult[
40+
_EnvType, _ValueType, _ErrorType,
41+
],
42+
) -> RequiresContextFutureResult[_EnvType, _NewValueType, _ErrorType]:
43+
...
44+
3145

3246
def _bind_context_result(
3347
function: Callable[

returns/_generated/pointfree/bind_io.pyi

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ from typing import Callable, TypeVar, overload
22

33
from typing_extensions import Protocol
44

5-
from returns.context import RequiresContextIOResult
5+
from returns.context import RequiresContextFutureResult, RequiresContextIOResult
66
from returns.future import Future, FutureResult
77
from returns.io import IO, IOResult
88

@@ -29,6 +29,15 @@ class _BindIO(Protocol[_ValueType, _NewValueType]):
2929
) -> RequiresContextIOResult[_EnvType, _NewValueType, _ErrorType]:
3030
...
3131

32+
@overload
33+
def __call__(
34+
self,
35+
container: RequiresContextFutureResult[
36+
_EnvType, _ValueType, _ErrorType,
37+
],
38+
) -> RequiresContextFutureResult[_EnvType, _NewValueType, _ErrorType]:
39+
...
40+
3241
@overload
3342
def __call__(
3443
self,

returns/_generated/pointfree/bind_ioresult.pyi

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ from typing import Callable, TypeVar, overload
22

33
from typing_extensions import Protocol
44

5-
from returns.context import RequiresContextIOResult
5+
from returns.context import RequiresContextFutureResult, RequiresContextIOResult
66
from returns.future import FutureResult
77
from returns.io import IOResult
88

@@ -29,6 +29,15 @@ class _BindIOResult(Protocol[_ValueType, _NewValueType, _ErrorType]):
2929
) -> RequiresContextIOResult[_EnvType, _NewValueType, _ErrorType]:
3030
...
3131

32+
@overload
33+
def __call__(
34+
self,
35+
container: RequiresContextFutureResult[
36+
_EnvType, _ValueType, _ErrorType,
37+
],
38+
) -> RequiresContextFutureResult[_EnvType, _NewValueType, _ErrorType]:
39+
...
40+
3241
@overload
3342
def __call__(
3443
self,

returns/_generated/pointfree/bind_result.pyi

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,11 @@ from typing import Callable, TypeVar, overload
22

33
from typing_extensions import Protocol
44

5-
from returns.context import RequiresContextIOResult, RequiresContextResult
5+
from returns.context import (
6+
RequiresContextFutureResult,
7+
RequiresContextIOResult,
8+
RequiresContextResult,
9+
)
610
from returns.future import FutureResult
711
from returns.io import IOResult
812
from returns.result import Result
@@ -37,6 +41,15 @@ class _BindResult(Protocol[_ValueType, _NewValueType, _ErrorType]):
3741
) -> RequiresContextIOResult[_EnvType, _NewValueType, _ErrorType]:
3842
...
3943

44+
@overload
45+
def __call__(
46+
self,
47+
container: RequiresContextFutureResult[
48+
_EnvType, _ValueType, _ErrorType,
49+
],
50+
) -> RequiresContextFutureResult[_EnvType, _NewValueType, _ErrorType]:
51+
...
52+
4053
@overload
4154
def __call__(
4255
self,

returns/context/requires_context_future_result.py

Lines changed: 231 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,26 @@
1-
from typing import Any, Awaitable, Callable, ClassVar, Generic, TypeVar, Union
1+
from typing import (
2+
TYPE_CHECKING,
3+
Any,
4+
Awaitable,
5+
Callable,
6+
ClassVar,
7+
Generic,
8+
TypeVar,
9+
Union,
10+
)
211

312
from typing_extensions import final
413

514
from returns._generated.futures import _future_result
615
from returns.context import NoDeps
716
from returns.future import FutureResult
8-
from returns.io import IO
17+
from returns.io import IO, IOResult
918
from returns.primitives.container import BaseContainer
19+
from returns.result import Result
20+
21+
if TYPE_CHECKING:
22+
from returns.context.requires_context import RequiresContext
23+
from returns.context.requires_context_result import RequiresContextResult
1024

1125
# Context:
1226
_EnvType = TypeVar('_EnvType', contravariant=True)
@@ -202,6 +216,221 @@ def bind(
202216
),
203217
)
204218

219+
def bind_result(
220+
self,
221+
function: Callable[[_ValueType], 'Result[_NewValueType, _ErrorType]'],
222+
) -> 'RequiresContextFutureResult[_EnvType, _NewValueType, _ErrorType]':
223+
"""
224+
Binds ``Result`` returning function to the current container.
225+
226+
.. code:: python
227+
228+
>>> import anyio
229+
>>> from returns.context import RequiresContextFutureResult
230+
>>> from returns.result import Success, Failure, Result
231+
>>> from returns.io import IOSuccess, IOFailure
232+
233+
>>> def function(num: int) -> Result[int, str]:
234+
... return Success(num + 1) if num > 0 else Failure('<0')
235+
236+
>>> assert anyio.run(
237+
... RequiresContextFutureResult.from_value(1).bind_result(
238+
... function,
239+
... ),
240+
... RequiresContextFutureResult.empty,
241+
... ) == IOSuccess(2)
242+
243+
>>> assert anyio.run(
244+
... RequiresContextFutureResult.from_value(0).bind_result(
245+
... function,
246+
... ),
247+
... RequiresContextFutureResult.empty,
248+
... ) == IOFailure('<0')
249+
250+
>>> assert anyio.run(
251+
... RequiresContextFutureResult.from_failure(':(').bind_result(
252+
... function,
253+
... ),
254+
... RequiresContextFutureResult.empty,
255+
... ) == IOFailure(':(')
256+
257+
"""
258+
return RequiresContextFutureResult(
259+
lambda deps: self(deps).bind_result(function),
260+
)
261+
262+
def bind_context(
263+
self,
264+
function: Callable[
265+
[_ValueType],
266+
'RequiresContext[_EnvType, _NewValueType]',
267+
],
268+
) -> 'RequiresContextFutureResult[_EnvType, _NewValueType, _ErrorType]':
269+
"""
270+
Binds ``RequiresContext`` returning function to current container.
271+
272+
.. code:: python
273+
274+
>>> import anyio
275+
>>> from returns.context import RequiresContext
276+
>>> from returns.io import IOSuccess, IOFailure
277+
278+
>>> def function(arg: int) -> RequiresContext[str, int]:
279+
... return RequiresContext(lambda deps: len(deps) + arg)
280+
281+
>>> assert function(2)('abc') == 5
282+
283+
>>> assert anyio.run(
284+
... RequiresContextFutureResult.from_value(2).bind_context(
285+
... function,
286+
... ),
287+
... 'abc',
288+
... ) == IOSuccess(5)
289+
290+
>>> assert anyio.run(
291+
... RequiresContextFutureResult.from_failure(0).bind_context(
292+
... function,
293+
... ),
294+
... 'abc',
295+
... ) == IOFailure(0)
296+
297+
"""
298+
return RequiresContextFutureResult(
299+
lambda deps: self(deps).map(
300+
lambda inner: function(inner)(deps), # type: ignore[misc]
301+
),
302+
)
303+
304+
def bind_context_result(
305+
self,
306+
function: Callable[
307+
[_ValueType],
308+
'RequiresContextResult[_EnvType, _NewValueType, _ErrorType]',
309+
],
310+
) -> 'RequiresContextFutureResult[_EnvType, _NewValueType, _ErrorType]':
311+
"""
312+
Binds ``RequiresContextResult`` returning function to the current one.
313+
314+
.. code:: python
315+
316+
>>> import anyio
317+
>>> from returns.context import RequiresContextResult
318+
>>> from returns.io import IOSuccess, IOFailure
319+
>>> from returns.result import Success, Failure
320+
321+
>>> def function(arg: int) -> RequiresContextResult[str, int, int]:
322+
... if arg > 0:
323+
... return RequiresContextResult(
324+
... lambda deps: Success(len(deps) + arg),
325+
... )
326+
... return RequiresContextResult(
327+
... lambda deps: Failure(len(deps) + arg),
328+
... )
329+
330+
>>> assert function(2)('abc') == Success(5)
331+
>>> assert function(-1)('abc') == Failure(2)
332+
333+
>>> instance = RequiresContextFutureResult.from_value(
334+
... 2,
335+
... ).bind_context_result(
336+
... function,
337+
... )('abc')
338+
>>> assert anyio.run(instance.awaitable) == IOSuccess(5)
339+
340+
>>> instance = RequiresContextFutureResult.from_value(
341+
... -1,
342+
... ).bind_context_result(
343+
... function,
344+
... )('abc')
345+
>>> assert anyio.run(instance.awaitable) == IOFailure(2)
346+
347+
>>> instance = RequiresContextFutureResult.from_failure(
348+
... 2,
349+
... ).bind_context_result(
350+
... function,
351+
... )('abc')
352+
>>> assert anyio.run(instance.awaitable) == IOFailure(2)
353+
354+
"""
355+
return RequiresContextFutureResult(
356+
lambda deps: self(deps).bind_result(
357+
lambda inner: function(inner)(deps), # type: ignore[misc]
358+
),
359+
)
360+
361+
def bind_io(
362+
self,
363+
function: Callable[[_ValueType], IO[_NewValueType]],
364+
) -> 'RequiresContextFutureResult[_EnvType, _NewValueType, _ErrorType]':
365+
"""
366+
Binds ``IO`` returning function to the current container.
367+
368+
.. code:: python
369+
370+
>>> import anyio
371+
>>> from returns.context import RequiresContextFutureResult
372+
>>> from returns.io import IO, IOSuccess, IOFailure
373+
374+
>>> def do_io(number: int) -> IO[str]:
375+
... return IO(str(number)) # not IO operation actually
376+
377+
>>> assert anyio.run(
378+
... RequiresContextFutureResult.from_value(1).bind_io(do_io),
379+
... RequiresContextFutureResult.empty,
380+
... ) == IOSuccess('1')
381+
382+
>>> assert anyio.run(
383+
... RequiresContextFutureResult.from_failure(1).bind_io(do_io),
384+
... RequiresContextFutureResult.empty,
385+
... ) == IOFailure(1)
386+
387+
"""
388+
return RequiresContextFutureResult(
389+
lambda deps: self(deps).bind_io(function),
390+
)
391+
392+
def bind_ioresult(
393+
self,
394+
function: Callable[[_ValueType], IOResult[_NewValueType, _ErrorType]],
395+
) -> 'RequiresContextFutureResult[_EnvType, _NewValueType, _ErrorType]':
396+
"""
397+
Binds ``IOResult`` returning function to the current container.
398+
399+
.. code:: python
400+
401+
>>> import anyio
402+
>>> from returns.context import RequiresContextFutureResult
403+
>>> from returns.io import IOResult, IOSuccess, IOFailure
404+
405+
>>> def function(num: int) -> IOResult[int, str]:
406+
... return IOSuccess(num + 1) if num > 0 else IOFailure('<0')
407+
408+
>>> assert anyio.run(
409+
... RequiresContextFutureResult.from_value(1).bind_ioresult(
410+
... function,
411+
... ),
412+
... RequiresContextFutureResult.empty,
413+
... ) == IOSuccess(2)
414+
415+
>>> assert anyio.run(
416+
... RequiresContextFutureResult.from_value(0).bind_ioresult(
417+
... function,
418+
... ),
419+
... RequiresContextFutureResult.empty,
420+
... ) == IOFailure('<0')
421+
422+
>>> assert anyio.run(
423+
... RequiresContextFutureResult.from_failure(':(').bind_ioresult(
424+
... function,
425+
... ),
426+
... RequiresContextFutureResult.empty,
427+
... ) == IOFailure(':(')
428+
429+
"""
430+
return RequiresContextFutureResult(
431+
lambda deps: self(deps).bind_ioresult(function),
432+
)
433+
205434
def fix(
206435
self, function: Callable[[_ErrorType], _NewValueType],
207436
) -> 'RequiresContextFutureResult[_EnvType, _NewValueType, _ErrorType]':

0 commit comments

Comments
 (0)