Skip to content
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

Merged
merged 8 commits into from
Mar 8, 2024

Conversation

jakkdl
Copy link
Member

@jakkdl jakkdl commented Mar 4, 2024

  • 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.
flake8_async/base.py Show resolved Hide resolved
Comment on lines +179 to +191
"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`."
),
Copy link
Member Author

@jakkdl jakkdl Mar 4, 2024

Choose a reason for hiding this comment

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

Comment on lines -96 to +98
nursery = get_matching_call(item.context_expr, "open_nursery")
nursery = get_matching_call(
item.context_expr, "open_nursery", base=("trio",)
)
Copy link
Member Author

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

Copy link
Member

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/autofix_files/noqa_testing.py Show resolved Hide resolved
tests/test_flake8_async.py Outdated Show resolved Hide resolved
README.md Outdated
Comment on lines 51 to 52
- **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).
Copy link
Member Author

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.

Copy link
Member

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.

Copy link
Member

@Zac-HD Zac-HD left a 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!

Comment on lines -96 to +98
nursery = get_matching_call(item.context_expr, "open_nursery")
nursery = get_matching_call(
item.context_expr, "open_nursery", base=("trio",)
)
Copy link
Member

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.

@@ -1,4 +1,4 @@
# NOASYNCIO
# ASYNCIO_NO_ERROR - no nursery/cancelscope in asyncio
Copy link
Member

@Zac-HD Zac-HD Mar 4, 2024

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.

Copy link
Member Author

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
Copy link
Member

Choose a reason for hiding this comment

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

Plausibly, yeah.

@@ -11,7 +11,9 @@
import trio

# ARG --startable-in-context-manager=custom_startable_function
# NOANYIO

# ANYIO_NO_ERROR - anyio uses TaskGroups, not nurseries
Copy link
Member

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?

Copy link
Member Author

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.

Comment on lines +24 to +25
async def file_binary_write(f: io.BufferedWriter):
f.read() # ASYNC232_asyncio: 4, 'read', 'f'
Copy link
Member

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.

Copy link
Member Author

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 😅)

Comment on lines 20 to 22
# 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'
Copy link
Member

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.

Copy link
Member Author

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
Comment on lines 51 to 52
- **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).
Copy link
Member

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.

jakkdl added 4 commits March 5, 2024 10:58
* split off anyio_create_task_group testing into async113_anyio.py
* improved comments
@jakkdl jakkdl merged commit 8b1a1cf into python-trio:main Mar 8, 2024
9 checks passed
@jakkdl jakkdl deleted the more_asyncio_support branch March 8, 2024 11:50
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.

2 participants