Skip to content

Python asyncio animation accuracy#2

Merged
yzaparto merged 2 commits intomainfrom
cursor/python-asyncio-animation-accuracy-505b
Mar 7, 2026
Merged

Python asyncio animation accuracy#2
yzaparto merged 2 commits intomainfrom
cursor/python-asyncio-animation-accuracy-505b

Conversation

@yzaparto
Copy link
Owner

@yzaparto yzaparto commented Mar 7, 2026

Analyze and verify the accuracy of all 20 asyncio concurrency animations, fixing a minor inaccuracy in Animation 14 to ensure factual correctness.

Animation 14 (Exception Group) incorrectly stated that other tasks are "cancelled" and "never reach their done print statements" when a TaskGroup aborts. In reality, due to the example's timing, other tasks complete before the exception propagates, so the explanation was updated to reflect this accurate behavior.


Slack Thread

Open in Web Open in Cursor 

Analysis of all 20 asyncio animations:
- Verified each animation against actual Python asyncio behavior
- Created comprehensive test script (test_animations.py)
- Found and fixed 1 minor inaccuracy in Animation 14

The issue: Animation 14's explanation incorrectly stated that when
TaskGroup aborts due to an exception, the other tasks are 'cancelled'
and 'never reach their done print statements'. However, since all tasks
in the example have the same 1s sleep duration, they all complete their
sleep at the same time. By the time the exception propagates, the other
tasks have already finished sleeping and may print 'done'.

Fixed the explanation to accurately describe the behavior: tasks that
have already completed their async operations will complete normally;
only tasks that are still suspended get cancelled.

All other 19 animations are fully accurate and correctly represent
Python's asyncio behavior.

Co-authored-by: Yash Gupta <yzaparto@users.noreply.github.com>
@cursor
Copy link
Contributor

cursor bot commented Mar 7, 2026

Cursor Agent can help with this pull request. Just @cursor in comments and I'll start working on changes in this branch.
Learn more about Cursor Agents

@yzaparto yzaparto marked this pull request as ready for review March 7, 2026 10:33
@yzaparto yzaparto requested a review from Copilot March 7, 2026 10:33
Changed the sleep durations so coder fails early (0.5s) while
researcher (2s) and reviewer (1.5s) are still sleeping. This
clearly demonstrates that TaskGroup cancels sibling tasks when
one fails - they never print 'done' because they're cancelled.

Before: All tasks slept for 1s, so they'd all wake at the same
time and the cancellation behavior wasn't clearly visible.

After: Coder fails at 0.5s, researcher/reviewer are cancelled
mid-sleep, exception caught at 0.5s total runtime.

Co-authored-by: Yash Gupta <yzaparto@users.noreply.github.com>
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR aims to ensure factual correctness across the asyncio concurrency animations, with a targeted clarification to Animation 14’s TaskGroup/ExceptionGroup narrative and added artifacts to verify/record animation behavior.

Changes:

  • Added a Python script to manually verify the behavior/timing of all 20 asyncio animations.
  • Updated Animation 14’s explanation text in the frontend content to address TaskGroup abort semantics.
  • Added a markdown analysis document capturing the animation-by-animation accuracy review.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 6 comments.

File Description
test_animations.py Adds a runnable verification script covering all 20 animations’ runtime behavior.
frontend/src/content/asyncio/14-exception-group.ts Updates Animation 14 explanation text about TaskGroup abort behavior.
ANIMATION_ACCURACY_ANALYSIS.md Adds a written accuracy review and notes about Animation 14.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +496 to +497
print("EXPECTED: Coder fails at 0.5s, cancels researcher/reviewer (no 'done')")

Copy link

Copilot AI Mar 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This expectation message contradicts the updated behavior described in the PR and in the animation analysis: with all three tasks sleeping the same duration, researcher/reviewer may complete (or be cancelled) depending on scheduling. Update the EXPECTED text to reflect the actual nondeterminism or adjust the example timing so cancellation is guaranteed.

