Fixed cancel scope crash without a current task on the asyncio backend - #1163
Fixed cancel scope crash without a current task on the asyncio backend#1163inoue22 wants to merge 3 commits into
Conversation
|
Just under what circumstances does it make any sense to call |
|
Thanks for taking a look, and for maintaining AnyIO. It isn't user code calling it outside a task. anyio's own primitives (locks, semaphores, capacity limiters) call On its own, the |
|
Let me rephrase: What sensible code would trigger this error? |
|
Or, is this only about confusing error messages when said APIs are misused? |
|
OK, so I would suggest changing the tests to use callbacks |
NOTE Erasing or replacing the contents of this template will result in your pull
request being summarily closed without consideration!
Changes
On the asyncio backend, entering a cancel scope while
asyncio.current_task()returnsNoneraised an obscureTypeError: cannot create weak reference to 'NoneType' object.CancelScope.__enter__used the host task as a key in aWeakKeyDictionary(_task_states[host_task]) without aNonecheck.This is reached through
CancelScope(shield=True)insidecancel_shielded_checkpoint(), which primitives such asCapacityLimiterandLockrely on, so using any of those whilecurrent_task()isNonecrashes instead of behaving gracefully.This is inconsistent with the rest of the backend:
checkpoint_if_cancelled()andcurrent_effective_deadline()already treatcurrent_task() is Noneas a benign no-op.This PR makes the asyncio backend consistent:
cancel_shielded_checkpoint()falls back to a plain checkpoint (await sleep(0)) whencurrent_task()isNone— with no current task there is nothing to shield from cancellation, mirroringcheckpoint_if_cancelled().CancelScope.__enter__now raises a clearRuntimeError("A cancel scope can only be entered from within a task")instead of the weakrefTypeError. TheCancelScopedocstring documents the new:raises RuntimeError:.The defect is independent of the Python version (reproduced identically on 3.12, 3.13 and 3.14).
Checklist
If this is a user-facing code change, like a bugfix or a new feature, please ensure that
you've fulfilled the following conditions (where applicable):
tests/) which would fail without your patchdocs/), in case of behavior changes or new features (N/A)docs/versionhistory.rst).If this is a trivial change, like a typo fix or a code reformatting, then you can ignore
these instructions.
Updating the changelog
If there are no entries after the last release, use
**UNRELEASED**as the version.If, say, your patch fixes issue #123, the entry should look like this:
If there's no issue linked, just link to your pull request instead by updating the
changelog after you've created the PR.