-
-
Notifications
You must be signed in to change notification settings - Fork 31.1k
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
"loop argument must agree with lock" instantiating asyncio.Condition #89579
Comments
In Python 3.10 it is not possible to instantiate an asyncio.Condition that wraps an asyncio.Lock without raising a "loop argument must agree with lock" exception. This code raises that exception: asyncio.Condition(asyncio.Lock()) This worked in previous Python versions. Note that the error only occurs if an event loop is running. Here's a simple script that replicates the problem: import asyncio
# This runs without an exception:
print(asyncio.Condition(asyncio.Lock()))
# This does not work:
async def example():
print(asyncio.Condition(asyncio.Lock()))
# This raises "ValueError: loop argument must agree with lock":
asyncio.run(example()) |
I ran across this issue while trying to use the https://pypi.org/project/janus/ locking library with Python 3.10 - see my issue on their tracker here: aio-libs/janus#358 |
It looks like the relevant test is here: cpython/Lib/test/test_asyncio/test_locks.py Lines 722 to 727 in a1092f6
def test_explicit_lock(self):
lock = asyncio.Lock()
cond = asyncio.Condition(lock)
self.assertIs(cond._lock, lock)
self.assertIs(cond._loop, lock._loop) But... that test doesn't appear to run inside an event loop, so it's not covering the behaviour described in this issue. |
Issue confirmed. The problem is that uriyyo, Andrew, Yury, since it's pretty likely that Lock objects will now have If you insist on keeping the loop check, it should special-case Simon, thanks for your detailed report! As a backwards-compatible workaround till we get a fix in, your user code can do the following: >>> l = asyncio.Lock()
>>> getattr(l, '_get_loop', lambda: None)()
<_UnixSelectorEventLoop running=True closed=False debug=False> You can use such lock without issues now: >>> asyncio.Condition(l)
<asyncio.locks.Condition object at 0x10c05bee0 [unlocked]> Alternatively, if the above disgusts you and you only want to trigger public APIs, you can do this dance: >>> l = asyncio.Lock()
>>> await l.acquire() # first acquire will just work
True
>>> try:
... # second acquire will block so we time it out
... await asyncio.wait_for(l.acquire(), 0.1)
... except asyncio.TimeoutError:
... pass
...
>>> l.release() Now the lock is fully initialized and we can use it:
Both workarounds should be compatible with Python 3.7+ asyncio. |
Thanks, guys! |
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
bugs.python.org fields:
The text was updated successfully, but these errors were encountered: