Skip to content

Commit 0ccdb53

Browse files
committed
Adds ContextFutureResult, refs #274
1 parent f14b7ba commit 0ccdb53

File tree

5 files changed

+110
-1
lines changed

5 files changed

+110
-1
lines changed

docs/pages/context.rst

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,55 @@ Use it when you work with impure context-related functions that might fail.
302302
This is basically **the main type** that is going to be used in most apps.
303303

304304

305+
RequiresContextFutureResult container
306+
-------------------------------------
307+
308+
This container is a combintaion of ``RequiresContext[env, FutureResult[a, b]]``.
309+
Which means that it is a wrapper around impure async function that might fail.
310+
311+
We also added a lot of useful methods for this container,
312+
so you can work easily with it.
313+
314+
These methods are identical with ``RequiresContextIOResult``:
315+
316+
.. currentmodule:: returns.context.requires_context_future_result
317+
318+
- :meth:`~RequiresContextFutureResult.from_typecast`
319+
turns accidental ``RequiresContext[env, IOResult[a, b]]`` into
320+
full-featured ``RequiresContextFutureResult[env, a, b]``
321+
- :meth:`~RequiresContextFutureResult.bind_result`
322+
allows to bind functions that return ``Result`` with just one call
323+
- :meth:`~RequiresContextFutureResult.bind_io`
324+
allows to bind functions that return ``IO`` with just one call
325+
- :meth:`~RequiresContextFutureResult.bind_ioresult`
326+
allows to bind functions that return ``IOResult`` with just one call
327+
- :meth:`~RequiresContextFutureResult.bind_context`
328+
allows to bind functions that return ``RequiresContext`` easily
329+
- :meth:`~RequiresContextFutureResult.bind_context_result`
330+
allows to bind functions that return ``RequiresContextResult`` easily
331+
332+
There are new ones:
333+
334+
- :meth:`~RequiresContextFutureResult.bind_future`
335+
allows to bind functions that return ``Future`` container
336+
- :meth:`~RequiresContextFutureResult.bind_future_result`
337+
allows to bind functions that return ``FutureResult`` container
338+
- :meth:`~RequiresContextFutureResult.bind_async_future`
339+
allows to bind async functions that return ``Future`` container
340+
- :meth:`~RequiresContextFutureResult.bind_async_future_result`
341+
allows to bind async functions that return ``FutureResult`` container
342+
- :meth:`~RequiresContextFutureResult.bind_context_ioresult`
343+
allows to bind functions that return ``RequiresContextIOResult``
344+
- :meth:`~RequiresContextFutureResult.bind_async`
345+
allows to bind async functions
346+
that return ``RequiresContextFutureResult`` container
347+
- :meth:`~RequiresContextFutureResult.bind_awaitable`
348+
allows to bind async function that return raw values
349+
350+
Use it when you work with impure context-related functions that might fail.
351+
This is basically **the main type** that is going to be used in most apps.
352+
353+
305354
Aliases
306355
-------
307356

docs/pages/railway.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ when you try to ``.failure()`` a successful container.
169169
Note::
170170

171171
Not all containers support these methods.
172-
``IO`` and ``RequiresContext`` cannot be unwrapped.
172+
``IO`` based containers and ``RequiresContext`` cannot be unwrapped.
173173

174174

175175
Further reading

returns/context/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44
from returns.context.requires_context import NoDeps as NoDeps
55
from returns.context.requires_context import Reader as Reader
66
from returns.context.requires_context import RequiresContext as RequiresContext
7+
from returns.context.requires_context_future_result import (
8+
ContextFutureResult as ContextFutureResult,
9+
)
710
from returns.context.requires_context_future_result import (
811
ReaderFutureResult as ReaderFutureResult,
912
)

returns/context/requires_context_future_result.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
from abc import ABCMeta
12
from typing import (
23
TYPE_CHECKING,
34
Any,
@@ -16,6 +17,7 @@
1617
from returns.future import FutureResult
1718
from returns.io import IO, IOResult
1819
from returns.primitives.container import BaseContainer
20+
from returns.primitives.types import Immutable
1921
from returns.result import Result
2022

2123
if TYPE_CHECKING:
@@ -674,6 +676,47 @@ def from_failure(
674676
)
675677

676678

679+
@final
680+
class ContextFutureResult(Immutable, Generic[_EnvType], metaclass=ABCMeta):
681+
"""
682+
Helpers that can be used to work with ``ReaderFutureResult`` container.
683+
684+
Related to :class:`returns.context.requires_context.Context`
685+
and :class:`returns.context.requires_context_result.ContextResult`,
686+
refer there for the docs.
687+
"""
688+
689+
__slots__ = ()
690+
691+
@classmethod
692+
def ask(cls) -> RequiresContextFutureResult[_EnvType, _EnvType, Any]:
693+
"""
694+
Is used to get the current dependencies inside the call stack.
695+
696+
Similar to :meth:`returns.context.requires_context.Context.ask`,
697+
but returns ``IOResult`` instead of a regular value.
698+
699+
Please, refer to the docs there to learn how to use it.
700+
701+
One important note that is worth duplicating here:
702+
you might need to provide ``_EnvType`` explicitly,
703+
so ``mypy`` will know about it statically.
704+
705+
.. code:: python
706+
707+
>>> import anyio
708+
>>> from returns.context import ContextFutureResult
709+
>>> from returns.io import IOSuccess
710+
711+
>>> assert anyio.run(
712+
... ContextFutureResult[int].ask().map(str),
713+
... 1,
714+
... ) == IOSuccess('1')
715+
716+
"""
717+
return RequiresContextFutureResult(FutureResult.from_value)
718+
719+
677720
# Aliases:
678721

679722
#: Alias for a popular case when ``Result`` has ``Exception`` as error type.
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
- case: context_result_future_ask1
2+
disable_cache: true
3+
main: |
4+
from returns.context import ContextFutureResult
5+
6+
reveal_type(ContextFutureResult.ask()) # N: Revealed type is 'returns.context.requires_context_future_result.RequiresContextFutureResult[<nothing>, <nothing>, Any]'
7+
8+
9+
- case: context_result_future_ask2
10+
disable_cache: true
11+
main: |
12+
from returns.context import ContextFutureResult
13+
14+
reveal_type(ContextFutureResult[str].ask()) # N: Revealed type is 'returns.context.requires_context_future_result.RequiresContextFutureResult[builtins.str*, builtins.str*, Any]'

0 commit comments

Comments
 (0)