ruff ASYNC115
labelled unknown
Analysis Nemotron 3 Super
Flags calls to trio.sleep(0) or anyio.sleep(0) and suggests replacing them with explicit checkpoint functions.
Fix: Replace trio.sleep(0) with trio.lowlevel.checkpoint() and anyio.sleep(0) with anyio.checkpoint(), preserving the await keyword and surrounding expression structure.
12 hazards
- If trio or anyio is imported as an alias (e.g., import trio as t), the fix may incorrectly reference trio.lowlevel.checkpoint instead of the aliased module, causing AttributeError.
- If trio.sleep or anyio.sleep is shadowed by a local variable or function, the fix will replace the wrong symbol, leading to incorrect behavior or NameError.
- If the call is part of a larger expression (e.g., f(trio.sleep(0))), replacing only the call may break argument ordering or introduce syntax errors if not handled contextually.
- If the sleep call appears in a default argument or lambda, moving the checkpoint call may alter evaluation timing or scope, especially if closure variables are involved.
- If the module trio.lowlevel or anyio is not imported, the fix may introduce a NameError unless the import is added, which the autofix may not do.
- If there are comments inside the call parentheses (e.g., trio.sleep( # comment 0 )), the fix may drop them, violating user intent even if semantically equivalent.
- If the code uses from trio import sleep, the fix cannot safely rewrite to trio.lowlevel.checkpoint without knowing the original import form, risking incorrect module references.
- If the code is in a string or comment (e.g., docstring or # await trio.sleep(0)), the tool might incorrectly flag and modify it, breaking documentation or introducing invalid code.
- If the sleep function is accessed via getattr or dynamic lookup (e.g., getattr(trio, 'sleep')(0)), the fix cannot apply safely as it assumes a direct attribute access.
- If the code runs under a mock or test patch where trio.sleep is replaced, the fix may bypass the mock and call the real checkpoint, altering test behavior.
- If the expression uses keyword arguments like trio.sleep(delay=0), the fix may fail to match or incorrectly rewrite, especially if mixed with positional args.
- If the file has encoding issues or non-standard whitespace, the autofix may misidentify the boundaries of the expression, leading to malformed replacement.
Programs
| id | result | title | hazard |
|---|---|---|---|
| r1-p001 | fix ok | Encoding and Whitespace Boundary Misidentification | If the file has encoding issues or non-standard whitespace, the autofix may misidentify the boundaries of the expression, leading to malformed replacement. |
| r1-p002 | fix ok prediction off | File Modes and Truncation Partial Writes | file modes and truncation, partial writes, non-str data passed to write |
| r1-p003 | fix ok | Import Alias Misreference | If trio or anyio is imported as an alias (e.g., import trio as t), the fix may incorrectly reference trio.lowlevel.checkpoint instead of the aliased module, causing AttributeError. |
| r1-p004 | fix ok | Mock Patch Bypass | If the code runs under a mock or test patch where trio.sleep is replaced, the fix may bypass the mock and call the real checkpoint, altering test behavior. |
| r1-p005 | fix ok | Evaluation Order and Side Effects | evaluation order and side effects when expressions are merged, duplicated or deleted |
| r1-p006 | fix ok | String or Comment False Positive | If the code is in a string or comment (e.g., docstring or # await trio.sleep(0)), the tool might incorrectly flag and modify it, breaking documentation or introducing invalid code. |
| r1-p007 | fix ok | Missing Module Import NameError | If the module trio.lowlevel or anyio is not imported, the fix may introduce a NameError unless the import is added, which the autofix may not do. |
| r1-p008 | silent prediction off | Int/Float/Bool Coercion Edge Cases | int/float/bool coercion, Decimal, division and rounding |
| r2-p001 | silent prediction off | Keyword argument usage | If the expression uses keyword arguments like trio.sleep(delay=0), the fix may fail to match or incorrectly rewrite, especially if mixed with positional args. |
| r2-p002 | invalid | Parameter forwarding with defaults | keyword-only, positional-only, *args/**kwargs forwarding, defaults evaluated once |
| r2-p003 | fix ok | Import alias mismatch | If trio or anyio is imported as an alias (e.g., import trio as t), the fix may incorrectly reference trio.lowlevel.checkpoint instead of the aliased module, causing AttributeError. |
| r2-p004 | fix ok | From import prevents safe rewrite | If the code uses from trio import sleep, the fix cannot safely rewrite to trio.lowlevel.checkpoint without knowing the original import form, risking incorrect module references. |
| r2-p005 | fired, no fix | Comment inside parentheses | If there are comments inside the call parentheses (e.g., trio.sleep( # comment\n 0 )), the fix may drop them, violating user intent even if semantically equivalent. |
| r2-p006 | silent | Dynamic attribute access via getattr | If the sleep function is accessed via getattr or dynamic lookup (e.g., getattr(trio, 'sleep')(0)), the fix cannot apply safely as it assumes a direct attribute access. |
| r2-p007 | fix ok | Missing lowlevel import | If the module trio.lowlevel or anyio is not imported, the fix may introduce a NameError unless the import is added, which the autofix may not do. |
| r2-p008 | fix ok | Comments on removed/moved code | comments and docstrings attached to the removed or moved code |
Sources
r1-p001 · Encoding and Whitespace Boundary Misidentification
1# -*- coding: utf-8 -*-
2import trio
3async def main():
4 x = 0
5 y = [
6 await trio.sleep( 0 ) # tab and space after comma
7 if False else None,
8 ]
9 print('y[0]:', y[0])
10try:
11 import asyncio
12 asyncio.run(main())
13except Exception as e:
14 print(f'{type(e).__name__}: {e}')
--- orig.py 2026-10-17 16:10:39.206082574 -0400 +++ fixed.py 2026-10-17 16:10:39.646069961 -0400 @@ -1,9 +1,10 @@ # -*- coding: utf-8 -*- import trio +import trio.lowlevel async def main(): x = 0 y = [ - await trio.sleep( 0 ) # tab and space after comma + await trio.lowlevel.checkpoint() # tab and space after comma if False else None, ] print('y[0]:', y[0])
r1-p002 · File Modes and Truncation Partial Writes
1import trio
2async def main():
3 with open('test.bin', 'wb') as f:
4 try:
5 f.write(b'before')
6 await trio.sleep(0)
7 f.write(b'after')
8 except Exception as e:
9 print(f'{type(e).__name__}: {e}')
10 finally:
11 f.seek(0)
12 print('read:', f.read())
13import asyncio
14import os
15asyncio.run(main())
16os.remove('test.bin')
--- orig.py 2026-10-17 16:10:39.844064285 -0400 +++ fixed.py 2026-10-17 16:10:40.253052577 -0400 @@ -1,9 +1,10 @@ import trio +import trio.lowlevel async def main(): with open('test.bin', 'wb') as f: try: f.write(b'before') - await trio.sleep(0) + await trio.lowlevel.checkpoint() f.write(b'after') except Exception as e: print(f'{type(e).__name__}: {e}')
r1-p003 · Import Alias Misreference
1import trio as t
2import anyio as a
3async def main():
4 await t.sleep(0)
5 await a.sleep(0)
6 print('both checkpoints passed')
7try:
8 import asyncio
9 asyncio.run(main())
10except Exception as e:
11 print(f'{type(e).__name__}: {e}')
--- orig.py 2026-10-17 16:10:40.468046427 -0400 +++ fixed.py 2026-10-17 16:10:40.844035672 -0400 @@ -1,8 +1,10 @@ import trio as t import anyio as a +import trio.lowlevel +import anyio.lowlevel async def main(): - await t.sleep(0) - await a.sleep(0) + await trio.lowlevel.checkpoint() + await anyio.lowlevel.checkpoint() print('both checkpoints passed') try: import asyncio
r1-p004 · Mock Patch Bypass
1import trio
2from unittest.mock import patch
3async def main():
4 with patch('trio.sleep', return_value='mocked'):
5 result = await trio.sleep(0)
6 print('result:', repr(result))
7try:
8 import asyncio
9 asyncio.run(main())
10except Exception as e:
11 print(f'{type(e).__name__}: {e}')
--- orig.py 2026-10-17 16:10:41.071029184 -0400 +++ fixed.py 2026-10-17 16:10:41.454018253 -0400 @@ -1,8 +1,9 @@ import trio from unittest.mock import patch +import trio.lowlevel async def main(): with patch('trio.sleep', return_value='mocked'): - result = await trio.sleep(0) + result = await trio.lowlevel.checkpoint() print('result:', repr(result)) try: import asyncio
r1-p005 · Evaluation Order and Side Effects
1import trio
2counter = 0
3async def inc():
4 global counter
5 counter += 1
6 return counter
7async def main():
8 global counter
9 counter = 0
10 results = []
11 for i in range(2):
12 val = inc()
13 await trio.sleep(0)
14 results.append((val, counter))
15 print('results:', results)
16try:
17 import asyncio
18 asyncio.run(main())
19except Exception as e:
20 print(f'{type(e).__name__}: {e}')
--- orig.py 2026-10-17 16:10:41.684011689 -0400 +++ fixed.py 2026-10-17 16:10:42.099999823 -0400 @@ -1,4 +1,5 @@ import trio +import trio.lowlevel counter = 0 async def inc(): global counter @@ -10,7 +11,7 @@ results = [] for i in range(2): val = inc() - await trio.sleep(0) + await trio.lowlevel.checkpoint() results.append((val, counter)) print('results:', results) try:
r1-p006 · String or Comment False Positive
1import trio
2async def main():
3 """This is a docstring with await trio.sleep(0) inside."""
4 s = 'not await trio.sleep(0)'
5 # await trio.sleep(0) # this is a comment
6 await trio.sleep(0) # real call
7 print('slept')
8try:
9 import asyncio
10 asyncio.run(main())
11except Exception as e:
12 print(f'{type(e).__name__}: {e}')
--- orig.py 2026-10-17 16:10:42.326993359 -0400 +++ fixed.py 2026-10-17 16:10:42.736981683 -0400 @@ -1,9 +1,10 @@ import trio +import trio.lowlevel async def main(): """This is a docstring with await trio.sleep(0) inside.""" s = 'not await trio.sleep(0)' # await trio.sleep(0) # this is a comment - await trio.sleep(0) # real call + await trio.lowlevel.checkpoint() # real call print('slept') try: import asyncio
r1-p007 · Missing Module Import NameError
1import trio
2# trio.lowlevel not imported
3async def main():
4 await trio.sleep(0) # should become trio.lowlevel.checkpoint()
5 print('checkpoint passed')
6try:
7 import asyncio
8 asyncio.run(main())
9except Exception as e:
10 print(f'{type(e).__name__}: {e}')
--- orig.py 2026-10-17 16:10:42.955975447 -0400 +++ fixed.py 2026-10-17 16:10:43.341964477 -0400 @@ -1,7 +1,8 @@ import trio +import trio.lowlevel # trio.lowlevel not imported async def main(): - await trio.sleep(0) # should become trio.lowlevel.checkpoint() + await trio.lowlevel.checkpoint() # should become trio.lowlevel.checkpoint() print('checkpoint passed') try: import asyncio
r1-p008 · Int/Float/Bool Coercion Edge Cases
1import trio
2from decimal import Decimal
3async def main():
4 vals = [0, 0.0, False, Decimal('0'), 0//1, (lambda: 0)()]
5 for v in vals:
6 try:
7 await trio.sleep(v)
8 print(f'{v!r}: slept')
9 except Exception as e:
10 print(f'{v!r}: {type(e).__name__}: {e}')
11try:
12 import asyncio
13 asyncio.run(main())
14except Exception as e:
15 print(f'{type(e).__name__}: {e}')
r2-p001 · Keyword argument usage
1import trio
2async def main():
3 delay_val = 0
4 await trio.sleep(delay=delay_val)
5 print('keyword ok')
6await trio.run(main())
r2-p002 · Parameter forwarding with defaults (generated program does not parse: Traceback (most recent call last):)
1import trio
2async def wrapper(*args, **kwargs):
3 return await trio.sleep(*args, **kwargs)
4async def main():
5 result = await wrapper(0)
6 print('forwarded:', result)
7async def posonly(/, delay):
8 return await trio.sleep(delay)
9async def main2():
10 r = await posonly(0)
11 print('posonly:', r)
12async def kwonly(*, delay):
13 return await trio.sleep(delay)
14async def main3():
15 r = await kwonly(delay=0)
16 print('kwonly:', r)
17asyncio.run(main())
18asyncio.run(main2())
19asyncio.run(main3())
r2-p003 · Import alias mismatch
1import trio as t
2async def main():
3 await t.sleep(0)
4 print('aliased ok')
5trio.run(main())
--- orig.py 2026-10-17 16:10:49.311795906 -0400 +++ fixed.py 2026-10-17 16:10:49.681785532 -0400 @@ -1,5 +1,6 @@ import trio as t +import trio.lowlevel async def main(): - await t.sleep(0) + await trio.lowlevel.checkpoint() print('aliased ok') trio.run(main())
r2-p004 · From import prevents safe rewrite
1from trio import sleep
2async def main():
3 await sleep(0)
4 print('from import ok')
5trio.run(main())
--- orig.py 2026-10-17 16:10:49.878780008 -0400 +++ fixed.py 2026-10-17 16:10:50.261769286 -0400 @@ -1,5 +1,6 @@ from trio import sleep +import trio.lowlevel async def main(): - await sleep(0) + await trio.lowlevel.checkpoint() print('from import ok') trio.run(main())
r2-p005 · Comment inside parentheses
1import trio
2async def main():
3 await trio.sleep(
4 0 # zero delay
5 )
6 print('comment preserved')
7trio.run(main())
r2-p006 · Dynamic attribute access via getattr
1import trio
2async def main():
3 sleep_fn = getattr(trio, 'sleep')
4 await sleep_fn(0)
5 print('getattr ok')
6trio.run(main())
r2-p007 · Missing lowlevel import
1import trio
2async def main():
3 await trio.sleep(0)
4 print('before checkpoint')
5 await trio.lowlevel.checkpoint() # This line will fail if not imported
6 print('after checkpoint')
7trio.run(main())
--- orig.py 2026-10-17 16:10:51.177743671 -0400 +++ fixed.py 2026-10-17 16:10:51.537733622 -0400 @@ -1,6 +1,7 @@ import trio +import trio.lowlevel async def main(): - await trio.sleep(0) + await trio.lowlevel.checkpoint() print('before checkpoint') await trio.lowlevel.checkpoint() # This line will fail if not imported print('after checkpoint')
r2-p008 · Comments on removed/moved code
1import trio
2# This is a comment before
3async def main():
4 # Comment before await
5 await trio.sleep(0) # Inline comment
6 # Comment after await
7 print('done')
8# Comment after function
9trio.run(main())
--- orig.py 2026-10-17 16:10:51.747727760 -0400 +++ fixed.py 2026-10-17 16:10:52.121717328 -0400 @@ -1,8 +1,9 @@ import trio +import trio.lowlevel # This is a comment before async def main(): # Comment before await - await trio.sleep(0) # Inline comment + await trio.lowlevel.checkpoint() # Inline comment # Comment after await print('done') # Comment after function