Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Lib/asyncio/locks.py
Original file line number Diff line number Diff line change
Expand Up @@ -332,7 +332,7 @@ def __init__(self, lock=None, *, loop=None):
DeprecationWarning, stacklevel=2)

if lock is None:
lock = Lock(loop=self._loop)
lock = Lock(loop=loop)
elif lock._loop is not self._loop:
raise ValueError("loop argument must agree with lock")

Expand Down
2 changes: 1 addition & 1 deletion Lib/asyncio/queues.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ def __init__(self, maxsize=0, *, loop=None):
# Futures.
self._putters = collections.deque()
self._unfinished_tasks = 0
self._finished = locks.Event(loop=self._loop)
self._finished = locks.Event(loop=loop)
self._finished.set()
self._init(maxsize)

Expand Down
7 changes: 3 additions & 4 deletions Lib/test/test_asyncio/test_locks.py
Original file line number Diff line number Diff line change
Expand Up @@ -500,10 +500,9 @@ def test_ctor_loop(self):
self.assertIs(cond._loop, self.loop)

def test_ctor_noloop(self):
with self.assertWarns(DeprecationWarning):
asyncio.set_event_loop(self.loop)
cond = asyncio.Condition()
self.assertIs(cond._loop, self.loop)
asyncio.set_event_loop(self.loop)
cond = asyncio.Condition()
self.assertIs(cond._loop, self.loop)

def test_wait(self):
with self.assertWarns(DeprecationWarning):
Expand Down
3 changes: 1 addition & 2 deletions Lib/test/test_asyncio/test_queues.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,7 @@ def test_ctor_loop(self):

def test_ctor_noloop(self):
asyncio.set_event_loop(self.loop)
with self.assertWarns(DeprecationWarning):
q = asyncio.Queue()
q = asyncio.Queue()
self.assertIs(q._loop, self.loop)

def test_repr(self):
Expand Down
10 changes: 6 additions & 4 deletions Lib/unittest/async_case.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,8 +89,9 @@ def _callMaybeAsync(self, func, /, *args, **kwargs):
else:
return ret

async def _asyncioLoopRunner(self):
queue = self._asyncioCallsQueue
async def _asyncioLoopRunner(self, fut):
self._asyncioCallsQueue = queue = asyncio.Queue()
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just curious why we moved it here. Is there a difference in constructing it in _setupAsyncioLoop itself without passing loop and having it here?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, it is possible to just drop the loop parameter from Queue construction because we installed the default event loop a few lines above but I did two steps further.

Instantiation on asyncio loop coupled objects from an async function is more idiomatic, it always grabs a currently executed loop (the loop which is used to run a coroutine).
It prevents things like this:

import asyncio
queue = asyncio.Queue()

asyncio.run(...)  # a code that works with queue

In the example queue variable is instantiated with the default asyncio loop but run() creates a new loop version. So the queue doesn't work and hangs eventually because a future created by one loop cannot be awaited by another one.

In Python 3.9 I have a plan to add another deprecation warning if not self._loop.is_running() for queues and locks and eventually replace get_event_loop() with get_running_loop() as a final fix.

fut.set_result(None)
while True:
query = await queue.get()
queue.task_done()
Expand All @@ -113,8 +114,9 @@ def _setupAsyncioLoop(self):
asyncio.set_event_loop(loop)
loop.set_debug(True)
self._asyncioTestLoop = loop
self._asyncioCallsQueue = asyncio.Queue(loop=loop)
self._asyncioCallsTask = loop.create_task(self._asyncioLoopRunner())
fut = loop.create_future()
self._asyncioCallsTask = loop.create_task(self._asyncioLoopRunner(fut))
loop.run_until_complete(fut)

def _tearDownAsyncioLoop(self):
assert self._asyncioTestLoop is not None
Expand Down