Skip to content

Update async features examples for Python 3.14 - #798

Open
lpozo wants to merge 2 commits into
masterfrom
update-async-features-python-314
Open

Update async features examples for Python 3.14#798
lpozo wants to merge 2 commits into
masterfrom
update-async-features-python-314

Conversation

@lpozo

@lpozo lpozo commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Refreshes the sample code for understanding-asynchronous-programming, which backs Getting Started With Async Features in Python. Paired with the light update on that tutorial (CMS clone: post 2283).

The repo copy had drifted further than the article itself — it still pinned aiohttp==3.5.4 and requests==2.21.0 from 2019.

Correctness and modernization

  • while tasks: instead of the done flag (examples 2, 3, 5). This came from a reader suggestion, and it also fixes a latent bug: the old loop removed items from tasks while iterating over it, which can skip a task. The loop now iterates over tasks.copy().
  • asyncio.gather()async with asyncio.TaskGroup() (examples 4 and 6). Task groups are the recommended default since Python 3.11 and cancel remaining tasks when one fails.
  • asyncio.timeout(10) around the HTTP request in example 6, so an unresponsive server can't stall a task indefinitely.
  • Renamed the queue parameter to work_queue in examples 2 and 3, where it was shadowing the queue module.
  • Dropped the stray from builtins import range in example 2 (an IDE artifact — it's a no-op on Python 3).
  • URL lists moved to https://, with the dead entries replaced. twitter.com now redirects to x.com, and yahoo.com returns 404 over https, so it was dropped.
  • requirements.txt refreshed to current releases, keeping only the three direct dependencies rather than the full frozen transitive set.

Readability

A second pass after review of the article's code blocks:

  • Early return instead of an else branch in example 1, so the main loop body isn't indented behind a conditional.
  • Descriptive loop variables in example 1's runner — task_func, task_name, tasks_queue rather than t, n, q.
  • tcurrent_task in the generator-driving loops of examples 2, 3, and 5.
  • _ for the unused counter in examples 1 and 2.
  • URL lists extracted into a urls variable in examples 5 and 6, instead of being inlined in the for statement header.
  • Boilerplate docstrings and step comments dropped — they restated what the code already says.

Example 1 keeps its list of (function, name, queue) tuples on purpose. Deferring the call is exactly the thing example 2 changes when task() becomes a generator, so the two files stay minimally different.

Verification

All six examples run on Python 3.14.6 with the pinned requirements:

file result
example_1.py ok — output matches the article byte for byte
example_2.py ok — output matches the article byte for byte
example_3.py ok — total 32.0s
example_4.py ok — total 17.0s
example_5.py ok — total ~3.0s
example_6.py ok — total ~1.2s

Examples 5 and 6 hit the live network, so their timings vary between runs. The async version stays roughly twice as fast as the sync one, which is the point the tutorial makes.

black -l 79 and flake8 --max-line-length 79 are both clean.

The code here is semantically identical to the code blocks in the updated article, verified line by line. This repo's PEP 8 blank-line formatting is preserved, including the blank line between the standard-library and third-party import groups — the article renders the same code with single blank lines, so the tutorial's python -m asyncio pstree output cites the line numbers from these files (example_4.py:12 and :22) and says so in a note.

🤖 Generated with Claude Code

lpozo and others added 2 commits July 29, 2026 10:57
Refresh the code for the "Getting Started With Async Features in
Python" tutorial update.

- Replace the `done`-flag loops with `while tasks:`, and iterate over
  a copy so removing an exhausted generator can't skip a task
- Switch `asyncio.gather()` to `async with asyncio.TaskGroup()` in
  examples 4 and 6 (Python 3.11+)
- Guard each HTTP request in example 6 with `asyncio.timeout(10)`
- Rename the `queue` parameter to `work_queue` so it stops shadowing
  the `queue` module
- Drop the stray `from builtins import range` in example 2
- Move the URL lists to https and replace the dead entries
  (twitter.com now redirects to x.com, yahoo.com returns 404)
- Refresh requirements.txt to current releases and drop the
  transitive pins

All six examples verified on Python 3.14.6.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Follow-up to the Python 3.14 refresh, applying review feedback on the
sample code for "Getting Started With Async Features in Python".

- Replace the `else` branch in example 1 with an early `return`, so the
  main loop body isn't indented behind a conditional
- Name the loop variables in example 1's runner (`task_func`,
  `task_name`, `tasks_queue`) instead of `t`, `n`, `q`
- Rename `t` to `current_task` in the generator-driving loops of
  examples 2, 3, and 5
- Use `_` for the unused counter variable in examples 1 and 2
- Extract the URL lists in examples 5 and 6 into a `urls` variable
  rather than inlining them in the `for` statement header
- Drop the boilerplate docstrings and step comments, which restated
  what the code already says

All six examples verified on Python 3.14.6 against the tutorial output.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant