diff --git a/docs/tutorial/asyncify.md b/docs/tutorial/asyncify.md index 530e395a..9c39a529 100644 --- a/docs/tutorial/asyncify.md +++ b/docs/tutorial/asyncify.md @@ -16,24 +16,7 @@ Let's see a **broken** example first. Let's see a sync (regular, blocking) function `do_sync_work()`: -```Python hl_lines="3-5" -# Code above omitted 👆 - -{!./docs_src/tutorial/asyncify/tutorial001.py[ln:6-8]!} - -# Code below omitted 👇 -``` - -
-👀 Full file preview - -```Python -# 🚨 Don't use this, it will block the event loop! 🚨 - -{!./docs_src/tutorial/asyncify/tutorial001.py!} -``` - -
+{* docs_src/tutorial/asyncify/tutorial001.py ln[8:10] hl[8:10] *} This function could be talking to a database, a remote API, etc. But it doesn't use `await`, it just makes Python wait there without a warning using `time.sleep(1)`. @@ -43,11 +26,7 @@ Here's the problem. Let's just call that **slow** sync (regular, blocking) function directly from inside the async code 😱: -```Python hl_lines="14" -# 🚨 Don't use this, it will block the event loop! 🚨 - -{!./docs_src/tutorial/asyncify/tutorial001.py!} -``` +{* docs_src/tutorial/asyncify/tutorial001.py hl[14] *} Because that function is not async, but still it makes Python wait there, it will impede any other async code that could have been started from running. It will all have to **just wait** there doing nothing, wasting computation time. 😭 @@ -55,9 +34,7 @@ Because that function is not async, but still it makes Python wait there, it wil In those cases where you want to run "**sync**" (synchronous, blocking) code **from inside of async** code in a way that is compatible with the rest of the async code you can use **Asyncer**'s `asyncify()`. 🚀 -```Python hl_lines="4 13" -{!./docs_src/tutorial/asyncify/tutorial002.py!} -``` +{* docs_src/tutorial/asyncify/tutorial002.py hl[4,13] *} `asyncify()` takes the **sync (blocking) function** that you want to call and then returns another **async function** that takes the actual **arguments for the original sync function**. @@ -67,22 +44,7 @@ Then you can `await` that and get the return value that was **safely** executed Notice that now the function `do_sync_work` is not an `async` function: -```Python hl_lines="3-5" -# Code above omitted 👆 - -{!./docs_src/tutorial/asyncify/tutorial002.py[ln:7-9]!} - -# Code below omitted 👇 -``` - -
-👀 Full file preview - -```Python -{!./docs_src/tutorial/asyncify/tutorial002.py!} -``` - -
+{* docs_src/tutorial/asyncify/tutorial002.py ln[7:9] hl[7:9] *} ...it even has a line: diff --git a/docs/tutorial/first-steps.md b/docs/tutorial/first-steps.md index 2a77a5c8..0cb8a563 100644 --- a/docs/tutorial/first-steps.md +++ b/docs/tutorial/first-steps.md @@ -6,22 +6,7 @@ Asyncer is based on **AnyIO**, so let's start with a simple example just using * Let's start with a simple main async function. -```Python hl_lines="3-4" -# Code above omitted 👆 - -{!./docs_src/tutorial/first_steps/tutorial001.py[ln:9-11]!} - -# Code below omitted 👇 -``` - -
-👀 Full file preview - -```Python -{!./docs_src/tutorial/first_steps/tutorial001.py!} -``` - -
+{* docs_src/tutorial/first_steps/tutorial001.py ln[9:11] hl[9:10] *} When working with **async** code you normally use `async` and `await`. @@ -40,30 +25,13 @@ The function `do_work()` also needs to be declared with `async def` for us to be For this example, let's simulate that by making `do_work()` wait there for 1 second: -```Python hl_lines="3-4" -# Code above omitted 👆 - -{!./docs_src/tutorial/first_steps/tutorial001.py[ln:4-11]!} - -# Code below omitted 👇 -``` - -
-👀 Full file preview - -```Python -{!./docs_src/tutorial/first_steps/tutorial001.py!} -``` - -
+{* docs_src/tutorial/first_steps/tutorial001.py ln[4:11] hl[4:5] *} ## Run the Main Function As `main()` is an `async` function, we can't call it directly because we can't `await` it. Instead, we call it with `anyio.run()`: -```Python hl_lines="1 14" -{!./docs_src/tutorial/first_steps/tutorial001.py!} -``` +{* docs_src/tutorial/first_steps/tutorial001.py hl[1,14] *} `anyio.run()` will do everything necessary to call `main()`, handling all the `await` parts, and waiting there until it finishes. diff --git a/docs/tutorial/runnify.md b/docs/tutorial/runnify.md index a8f86e89..a6f30cbd 100644 --- a/docs/tutorial/runnify.md +++ b/docs/tutorial/runnify.md @@ -6,43 +6,13 @@ Continuing with the last example, let's see the first use case where **Asyncer** Let's say that now you want your async `main()` function to take arguments: -```Python hl_lines="3" -# Code above omitted 👆 - -{!./docs_src/tutorial/runnify/tutorial001.py[ln:10-12]!} - -# Code below omitted 👇 -``` - -
-👀 Full file preview - -```Python -{!./docs_src/tutorial/runnify/tutorial001.py!} -``` - -
+{* docs_src/tutorial/runnify/tutorial001.py ln[10:12] hl[10] *} ## Runnify with Arguments Now you can use `asyncer.runnify()` to run this function passing arguments: -```Python hl_lines="3" -# Code above omitted 👆 - -{!./docs_src/tutorial/runnify/tutorial001.py[ln:15]!} - -# Code below omitted 👇 -``` - -
-👀 Full file preview - -```Python -{!./docs_src/tutorial/runnify/tutorial001.py!} -``` - -
+{* docs_src/tutorial/runnify/tutorial001.py ln[15] hl[15] *} `asyncer.runnify()` takes the **async function** you want to call, and then it returns another function that **takes the positional and keyword arguments** needed, in this case it's just `name="World"`. diff --git a/docs/tutorial/soonify-return.md b/docs/tutorial/soonify-return.md index 6ffb378e..8241594b 100644 --- a/docs/tutorial/soonify-return.md +++ b/docs/tutorial/soonify-return.md @@ -12,22 +12,7 @@ I'll show you how to do that here. 🤓 Let's see the last example `do_work()` async function we used in the previous chapter: -```Python hl_lines="3-5" -# Code above omitted 👆 - -{!./docs_src/tutorial/soonify/tutorial002.py[ln:5-7]!} - -# Code below omitted 👇 -``` - -
-👀 Full file preview - -```Python -{!./docs_src/tutorial/soonify/tutorial002.py!} -``` - -
+{* docs_src/tutorial/soonify/tutorial002.py ln[5:7] hl[5:7] *} This function takes a parameter `name` and then it prints a message. @@ -39,22 +24,7 @@ But now let's say that we don't really want that function to print the message d Maybe because we could want to do something else later with the value, or for any other reason: -```Python hl_lines="5-6" -# Code above omitted 👆 - -{!./docs_src/tutorial/soonify_return/tutorial001.py[ln:5-8]!} - -# Code below omitted 👇 -``` - -
-👀 Full file preview - -```Python -{!./docs_src/tutorial/soonify_return/tutorial001.py!} -``` - -
+{* docs_src/tutorial/soonify_return/tutorial001.py ln[5:8] hl[7:8] *} ## Store `SoonValue` Objects @@ -66,43 +36,13 @@ task_group.soonify(async_function)(arg1, arg2) ...that call **returns a special object** (an instance of a class `SoonValue`) that you can store in a variable: -```Python hl_lines="11-13" -# Code above omitted 👆 - -{!./docs_src/tutorial/soonify_return/tutorial001.py[ln:5-15]!} - -# Code below omitted 👇 -``` - -
-👀 Full file preview - -```Python -{!./docs_src/tutorial/soonify_return/tutorial001.py!} -``` - -
+{* docs_src/tutorial/soonify_return/tutorial001.py ln[5:15] hl[13:15] *} ## Get the Return Value from `SoonValue` Objects When one of these async functions started with `soonify()` finishes, the **return value** of the function is **stored** inside the `SoonValue` object, in the **attribute** `soon_value1.value`: -```Python hl_lines="9" -# Code above omitted 👆 - -{!./docs_src/tutorial/soonify_return/tutorial001.py[ln:11-18]!} - -# Code below omitted 👇 -``` - -
-👀 Full file preview - -```Python -{!./docs_src/tutorial/soonify_return/tutorial001.py!} -``` - -
+{* docs_src/tutorial/soonify_return/tutorial001.py ln[11:18] hl[17] *} After the `async with` block, the **task group** will wait for all of the concurrent functions/tasks to finish **before** any code below is executed. @@ -136,22 +76,7 @@ All this **typing support** also means that you can use tools like **mypy** to v If you try to access the `soon_value1.value` attribute of the `SoonValue` object **inside** the `async with` block, you will **normally get an error**: -```Python hl_lines="8" -# Code above omitted 👆 - -{!./docs_src/tutorial/soonify_return/tutorial002.py[ln:11-19]!} - -# Code below omitted 👇 -``` - -
-👀 Full file preview - -```Python -{!./docs_src/tutorial/soonify_return/tutorial002.py!} -``` - -
+{* docs_src/tutorial/soonify_return/tutorial002.py ln[11:19] hl[16] *} That will raise an exception like this: @@ -176,22 +101,7 @@ Because of that, the `soon_value1.value` attributes of the `SoonValue` objects * You can check if the value is already available by using the `soon_value.ready` attribute, it will be `True` or `False`: -```Python hl_lines="6-8" linenums="1" -# Code above omitted 👆 - -{!./docs_src/tutorial/soonify_return/tutorial003.py[ln:11-16]!} - - # Code below omitted 👇 -``` - -
-👀 Full file preview - -```Python -{!./docs_src/tutorial/soonify_return/tutorial003.py!} -``` - -
+{* docs_src/tutorial/soonify_return/tutorial003.py ln[11:16] hl[14:16] *} Here we have an `await` inside the `async with` block. It sleeps for **2 seconds**. diff --git a/docs/tutorial/soonify.md b/docs/tutorial/soonify.md index 4a7182ad..f00c7177 100644 --- a/docs/tutorial/soonify.md +++ b/docs/tutorial/soonify.md @@ -10,24 +10,7 @@ Let's start by just calling an **async function 3 times**, one after the other. This is still **not concurrent** because Python will run each one in its turn: -```Python hl_lines="3-9" -# Code above omitted 👆 - -{!./docs_src/tutorial/soonify/tutorial001.py[ln:9-12]!} - -# Code below omitted 👇 -``` - -
-👀 Full file preview - -```Python -# 🚨 This is not concurrent 🚨 - -{!./docs_src/tutorial/soonify/tutorial001.py!} -``` - -
+{* docs_src/tutorial/soonify/tutorial001.py ln[11:14] hl[11:14] *} Python will see the first `await`, then it will know that **this might take a while**. @@ -53,27 +36,7 @@ Let's now use **Asyncer** to run these **3 functions concurrently**. 🎉 Use **Asyncer**'s `create_task_group()` in an `async with` block to create a **task group** object: -```Python hl_lines="3 8" -# Code above omitted 👆 - -{!./docs_src/tutorial/soonify/tutorial002.py[ln:2]!} - -# Code here omitted 👈 - -{!./docs_src/tutorial/soonify/tutorial002.py[ln:10-11]!} - # Code here omitted 👈 - -# Code below omitted 👇 -``` - -
-👀 Full file preview - -```Python -{!./docs_src/tutorial/soonify/tutorial002.py!} -``` - -
+{* docs_src/tutorial/soonify/tutorial002.py ln[2,10:12] hl[2,11] *} ## Task Group - Soonify One Function @@ -83,27 +46,7 @@ Pass it the async function to call. That returns another function that receives the **arguments** for the async function you want to call: -```Python hl_lines="9" -# Code above omitted 👆 - -{!./docs_src/tutorial/soonify/tutorial002.py[ln:2]!} - -# Code here omitted 👈 - -{!./docs_src/tutorial/soonify/tutorial002.py[ln:10-12]!} - # Code here omitted 👈 - -# Code below omitted 👇 -``` - -
-👀 Full file preview - -```Python -{!./docs_src/tutorial/soonify/tutorial002.py!} -``` - -
+{* docs_src/tutorial/soonify/tutorial002.py ln[2,10:12] hl[12] *} This tells this **task group** to run that function **soon**. @@ -113,27 +56,7 @@ It **won't run it right away** and make Python wait for it. Instead, the **task Now you can use the same `task_group.soonify()` to **add the other async functions** you want to call concurrently with their parameters: -```Python hl_lines="9-11" -# Code above omitted 👆 - -{!./docs_src/tutorial/soonify/tutorial002.py[ln:2]!} - -# Code here omitted 👈 - -{!./docs_src/tutorial/soonify/tutorial002.py[ln:10-14]!} - # Code here omitted 👈 - -# Code below omitted 👇 -``` - -
-👀 Full file preview - -```Python -{!./docs_src/tutorial/soonify/tutorial002.py!} -``` - -
+{* docs_src/tutorial/soonify/tutorial002.py ln[2,10:14] hl[12:14] *} After the `async with` block ends, Python takes it as if it had an implicit `await` there. @@ -143,31 +66,13 @@ Python will wait for all that to end in that `async with` block. It's like if th ## Review All the Code -```Python -{!./docs_src/tutorial/soonify/tutorial002.py!} -``` +{* docs_src/tutorial/soonify/tutorial002.py *} Python will start with the first async function call to `do_work()` with the parameters `name="Yury"`. It will start that `anyio.sleep(1)` and it will notice the `await` there: -```Python hl_lines="4" -# Code above omitted 👆 - -{!./docs_src/tutorial/soonify/tutorial002.py[ln:5-7]!} - -# Code below omitted 👇 -``` - -
-👀 Full file preview - -```Python -{!./docs_src/tutorial/soonify/tutorial002.py!} -``` - -
- +{* docs_src/tutorial/soonify/tutorial002.py ln[5:7] hl[6] *} That's the cue for Python to go and **run anything else** that might be **pending**. @@ -175,22 +80,7 @@ At that point, Python will notice another thing **pending to run**, the next cal At some point it will get back to the first `await` and see that it's now done, so it will continue with that code, and print a message: -```Python hl_lines="5" -# Code above omitted 👆 - -{!./docs_src/tutorial/soonify/tutorial002.py[ln:5-7]!} - -# Code below omitted 👇 -``` - -
-👀 Full file preview - -```Python -{!./docs_src/tutorial/soonify/tutorial002.py!} -``` - -
+{* docs_src/tutorial/soonify/tutorial002.py ln[5:7] hl[7] *} Because this was the first call, with `name="Yury"`, it will print: diff --git a/docs/tutorial/syncify-no-raise.md b/docs/tutorial/syncify-no-raise.md index 24e7e59e..cc078969 100644 --- a/docs/tutorial/syncify-no-raise.md +++ b/docs/tutorial/syncify-no-raise.md @@ -22,9 +22,7 @@ If you use `syncify()` directly in a mainly **sync** (blocking) program, by defa But `syncify()` has an **option** that you can set: `raise_sync_error=False`, that instead of raising an error will **run the async code**: -```Python hl_lines="14" -{!./docs_src/tutorial/syncify_no_raise/tutorial001.py!} -``` +{* docs_src/tutorial/syncify_no_raise/tutorial001.py hl[14] *} If `syncify()` is called from inside of an async program (so, from inside of some code called with `asyncify()`), it will do the same thing as always, send the async function from the **worker thread** to the **main async thread** and run it there. @@ -34,9 +32,7 @@ But if the program is not async, when using `syncify(raise_sync_error=False)`, i In this example, in the same file, we are running both an async and a sync program. -```Python hl_lines="28-29" -{!./docs_src/tutorial/syncify_no_raise/tutorial001.py!} -``` +{* docs_src/tutorial/syncify_no_raise/tutorial001.py hl[28:30] *} * We first run the async code, with `anyio.run()`. It starts the async function `main()`. * Then we run the sync code, we just call directly `sync_main()`. diff --git a/docs/tutorial/syncify.md b/docs/tutorial/syncify.md index a4002ebd..1dbc7d36 100644 --- a/docs/tutorial/syncify.md +++ b/docs/tutorial/syncify.md @@ -15,9 +15,7 @@ But async functions can only be awaited inside of other async functions, you can For these cases, where you are in **sync code** and need to **call an async function** from within the sync code in a way that is **sync-compatible**, you can use **Asyncer**'s `syncify()`: -```Python hl_lines="4 14" -{!./docs_src/tutorial/syncify/tutorial001.py!} -``` +{* docs_src/tutorial/syncify/tutorial001.py hl[4,14] *} The way this will work, step by step, is like this: diff --git a/docs_src/tutorial/asyncify/tutorial001.py b/docs_src/tutorial/asyncify/tutorial001.py index a6636dd0..ee3cb46f 100644 --- a/docs_src/tutorial/asyncify/tutorial001.py +++ b/docs_src/tutorial/asyncify/tutorial001.py @@ -1,3 +1,5 @@ +# 🚨 Don't use this, it will block the event loop! 🚨 + import time import anyio diff --git a/docs_src/tutorial/soonify/tutorial001.py b/docs_src/tutorial/soonify/tutorial001.py index 8e1ef509..97cf7f4f 100644 --- a/docs_src/tutorial/soonify/tutorial001.py +++ b/docs_src/tutorial/soonify/tutorial001.py @@ -1,3 +1,5 @@ +# 🚨 This is not concurrent 🚨 + import anyio diff --git a/mkdocs.yml b/mkdocs.yml index 2f6e59be..9623e5a5 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -115,6 +115,7 @@ markdown_extensions: class: mermaid format: !!python/name:pymdownx.superfences.fence_code_format pymdownx.tilde: + markdown_include_variants: null # pymdownx blocks pymdownx.blocks.admonition: diff --git a/requirements-docs.txt b/requirements-docs.txt index bad2196c..4c187caa 100644 --- a/requirements-docs.txt +++ b/requirements-docs.txt @@ -15,3 +15,4 @@ griffe-typingdoc==0.3.0 griffe-warnings-deprecated==1.1.0 typer == 0.20.0 mkdocs-macros-plugin==1.5.0 +markdown-include-variants==0.0.5