-
-
Notifications
You must be signed in to change notification settings - Fork 353
add @as_safe_channel
#3197
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
add @as_safe_channel
#3197
Conversation
I'm not too sold on how some of this is done, but at least now it shouldn't fail CI. edit: I'm also pretty sure the more correct way to fix the race condition would be using |
I tracked down the race condition to We still want to use The reason it works to move the |
…add buffer_size tests, remove unused code
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## main #3197 +/- ##
================================================
Coverage 100.00000% 100.00000%
================================================
Files 124 124
Lines 18848 19038 +190
Branches 1277 1287 +10
================================================
+ Hits 18848 19038 +190
🚀 New features to boost your workflow:
|
@Zac-HD if you can show why the inner loop is necessary it'd be great, but I'm kinda suspecting it's a remnant of previous implementations or something - because I can't come up with anything that would hit that code path. |
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.
I think this'll help? But haven't run many tests yet...
add buffer_size note to docstring Co-authored-by: Zac Hatfield-Dodds <zac.hatfield.dodds@gmail.com>
for more information, see https://pre-commit.ci
…syncContextManager, I have no clue why
I have no clue why sphinx fails to link the |
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.
Looks good and useful.
This is unrelated, but while we're editing the async-gen docs, we might want to swap out the async_generator.aclosing
reference to point to contextlib
first, with async_generator
as a backport.
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 code itself looks good!
does anybody have any idea about the RTD fail?
|
Let's merge as-is then. I don't want to split into multiple functions (linter recs etc get harder), we've already disabled |
sorry, with throwing I meant #3197 (comment) for linter recs we'd just always recommend |
#3197 (comment) doesn't bother me, because cancellation is always a possibility you have to handle. It "just so happens" that we always cancel "right before" the In practice most users are never going to touch the default, so maybe we should only supply the unbuffered version, and let power-users add their own buffering if desired? We could even share a recipe for the " |
Okay yeah this seems fine. The only time this would be insufficient is if they're relying on an external asyncgen they can't modify and they want buffering, but if so they can still just write an equivalent version of But god I am not looking forward to another go at the "oh just unwrap the exception from inside the group"; I'm tempted to go create a helper for that in a new PR, which would be pretty great for trio-websocket and probably others as well: https://github.com/python-trio/trio-websocket/blob/bec4232178700e53dccb887d028997f6746e91de/trio_websocket/_impl.py#L218 |
OK, I think this is the last round of comments from me:
|
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.
false alarm, the simple idea leaks cancellations from the generator into the caller (cf PEP-789) 😞
Could we add a test for that in this PR too at least |
@generator_as_channel
async def agenfn():
with trio.CancelScope() as cscope:
cscope.cancel()
yield
async def test_doesn't_leak_cancellation():
with pytest.raises(AssertionError):
async with agenfn() as recv_chan:
async for _ in recv_chan:
pass
raise AssertionError("should be reachable") |
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.
Three things below - I'm very keen to merge and thus deferred .clone()
, but I also think we need to get the core interface right the first time 😅
- The big-but-easy one is renaming the function
@as_safe_channel
; see below for why - We can drop some docs now that the interface is simpler 🎉
- Two small but important correctness changes.
(once more into the diff, dear friends!)
src/trio/_channel.py
Outdated
# TODO: should this allow clones? We'd signal that by inheriting from | ||
# MemoryReceiveChannel. |
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.
I suggest we ship an initial version without .clone()
support, and come back later if anyone asks for it. This will already be super valuable, and I'd rather not wait any longer!
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.
I was mostly thinking if we have any strong reasons not to offer it, implementing it should be straightforward.
Though looking at the interface of MemoryReceiveChannel
we also don't have receive_nowait
on the wrapper and I'm not seeing how that one would make sense to offer - so let's stick to the interface of ReceiveChannel
…'t unwrap user exception groups, add test for multiple receivers, clean up docs
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 looks great to me!
- tiny tweaks for changelog and coverage below
- ✅ Switch from
PurePath#as_uri
toPurePath#joinpath
for our test that PurePath methods get inherited #3249 has fixed the unrelated test failures
then let's ship it!
Okay I added a testcase for multiple cancellations, and current implementation will break code that does |
Phew! That was more of a saga than I expected, but I'm very very happy to have it in. Thanks again to @jakkdl, and to everyone else who helped out with design and code review - I think we got to a much better solution than my original proposal. |
turns out this shit is complicated at times 😅 But yes thank you all for initial design, reviews, and other feedback! |
Mostly just shepherding @Zac-HD's implementation from #638 (comment)
I don't understand all the details of it, esp some of the code paths I'm completely failing how to cover, so gonna need some help. And I'm getting an exception that sometimes disappear.. which seems bad?
Feel free to add code suggestions and/or commit directly to the branch.
I don't know if this fully resolves #638, or if there's docs and/or other stuff that should be added.
I will make https://flake8-async.readthedocs.io/en/latest/rules.html#async900 suggest using this, and perhaps make it enabled by default, once released.