mirror of
https://github.com/python/cpython.git
synced 2025-07-31 07:04:42 +00:00
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
3 changed files with 57 additions and 13 deletions
|
@ -230,8 +230,6 @@ class Condition(_ContextManagerMixin, mixins._LoopBoundMixin):
|
||||||
super().__init__(loop=loop)
|
super().__init__(loop=loop)
|
||||||
if lock is None:
|
if lock is None:
|
||||||
lock = Lock()
|
lock = Lock()
|
||||||
elif lock._loop is not self._get_loop():
|
|
||||||
raise ValueError("loop argument must agree with lock")
|
|
||||||
|
|
||||||
self._lock = lock
|
self._lock = lock
|
||||||
# Export the lock's locked(), acquire() and release() methods.
|
# Export the lock's locked(), acquire() and release() methods.
|
||||||
|
|
|
@ -724,24 +724,68 @@ class ConditionTests(test_utils.TestCase):
|
||||||
self.loop.run_until_complete(f())
|
self.loop.run_until_complete(f())
|
||||||
|
|
||||||
def test_explicit_lock(self):
|
def test_explicit_lock(self):
|
||||||
lock = asyncio.Lock()
|
async def f(lock=None, cond=None):
|
||||||
cond = asyncio.Condition(lock)
|
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)
|
# All should work in the same way.
|
||||||
self.assertIs(cond._loop, lock._loop)
|
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):
|
def test_ambiguous_loops(self):
|
||||||
loop = self.new_test_loop()
|
loop = asyncio.new_event_loop()
|
||||||
self.addCleanup(loop.close)
|
self.addCleanup(loop.close)
|
||||||
|
|
||||||
lock = asyncio.Lock()
|
async def wrong_loop_in_lock():
|
||||||
lock._loop = loop
|
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():
|
async def wrong_loop_in_cond():
|
||||||
with self.assertRaises(ValueError):
|
# Same analogy here with the condition's loop.
|
||||||
asyncio.Condition(lock)
|
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):
|
def test_timeout_in_block(self):
|
||||||
loop = asyncio.new_event_loop()
|
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…
Add table
Add a link
Reference in a new issue