mirror of https://github.com/python/cpython.git
bpo-45416: Fix use of asyncio.Condition() with explicit Lock objects (GH-28850)
Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
(cherry picked from commit 1a7892414e
)
Co-authored-by: Joongi Kim <joongi@lablup.com>
This commit is contained in:
parent
3c27013077
commit
164dddf5f8
|
@ -230,8 +230,6 @@ def __init__(self, lock=None, *, loop=mixins._marker):
|
|||
super().__init__(loop=loop)
|
||||
if lock is None:
|
||||
lock = Lock()
|
||||
elif lock._loop is not self._get_loop():
|
||||
raise ValueError("loop argument must agree with lock")
|
||||
|
||||
self._lock = lock
|
||||
# Export the lock's locked(), acquire() and release() methods.
|
||||
|
|
|
@ -724,24 +724,68 @@ async def f():
|
|||
self.loop.run_until_complete(f())
|
||||
|
||||
def test_explicit_lock(self):
|
||||
lock = asyncio.Lock()
|
||||
cond = asyncio.Condition(lock)
|
||||
async def f(lock=None, cond=None):
|
||||
if lock is None:
|
||||
lock = asyncio.Lock()
|
||||
if cond is None:
|
||||
cond = asyncio.Condition(lock)
|
||||
self.assertIs(cond._lock, lock)
|
||||
self.assertFalse(lock.locked())
|
||||
self.assertFalse(cond.locked())
|
||||
async with cond:
|
||||
self.assertTrue(lock.locked())
|
||||
self.assertTrue(cond.locked())
|
||||
self.assertFalse(lock.locked())
|
||||
self.assertFalse(cond.locked())
|
||||
async with lock:
|
||||
self.assertTrue(lock.locked())
|
||||
self.assertTrue(cond.locked())
|
||||
self.assertFalse(lock.locked())
|
||||
self.assertFalse(cond.locked())
|
||||
|
||||
self.assertIs(cond._lock, lock)
|
||||
self.assertIs(cond._loop, lock._loop)
|
||||
# All should work in the same way.
|
||||
self.loop.run_until_complete(f())
|
||||
self.loop.run_until_complete(f(asyncio.Lock()))
|
||||
lock = asyncio.Lock()
|
||||
self.loop.run_until_complete(f(lock, asyncio.Condition(lock)))
|
||||
|
||||
def test_ambiguous_loops(self):
|
||||
loop = self.new_test_loop()
|
||||
loop = asyncio.new_event_loop()
|
||||
self.addCleanup(loop.close)
|
||||
|
||||
lock = asyncio.Lock()
|
||||
lock._loop = loop
|
||||
async def wrong_loop_in_lock():
|
||||
with self.assertRaises(TypeError):
|
||||
asyncio.Lock(loop=loop) # actively disallowed since 3.10
|
||||
lock = asyncio.Lock()
|
||||
lock._loop = loop # use private API for testing
|
||||
async with lock:
|
||||
# acquired immediately via the fast-path
|
||||
# without interaction with any event loop.
|
||||
cond = asyncio.Condition(lock)
|
||||
# cond.acquire() will trigger waiting on the lock
|
||||
# and it will discover the event loop mismatch.
|
||||
with self.assertRaisesRegex(
|
||||
RuntimeError,
|
||||
"is bound to a different event loop",
|
||||
):
|
||||
await cond.acquire()
|
||||
|
||||
async def _create_condition():
|
||||
with self.assertRaises(ValueError):
|
||||
asyncio.Condition(lock)
|
||||
async def wrong_loop_in_cond():
|
||||
# Same analogy here with the condition's loop.
|
||||
lock = asyncio.Lock()
|
||||
async with lock:
|
||||
with self.assertRaises(TypeError):
|
||||
asyncio.Condition(lock, loop=loop)
|
||||
cond = asyncio.Condition(lock)
|
||||
cond._loop = loop
|
||||
with self.assertRaisesRegex(
|
||||
RuntimeError,
|
||||
"is bound to a different event loop",
|
||||
):
|
||||
await cond.wait()
|
||||
|
||||
self.loop.run_until_complete(_create_condition())
|
||||
self.loop.run_until_complete(wrong_loop_in_lock())
|
||||
self.loop.run_until_complete(wrong_loop_in_cond())
|
||||
|
||||
def test_timeout_in_block(self):
|
||||
loop = asyncio.new_event_loop()
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
Fix use of :class:`asyncio.Condition` with explicit :class:`asyncio.Lock` objects, which was a regression due to removal of explicit loop arguments.
|
||||
Patch by Joongi Kim.
|
Loading…
Reference in New Issue