Skip to content

Commit e04c094

Browse files
committed
Closes #686
1 parent 79bae74 commit e04c094

File tree

14 files changed

+225
-130
lines changed

14 files changed

+225
-130
lines changed

docs/pages/context.rst

Lines changed: 2 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -319,72 +319,8 @@ Which means that it is a wrapper around impure async function that might fail.
319319

320320
Here's how it should be used:
321321

322-
.. code:: python
323-
324-
from typing import Callable, Sequence
325-
326-
import anyio # you would need to `pip install anyio`
327-
import httpx # you would need to `pip install httpx`
328-
from typing_extensions import Final, TypedDict
329-
330-
from returns.context import RequiresContextFutureResultE
331-
from returns.functions import tap
332-
from returns.future import FutureResultE, future_safe
333-
from returns.iterables import Fold
334-
from returns.pipeline import managed
335-
from returns.result import safe
336-
337-
_URL: Final = 'https://jsonplaceholder.typicode.com/posts/{0}'
338-
_Post = TypedDict('_Post', {
339-
'id': int,
340-
'userId': int,
341-
'title': str,
342-
'body': str,
343-
})
344-
_TitleOnly = TypedDict('_TitleOnly', {'title': str})
345-
346-
def _close(client: httpx.AsyncClient, _) -> FutureResultE[None]:
347-
return future_safe(client.aclose)()
348-
349-
def _fetch_post(
350-
post_id: int,
351-
) -> RequiresContextFutureResultE[_Post, httpx.AsyncClient]:
352-
context: RequiresContextFutureResultE[
353-
httpx.AsyncClient,
354-
httpx.AsyncClient,
355-
] = RequiresContextFutureResultE.ask()
356-
357-
return context.bind_future_result(
358-
lambda client: future_safe(client.get)(_URL.format(post_id)),
359-
).bind_result(
360-
safe(tap(httpx.Response.raise_for_status)),
361-
).map(
362-
lambda response: response.json(),
363-
)
364-
365-
def show_titles(
366-
number_of_posts: int,
367-
) -> RequiresContextFutureResultE[Sequence[_TitleOnly], httpx.AsyncClient]:
368-
titles = [
369-
# Notice how easily we compose async and sync functions:
370-
_fetch_post(post_id).map(lambda post: post['title'])
371-
# TODO: try `for post_id in {2, 1, 0}:` to see how errors work
372-
for post_id in range(1, number_of_posts + 1)
373-
]
374-
return Fold.collect(titles, RequiresContextFutureResultE.from_value(()))
375-
376-
if __name__ == '__main__':
377-
# Let's fetch 3 titles of posts asynchronously:
378-
managed_httpx = managed(show_titles(3), _close)
379-
future_result = managed_httpx(
380-
FutureResultE.from_value(httpx.AsyncClient(timeout=5)),
381-
)
382-
print(anyio.run(future_result.awaitable))
383-
# <IOResult: <Success: (
384-
# 'sunt aut facere repellat provident occaecati ...',
385-
# 'qui est esse',
386-
# 'ea molestias quasi exercitationem repellat qui ipsa sit aut',
387-
# )>>
322+
.. literalinclude:: ../../tests/test_examples/test_context/test_reader_future_result.py
323+
:linenos:
388324

389325
This example illustrates the whole point of our actions: writting
390326
sync code that executes asynchronously without any magic at all!

docs/pages/create-your-own-container.rst

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ Looks like it already knows what methods should be there!
138138
Ok, let's drop some initial and straight forward implementation.
139139
We will later make it more complex step by step.
140140

141-
.. literalinclude:: ../../tests/test_examples/test_pair1.py
141+
.. literalinclude:: ../../tests/test_examples/test_your_container/test_pair1.py
142142
:linenos:
143143

144144
You can check our resulting source with ``mypy``. It would be happy this time.
@@ -159,17 +159,17 @@ It would be also nice to add all other interfaces there as supertypes.
159159

160160
That's how it is going to look:
161161

162-
.. literalinclude:: ../../tests/test_examples/test_pair2.py
162+
.. literalinclude:: ../../tests/test_examples/test_your_container/test_pair2.py
163163
:linenos:
164164
:pyobject: PairLikeN
165165

166166
Awesome! Now we have a new interface to implement. Let's do that!
167167

168-
.. literalinclude:: ../../tests/test_examples/test_pair2.py
168+
.. literalinclude:: ../../tests/test_examples/test_your_container/test_pair2.py
169169
:linenos:
170170
:pyobject: Pair.pair
171171

172-
.. literalinclude:: ../../tests/test_examples/test_pair2.py
172+
.. literalinclude:: ../../tests/test_examples/test_your_container/test_pair2.py
173173
:linenos:
174174
:pyobject: Pair.from_unpaired
175175

@@ -194,7 +194,7 @@ This gives us several key benefits:
194194

195195
Let's add docs and doctests! Let's use ``map`` method as a short example:
196196

197-
.. literalinclude:: ../../tests/test_examples/test_pair3.py
197+
.. literalinclude:: ../../tests/test_examples/test_your_container/test_pair3.py
198198
:linenos:
199199
:pyobject: Pair.map
200200

@@ -215,13 +215,13 @@ Let's add them to our ``PairLikeN`` interface.
215215

216216
Let's start with laws definition:
217217

