-
-
Notifications
You must be signed in to change notification settings - Fork 30.8k
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
bpo-38599: Deprecate creation of asyncio object when the loop is not running #18195
Conversation
Add Deprecation Warning when Queue and Locks are created and the loop is not running.
I believe this change should also be implemented for the other synchronization primitives: |
@aeros thanks for the review, I will fix the PR |
Add @aeros comments
@aeros hi I've just push the changes |
Thanks. You'll need to update the tests as well. |
Codecov Report
@@ Coverage Diff @@
## master #18195 +/- ##
===========================================
+ Coverage 82.11% 83.19% +1.07%
===========================================
Files 1954 1570 -384
Lines 583213 414440 -168773
Branches 44383 44433 +50
===========================================
- Hits 478932 344791 -134141
+ Misses 94652 60001 -34651
- Partials 9629 9648 +19
Continue to review full report at Codecov.
|
@aeros I think now is ready :) |
What was the reason behind removing the BoundedSemaphore deprecation warning? Also, it would be helpful to add unit tests, to ensure the deprecation warnings are working as intended; this is done for most of the existing ones. |
@aeros okas I will add tests. I remove the check on BoundedSemaphore because it inherit from Semaphore. If I let the warning, will be a double check, isn't? |
I hadn't previously noticed 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.
Mostly looks good now, just a few points to address in the tests.
Note: The suggestions below apply to all of the tests, but I only commented on one of them to avoid repeating the same message.
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.
LGTM, thanks for making the recommended changes @eamanu!
As a minor note, I think a brief docstring beneath the new class with something along the lines of Tests the deprecation of creating asyncio objects outside of a running event loop.
would be helpful to document the purpose of the tests (since it may not be immediately clear what the deprecation is testing). But I don't think that's 100% necessary, and the PR could likely be merged without it.
Also for formatting, there's typically a space between the class declaration and the first method (which is followed for the above test class). That should be a quick fix. (:
Misc/NEWS.d/next/Library/2020-01-26-20-54-04.bpo-38599.0PObOD.rst
Outdated
Show resolved
Hide resolved
Creating a Lock object with a non-running event loop is OK as long as the loop was passed explicitly (and not obtained via a hidden call to def __init__(self, loop=None):
if loop is None:
loop = asyncio._get_running_loop()
if loop is None:
# issue warning
loop = asyncio.get_event_loop() (and drop the |
def __init__(self, loop=None):
if loop is None:
loop = asyncio._get_running_loop()
if loop is None:
# issue warning
loop = asyncio.get_event_loop() Ah, I see. That's likely the most explicit way to always raise when the constructor for the class is called outside of a coroutine, while also not having a second redundant deprecation warning from passing an explicit loop argument. With the current implementation in the PR, it can raise both deprecation warnings at the same time. Out of curiosity though, would something like this work as well, or is there a situation it wouldn't appropriately cover as well as the above?: def __init__(self, loop=None):
if loop is None:
loop = asyncio.get_event_loop()
if not loop.is_running():
# warn
... Although it's not a significant concern since this is within the internals of asyncio, I typically prefer to avoid directly accessing private members of other classes when possible. IMO, it also makes the code a bit more obvious to readers since they're less likely to be as familiar with I suspect that you may have been considering the discussion about eventually deprecating |
IMO, we need to raise the two warns (if is the case) because are two different deprecations. One of them is a warn about the loop argument deprecated where exist an explicit version where the loop argument will be removed. Meanwhile, the creation of a async object without a event loop running, is deprecated from a different version and without plan of remove it yet. So maybe the code will be: def __init__(self, loop=None):
...
if loop is None:
loop = asyncio._get_running_loop()
if loop is None:
# issue warning
loop = asyncio.get_event_loop()
else:
# warn loop arg deprecated
... Also, I think that ...
loop = asyncio.get_event_loop()
if not loop.is_running():
... will work, isn't? In the other hand I agree with @aeros. I think is more redeable use |
That's exactly the purpose of my solution:
No.
That's the thing — I don't like deprecating too much in one release. My strategy:
|
I think you may have misunderstood my question. I know that More specifically, I was referring to whether or not the following two implementation examples would cover all of the same situations: def __init__(self, loop=None):
if loop is None:
loop = asyncio._get_running_loop()
if loop is None:
# issue warning
loop = asyncio.get_event_loop() def __init__(self, loop=None):
if loop is None:
loop = asyncio.get_event_loop()
if not loop.is_running():
# warn
... While they use a different process to check if the event loop is running, I believe both would ultimately behave the same from a user perspective (based on my own experimentation, at least). I was wondering if there were any specific situations where the above two wouldn't behave the same (or any specific reason to use one over the other). |
Yeah, both snippets are indeed similar in functionality. I'd still prefer the first one since it conditions the |
Agree with Yuri |
@1st1 So, the changes looks like this, right? That generate some errors on test, so I want be sure if I interpret correctly your idea.
|
Sorry I don't know if clear my last comments, so let just the code:
|
@eamanu The logic is fine, but within the internals you should use the local module name def __init__(self, *, loop=None):
self._waiters = None
self._locked = False
if loop is None:
self._loop = events._get_running_loop()
if self._loop is None:
warnings.warn("The creation of asyncio objects without a running "
"event loop is deprecated as of Python 3.9.",
DeprecationWarning, stacklevel=2)
self._loop = events.get_event_loop() You can observe that the current code uses |
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.
Also, a bit of a bikeshed on the warning message: I'm thinking that "The creation of asyncio objects outside of a running event loop is deprecated..." will be more immediately clear to users and technically correct compared to "The creation of asyncio objects without a running event loop is deprecated...".
(I suggested the current version previously, but after having some additional time to think about it, I think the above is more clear)
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.
@eamanu I don't think the intention from @1st1 was to remove the existing deprecation warnings for the loop argument that were added in 3.8:
That's the thing — I don't like deprecating too much in one release. My strategy:
In 3.9 we deprecate instantiating a Loop/Semaphore/Future/etc outside a coroutine/loop callback without an explicit loop argument.
In 3.10 we can maybe deprecate the argument itself.
Yury can correct me if I misunderstood what he meant, but I believe he was referring to deprecating the loop argument in all situations in 3.10. With his plan, explicitly passing the event loop would continue to raise a deprecation warning in 3.9 if the user attempted to do so within a running event loop (such as within an async def
function/method), as it already does in 3.8. Then in 3.10, we could consider also deprecating the loop argument when it's passed outside of a running event loop.
But regardless of what Yury meant, I personally disagree with entirely removing the existing deprecation warnings that were added in 3.8, as the PR currently is doing:
warnings.warn("The loop argument is deprecated since Python 3.8, " | ||
"and scheduled for removal in Python 3.10.", | ||
DeprecationWarning, stacklevel=2) |
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.
It would be very confusing to users to add a deprecation warning in 3.8, and then remove the warning from certain asyncio objects entirely in 3.9. That doesn't make much sense to me.
(also applies to the other warning removals)
Hi @aeros yes, first I was a little confusing with the @1st1 's comments and code example. But following the code example my interpretation was "deprecate instantiating a Loop/Semaphore/Future/etc outside a coroutine/loop callback without an explicit loop argument" and then mabye we can "remove the loop parameter". But, I think yes, my interpretation is very very wrong. So the could must be:
And go back the changes on the tests |
Closing this PR following the closure of its b.p.o issue (https://bugs.python.org/issue38599) |
Add Deprecation Warning when Queue and Locks are created and
the loop is not running.
https://bugs.python.org/issue38599