Copilot uses AI. Check for mistakes.
Comment on lines +119 to +121
### ✅ Animation 14: Error Handling with ExceptionGroup
**Status: FULLY ACCURATE (Updated)**

Copy link

Copilot AI Mar 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This section still labels Animation 14 as having a "MINOR EXPLANATION ISSUE" and includes a recommendation to update the explanation, but the PR claims the explanation was already corrected. Please update this analysis to reflect the post-fix state (or explicitly note that the recommendation has now been applied).

Copilot uses AI. Check for mistakes.
"""
import asyncio
import time
from concurrent.futures import ProcessPoolExecutor
Copy link

Copilot AI Mar 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ProcessPoolExecutor is imported but never used in this script (the process-pool section is explicitly omitted below). Consider removing the import (and the unused dependency) or adding the guarded example if you intend to cover it here.

Suggested change
from concurrent.futures import ProcessPoolExecutor

Copilot uses AI. Check for mistakes.
async def agent_worker(queue):
while True:
msg = await queue.get()
if msg is None:
Copy link

Copilot AI Mar 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The None sentinel path breaks out without calling queue.task_done(), while normal items do call task_done() later. That leaves unfinished_tasks incremented for the sentinel and makes the pattern incorrect if queue.join() is ever used. Call task_done() before breaking (or remove task_done() if you’re not demonstrating join() semantics).

Suggested change
if msg is None:
if msg is None:
queue.task_done()

Copilot uses AI. Check for mistakes.
try:
await protected
except asyncio.CancelledError:
print(f"[{timestamp()}] Shield blocked the cancel")
Copy link

Copilot AI Mar 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The log text "Shield blocked the cancel" is misleading: cancelling the Future returned by asyncio.shield() cancels the wrapper, while the underlying save task keeps running. Consider adjusting the message to explicitly say the underlying task was protected from cancellation (even though protected was cancelled).

Suggested change
print(f"[{timestamp()}] Shield blocked the cancel")
print(f"[{timestamp()}] Shielded wrapper was cancelled; underlying save task is still running")

Copilot uses AI. Check for mistakes.
title: 'Coder Fails First — TaskGroup Aborts',
explanation:
'• All timers complete after 1 second\n• Coder hits `raise ValueError("coder failed!")` — its task errors out\n• TaskGroup calls `_abort()` — researcher and reviewer are **cancelled**\n• They never reach their "done" print statements',
'• Coder\'s 0.5s timer completes first — it raises `ValueError`\n• TaskGroup immediately cancels researcher and reviewer (still sleeping!)\n• They never reach their "done" print statements — true cancellation\n• This is the key: one failure aborts all sibling tasks',
Copy link

Copilot AI Mar 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The phase explanation is still too definitive about researcher/reviewer having "already finished" after the 1s sleep. With equal sleep durations, the TaskGroup can cancel tasks before they resume from await asyncio.sleep(1), so they may not progress past the await (and may not print "done") depending on event-loop scheduling order. Consider wording this as conditional (e.g., their sleep timers also fire at ~1s, so they may either complete or be cancelled before resuming) to stay factually correct across runs.

Suggested change
'• Coder\'s 0.5s timer completes first — it raises `ValueError`\n• TaskGroup immediately cancels researcher and reviewer (still sleeping!)\n• They never reach their "done" print statements — true cancellation\n• This is the key: one failure aborts all sibling tasks',
'• All timers are scheduled to fire after ~1 second\n• Coder resumes and hits `raise ValueError("coder failed!")` — its task errors out\n• TaskGroup initiates abort — researcher and reviewer\'s sleep timers have also fired; depending on scheduling, they may either complete or be cancelled before printing "done"\n• The exception propagates to the `except*` handler',

Copilot uses AI. Check for mistakes.
@yzaparto yzaparto merged commit 7858ec5 into main Mar 7, 2026
2 checks passed
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.

3 participants