-
-
Notifications
You must be signed in to change notification settings - Fork 2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
moar asyncio support, test infra improvements #213
Conversation
jakkdl
commented
Mar 4, 2024
•
edited
Loading
edited
- Add asyncio-specific error messages for 2xx.
- Add check in tests to detect if [library]_NO_ERROR should be used, add it to several checks.
- Specify why NO_[library] and [library]_NO_ERROR is specified in a lot of eval files.
Add check in tests to detect if [library]_NO_ERROR should be used, add it to several checks. Specify why NO_[library] and [library]_NO_ERROR is specified in a lot of eval files.
"ASYNC220_asyncio": ( | ||
"Sync call {} in async function, use " | ||
"`asyncio.create_subprocess_[exec/shell]." | ||
), | ||
"ASYNC221": "Sync call {} in async function, use `await {}.run_process(...)`.", | ||
"ASYNC221_asyncio": ( | ||
"Sync call {} in async function, use " | ||
"`asyncio.create_subprocess_[exec/shell]." | ||
), | ||
"ASYNC222": "Sync call {} in async function, wrap in `{}.to_thread.run_sync()`.", | ||
"ASYNC222_asyncio": ( | ||
"Sync call {} in async function, use `asyncio.loop.run_in_executor`." | ||
), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
educated guesses from reading asyncio docs:
https://docs.python.org/3/library/asyncio-dev.html#asyncio-multithreading
https://docs.python.org/3/library/asyncio-subprocess.html
nursery = get_matching_call(item.context_expr, "open_nursery") | ||
nursery = get_matching_call( | ||
item.context_expr, "open_nursery", base=("trio",) | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nurseries only exist in trio. Could expand the check to work with anyio taskgroups though
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's leave that for a future PR, but yes - it'd be great for the ecosystem to support this for anyio.TaskGroup
, and at that point we might as well support asyncio.TaskGroup
too.
README.md
Outdated
- **ASYNC220**: Sync process call in async function, use `await nursery.start([trio|anyio].run_process, ...)`. `asyncio` users can use [`asyncio.create_subprocess_[exec/shell]`](https://docs.python.org/3/library/asyncio-subprocess.html). | ||
- **ASYNC221**: Sync process call in async function, use `await [trio|anyio].run_process(...)`. `asyncio` users can use [`asyncio.create_subprocess_[exec/shell]`](https://docs.python.org/3/library/asyncio-subprocess.html). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ugh, starting to feel like we might consider generating proper docs with interlinks and stuff.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's open an issue for that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Merge when you feel it's ready!
nursery = get_matching_call(item.context_expr, "open_nursery") | ||
nursery = get_matching_call( | ||
item.context_expr, "open_nursery", base=("trio",) | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's leave that for a future PR, but yes - it'd be great for the ecosystem to support this for anyio.TaskGroup
, and at that point we might as well support asyncio.TaskGroup
too.
tests/eval_files/async101.py
Outdated
@@ -1,4 +1,4 @@ | |||
# NOASYNCIO | |||
# ASYNCIO_NO_ERROR - no nursery/cancelscope in asyncio |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See above for a future PR; there is asyncio.TaskGroup
.
I also suspect that async with timeout()
is doing something similar? But at this point users really just have to switch to structured concurrency if they want sane error handling.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh right right, trio.[move_on/fail]_[after/at]
are just wrapper functions for cancelscopes.
It might still be good (and fairly easy) to raise errors for an asyncio user doing it, even if our real suggestion is for them to switch to anyio.
Secret plan is for asyncio users to start running our checks, then when getting tons of useful errors realize they should switch to anyio 😈
# NOASYNCIO | ||
# ASYNC111: Variable, from context manager opened inside nursery, passed to start[_soon] might be invalidly accessed while in use, due to context manager closing before the nursery. This is usually a bug, and nurseries should generally be the inner-most context manager. | ||
# It's possible there's an equivalent asyncio construction/gotcha, but methods are differently named, so this file will not raise any errors | ||
# ASYNCIO_NO_ERROR # no nurseries in asyncio. Though maybe the bug is relevant for TaskGroups |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Plausibly, yeah.
tests/eval_files/async113_trio.py
Outdated
@@ -11,7 +11,9 @@ | |||
import trio | |||
|
|||
# ARG --startable-in-context-manager=custom_startable_function | |||
# NOANYIO | |||
|
|||
# ANYIO_NO_ERROR - anyio uses TaskGroups, not nurseries |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should support anyio
for this though, open an issue?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This one, as opposed to 101, 111, and 112 is supported. Updated comment to refer to async113.py
which tests anyio functionality.
async def file_binary_write(f: io.BufferedWriter): | ||
f.read() # ASYNC232_asyncio: 4, 'read', 'f' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
f.write()
? And below for the bare name.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is tested by row 16/17, any call on a file object will trigger the error. Added clarifying comment and a more obvious nonsense-name example.
(pretty much all your comments in this vein make me go "yeah duh", change it, then after a minute realize/remember the reason for the status quo 😅)
tests/eval_files/async23x_asyncio.py
Outdated
# asyncio.wrap_file does not exist | ||
await asyncio.wrap_file(open("")) # ASYNC230_asyncio: 28, 'open' | ||
await asyncio.wrap_file(os.fdopen(0)) # ASYNC231_asyncio: 28, 'os.fdopen' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doesn't make sense to test this if it doesn't exist, IMO.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The test is to make sure the protection that wrap_file()
would give doesn't trigger. Not that it would matter much since it doesn't exist, but I constructed the file by copypasting and replacing - so /shrug. I'll clarify the comment
README.md
Outdated
- **ASYNC220**: Sync process call in async function, use `await nursery.start([trio|anyio].run_process, ...)`. `asyncio` users can use [`asyncio.create_subprocess_[exec/shell]`](https://docs.python.org/3/library/asyncio-subprocess.html). | ||
- **ASYNC221**: Sync process call in async function, use `await [trio|anyio].run_process(...)`. `asyncio` users can use [`asyncio.create_subprocess_[exec/shell]`](https://docs.python.org/3/library/asyncio-subprocess.html). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's open an issue for that.
* split off anyio_create_task_group testing into async113_anyio.py * improved comments