218-
.. literalinclude:: ../../tests/test_examples/test_pair4.py
218+
.. literalinclude:: ../../tests/test_examples/test_your_container/test_pair4.py
219219
:linenos:
220220
:pyobject: _LawSpec
221221

222222
And them let's add them to our ``PairLikeN`` interface:
223223

224-
.. literalinclude:: ../../tests/test_examples/test_pair4.py
224+
.. literalinclude:: ../../tests/test_examples/test_your_container/test_pair4.py
225225
:linenos:
226226
:pyobject: PairLikeN
227227
:emphasize-lines: 9-12
@@ -231,7 +231,7 @@ to generate 10 ``hypothesis`` test cases with hundreds real test cases inside.
231231

232232
Here's the final result of our brand new ``Pair`` type:
233233

234-
.. literalinclude:: ../../tests/test_examples/test_pair4.py
234+
.. literalinclude:: ../../tests/test_examples/test_your_container/test_pair4.py
235235
:linenos:
236236

237237

@@ -258,12 +258,12 @@ to make sure our ``.pair`` function works correctly:
258258
We need it since we store our example in ``tests/`` folder.
259259
And we have to tell ``mypy`` how to find it.
260260

261-
.. literalinclude:: ../../typesafety/test_examples/test_pair4_def.yml
261+
.. literalinclude:: ../../typesafety/test_examples/test_your_container/test_pair4_def.yml
262262
:linenos:
263263

264264
Ok, now, let's try to raise an error by using it incorrectly:
265265

266-
.. literalinclude:: ../../typesafety/test_examples/test_pair4_error.yml
266+
.. literalinclude:: ../../typesafety/test_examples/test_your_container/test_pair4_error.yml
267267
:linenos:
268268

269269

@@ -280,7 +280,7 @@ So, let's say we want to use native :func:`~returns.pointfree.map.map_`
280280
pointfree function with our new ``Pair`` type.
281281
Let's test that it will work correctly:
282282

283-
.. literalinclude:: ../../typesafety/test_examples/test_pair4_reuse.yml
283+
.. literalinclude:: ../../typesafety/test_examples/test_your_container/test_pair4_reuse.yml
284284
:linenos:
285285

286286
Yes, it works!

docs/pages/future.rst

Lines changed: 2 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -81,51 +81,8 @@ And is literally a wrapper around ``Future[Result[_V, _E]]`` type.
8181

8282
Let's see how it can be used in a real program:
8383

84-
.. code:: python
85-
86-
from typing import Sequence
87-
88-
import anyio # you would need to `pip install anyio`
89-
import httpx # you would need to `pip install httpx`
90-
from typing_extensions import Final, TypedDict
91-
92-
from returns.future import FutureResultE, future_safe
93-
from returns.iterables import Fold
94-
95-
_URL: Final = 'https://jsonplaceholder.typicode.com/posts/{0}'
96-
_Post = TypedDict('_Post', {
97-
'id': int,
98-
'userId': int,
99-
'title': str,
100-
'body': str,
101-
})
102-
_TitleOnly = TypedDict('_TitleOnly', {'title': str})
103-
104-
@future_safe
105-
async def _fetch_post(post_id: int) -> _Post:
106-
# Ideally, we can use `ReaderFutureResult` to provide `client` from deps.
107-
async with httpx.AsyncClient(timeout=5) as client:
108-
response = await client.get(_URL.format(post_id))
109-
response.raise_for_status()
110-
return response.json()
111-
112-
def show_titles(number_of_posts: int) -> FutureResultE[Sequence[_TitleOnly]]:
113-
titles = [
114-
# Notice how easily we compose async and sync functions:
115-
_fetch_post(post_id).map(lambda post: post['title'])
116-
# TODO: try `for post_id in {2, 1, 0}:` to see how errors work
117-
for post_id in range(1, number_of_posts + 1)
118-
]
119-
return Fold.collect(titles, FutureResultE.from_value(()))
120-
121-
if __name__ == '__main__':
122-
# Let's fetch 3 titles of posts asynchronously:
123-
print(anyio.run(show_titles(3).awaitable))
124-
# <IOResult: <Success: (
125-
# 'sunt aut facere repellat provident occaecati ...',
126-
# 'qui est esse',
127-
# 'ea molestias quasi exercitationem repellat qui ipsa sit aut',
128-
# )>>
84+
.. literalinclude:: ../../tests/test_examples/test_future/test_future_result.py
85+
:linenos:
12986

13087
What is different?
13188

poetry.lock

Lines changed: 72 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -60,16 +60,18 @@ typing-extensions = "^3.7"
6060

6161

6262
[tool.poetry.dev-dependencies]
63+
anyio = "^2.0"
64+
curio = "^1.4"
65+
trio = "^0.17"
66+
attrs = "^20.2"
67+
httpx = "^0.16"
68+
6369
mypy = "^0.790"
6470
wemake-python-styleguide = "^0.14"
6571
flake8-pytest-style = "^1.2"
6672
flake8-pyi = "^20.10"
6773
nitpick = "^0.23"
6874

69-
anyio = "^2.0"
70-
curio = "^1.4"
71-
trio = "^0.17"
72-
7375
safety = "^1.8"
7476

7577
pytest = "^6.1"
@@ -88,4 +90,3 @@ sphinx-hoverxref = "^0.5b1"
8890
doc8 = "^0.8"
8991
m2r = "^0.2"
9092
tomlkit = "^0.7"
91-
attrs = "^20.2"

0 commit comments

Comments
 (0)