Skip to content

Commit c967bd5

Browse files
[3.9] bpo-45097: Remove incorrect deprecation warnings in asyncio. (GH-28153)
Deprecation warnings about the loop argument were incorrectly emitted in cases when the loop argument was used inside the asyncio library, not from user code.
1 parent ce83e42 commit c967bd5

File tree

11 files changed

+234
-181
lines changed

11 files changed

+234
-181
lines changed

Lib/asyncio/base_events.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -350,7 +350,7 @@ async def start_serving(self):
350350
self._start_serving()
351351
# Skip one loop iteration so that all 'loop.add_reader'
352352
# go through.
353-
await tasks.sleep(0, loop=self._loop)
353+
await tasks.sleep(0)
354354

355355
async def serve_forever(self):
356356
if self._serving_forever_fut is not None:
@@ -539,7 +539,7 @@ async def shutdown_asyncgens(self):
539539
closing_agens = list(self._asyncgens)
540540
self._asyncgens.clear()
541541

542-
results = await tasks.gather(
542+
results = await tasks._gather(
543543
*[ag.aclose() for ag in closing_agens],
544544
return_exceptions=True,
545545
loop=self)
@@ -1457,7 +1457,7 @@ async def create_server(
14571457
fs = [self._create_server_getaddrinfo(host, port, family=family,
14581458
flags=flags)
14591459
for host in hosts]
1460-
infos = await tasks.gather(*fs, loop=self)
1460+
infos = await tasks._gather(*fs, loop=self)
14611461
infos = set(itertools.chain.from_iterable(infos))
14621462

14631463
completed = False
@@ -1515,7 +1515,7 @@ async def create_server(
15151515
server._start_serving()
15161516
# Skip one loop iteration so that all 'loop.add_reader'
15171517
# go through.
1518-
await tasks.sleep(0, loop=self)
1518+
await tasks.sleep(0)
15191519

15201520
if self._debug:
15211521
logger.info("%r is serving", server)

Lib/asyncio/runners.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ def _cancel_all_tasks(loop):
6161
task.cancel()
6262

6363
loop.run_until_complete(
64-
tasks.gather(*to_cancel, loop=loop, return_exceptions=True))
64+
tasks._gather(*to_cancel, loop=loop, return_exceptions=True))
6565

6666
for task in to_cancel:
6767
if task.cancelled():

Lib/asyncio/subprocess.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -193,8 +193,8 @@ async def communicate(self, input=None):
193193
stderr = self._read_stream(2)
194194
else:
195195
stderr = self._noop()
196-
stdin, stdout, stderr = await tasks.gather(stdin, stdout, stderr,
197-
loop=self._loop)
196+
stdin, stdout, stderr = await tasks._gather(stdin, stdout, stderr,
197+
loop=self._loop)
198198
await self.wait()
199199
return (stdout, stderr)
200200

Lib/asyncio/tasks.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -580,15 +580,16 @@ def as_completed(fs, *, loop=None, timeout=None):
580580
if futures.isfuture(fs) or coroutines.iscoroutine(fs):
581581
raise TypeError(f"expect an iterable of futures, not {type(fs).__name__}")
582582

583+
if loop is not None:
584+
warnings.warn("The loop argument is deprecated since Python 3.8, "
585+
"and scheduled for removal in Python 3.10.",
586+
DeprecationWarning, stacklevel=2)
587+
583588
from .queues import Queue # Import here to avoid circular import problem.
584589
done = Queue(loop=loop)
585590

586591
if loop is None:
587592
loop = events.get_event_loop()
588-
else:
589-
warnings.warn("The loop argument is deprecated since Python 3.8, "
590-
"and scheduled for removal in Python 3.10.",
591-
DeprecationWarning, stacklevel=2)
592593
todo = {ensure_future(f, loop=loop) for f in set(fs)}
593594
timeout_handle = None
594595

@@ -756,6 +757,10 @@ def gather(*coros_or_futures, loop=None, return_exceptions=False):
756757
"and scheduled for removal in Python 3.10.",
757758
DeprecationWarning, stacklevel=2)
758759

760+
return _gather(*coros_or_futures, loop=loop, return_exceptions=return_exceptions)
761+
762+
763+
def _gather(*coros_or_futures, loop=None, return_exceptions=False):
759764
if not coros_or_futures:
760765
if loop is None:
761766
loop = events.get_event_loop()

Lib/asyncio/unix_events.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -323,7 +323,7 @@ async def create_unix_server(
323323
server._start_serving()
324324
# Skip one loop iteration so that all 'loop.add_reader'
325325
# go through.
326-
await tasks.sleep(0, loop=self)
326+
await tasks.sleep(0)
327327

328328
return server
329329

Lib/test/test_asyncgen.py

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1077,6 +1077,84 @@ async def wait():
10771077

10781078
self.assertEqual(finalized, 2)
10791079

1080+
def test_async_gen_asyncio_shutdown_02(self):
1081+
messages = []
1082+
1083+
def exception_handler(loop, context):
1084+
messages.append(context)
1085+
1086+
async def async_iterate():
1087+
yield 1
1088+
yield 2
1089+
1090+
it = async_iterate()
1091+
async def main():
1092+
loop = asyncio.get_running_loop()
1093+
loop.set_exception_handler(exception_handler)
1094+
1095+
async for i in it:
1096+
break
1097+
1098+
asyncio.run(main())
1099+
1100+
self.assertEqual(messages, [])
1101+
1102+
def test_async_gen_asyncio_shutdown_exception_01(self):
1103+
messages = []
1104+
1105+
def exception_handler(loop, context):
1106+
messages.append(context)
1107+
1108+
async def async_iterate():
1109+
try:
1110+
yield 1
1111+
yield 2
1112+
finally:
1113+
1/0
1114+
1115+
it = async_iterate()
1116+
async def main():
1117+
loop = asyncio.get_running_loop()
1118+
loop.set_exception_handler(exception_handler)
1119+
1120+
async for i in it:
1121+
break
1122+
1123+
asyncio.run(main())
1124+
1125+
message, = messages
1126+
self.assertEqual(message['asyncgen'], it)
1127+
self.assertIsInstance(message['exception'], ZeroDivisionError)
1128+
self.assertIn('an error occurred during closing of asynchronous generator',
1129+
message['message'])
1130+
1131+
def test_async_gen_asyncio_shutdown_exception_02(self):
1132+
messages = []
1133+
1134+
def exception_handler(loop, context):
1135+
messages.append(context)
1136+
1137+
async def async_iterate():
1138+
try:
1139+
yield 1
1140+
yield 2
1141+
finally:
1142+
1/0
1143+
1144+
async def main():
1145+
loop = asyncio.get_running_loop()
1146+
loop.set_exception_handler(exception_handler)
1147+
1148+
async for i in async_iterate():
1149+
break
1150+
1151+
asyncio.run(main())
1152+
1153+
message, = messages
1154+
self.assertIsInstance(message['exception'], ZeroDivisionError)
1155+
self.assertIn('unhandled exception during asyncio.run() shutdown',
1156+
message['message'])
1157+
10801158
def test_async_gen_expression_01(self):
10811159
async def arange(n):
10821160
for i in range(n):

Lib/test/test_asyncio/__init__.py

Lines changed: 2 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,10 @@
11
import os
22
from test import support
3-
import unittest
43

54
# Skip tests if we don't have concurrent.futures.
65
support.import_module('concurrent.futures')
76

87

9-
def load_tests(loader, _, pattern):
8+
def load_tests(*args):
109
pkg_dir = os.path.dirname(__file__)
11-
suite = AsyncioTestSuite()
12-
return support.load_package_tests(pkg_dir, loader, suite, pattern)
13-
14-
15-
class AsyncioTestSuite(unittest.TestSuite):
16-
"""A custom test suite that also runs setup/teardown for the whole package.
17-
18-
Normally unittest only runs setUpModule() and tearDownModule() within each
19-
test module part of the test suite. Copying those functions to each file
20-
would be tedious, let's run this once and for all.
21-
"""
22-
def run(self, result, debug=False):
23-
ignore = support.ignore_deprecations_from
24-
tokens = {
25-
ignore("asyncio.base_events", like=r".*loop argument.*"),
26-
ignore("asyncio.unix_events", like=r".*loop argument.*"),
27-
ignore("asyncio.futures", like=r".*loop argument.*"),
28-
ignore("asyncio.runners", like=r".*loop argument.*"),
29-
ignore("asyncio.subprocess", like=r".*loop argument.*"),
30-
ignore("asyncio.tasks", like=r".*loop argument.*"),
31-
ignore("test.test_asyncio.test_events", like=r".*loop argument.*"),
32-
ignore("test.test_asyncio.test_queues", like=r".*loop argument.*"),
33-
ignore("test.test_asyncio.test_tasks", like=r".*loop argument.*"),
34-
}
35-
try:
36-
super().run(result, debug=debug)
37-
finally:
38-
support.clear_ignored_deprecations(*tokens)
10+
return support.load_package_tests(pkg_dir, *args)

0 commit comments

Comments
 (0)