From c528e0567a14eb62a2a42e4ce9a8b0afbb8eb7b5 Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Thu, 17 May 2018 16:50:33 -0400 Subject: [PATCH 1/7] Verify tests are not modifying global asyncio settings --- Lib/test/libregrtest/save_env.py | 33 +++++++++++++++++++ .../2018-05-17-16-50-06.bpo-33562.qmmv60.rst | 1 + 2 files changed, 34 insertions(+) create mode 100644 Misc/NEWS.d/next/Tests/2018-05-17-16-50-06.bpo-33562.qmmv60.rst diff --git a/Lib/test/libregrtest/save_env.py b/Lib/test/libregrtest/save_env.py index 45b365d456336a..5ac423ff64c46f 100644 --- a/Lib/test/libregrtest/save_env.py +++ b/Lib/test/libregrtest/save_env.py @@ -1,3 +1,4 @@ +import asyncio import builtins import locale import logging @@ -65,8 +66,40 @@ def __init__(self, testname, verbose=0, quiet=False, *, pgo=False): 'sysconfig._CONFIG_VARS', 'sysconfig._INSTALL_SCHEMES', 'files', 'locale', 'warnings.showwarning', 'shutil_archive_formats', 'shutil_unpack_formats', + 'asyncio.get_event_loop_policy', 'asyncio.get_event_loop', + 'asyncio_get_exception_handler', 'asyncio_get_debug', + 'asyncio_get_child_watcher', ) + def get_asyncio_get_event_loop_policy(self): + return asyncio.get_event_loop_policy() + def restore_asyncio_get_event_loop_policy(self, policy): + asyncio.set_event_loop_policy(policy) + + def get_asyncio_get_event_loop(self): + return asyncio.get_event_loop() + def restore_asyncio_get_event_loop(self, loop): + asyncio.set_event_loop(loop) + + def get_asyncio_get_exception_handler(self): + return asyncio.get_event_loop().get_exception_handler() + def restore_asyncio_get_exception_handler(self, handler): + asyncio.get_event_loop().set_exception_handler(handler) + + def get_asyncio_get_debug(self): + return asyncio.get_event_loop().get_debug() + def restore_asyncio_get_debug(self, enabled): + asyncio.get_event_loop().set_debug(enabled) + + def get_asyncio_get_child_watcher(self): + try: + return asyncio.get_event_loop_policy().get_child_watcher() + except NotImplementedError: + return NotImplemented + def restore_asyncio_get_child_watcher(self, watcher): + if watcher is not NotImplemented: + asyncio.get_event_loop_policy().set_child_watcher(watcher) + def get_sys_argv(self): return id(sys.argv), sys.argv, sys.argv[:] def restore_sys_argv(self, saved_argv): diff --git a/Misc/NEWS.d/next/Tests/2018-05-17-16-50-06.bpo-33562.qmmv60.rst b/Misc/NEWS.d/next/Tests/2018-05-17-16-50-06.bpo-33562.qmmv60.rst new file mode 100644 index 00000000000000..8eac93432c5016 --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2018-05-17-16-50-06.bpo-33562.qmmv60.rst @@ -0,0 +1 @@ +Verify that tests are not modifying global settings for asyncio. From a00094cb8ec3e61ebd1f8f6d202711ec3ba0e8b1 Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Thu, 17 May 2018 16:50:48 -0400 Subject: [PATCH 2/7] Make test_asyncgen not wipe out the global event loop --- Lib/test/test_asyncgen.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_asyncgen.py b/Lib/test/test_asyncgen.py index 5a36423dc97afa..0cdead54d80a7b 100644 --- a/Lib/test/test_asyncgen.py +++ b/Lib/test/test_asyncgen.py @@ -322,12 +322,14 @@ async def gen(): class AsyncGenAsyncioTest(unittest.TestCase): def setUp(self): + self.old_loop = asyncio.get_event_loop() self.loop = asyncio.new_event_loop() asyncio.set_event_loop(None) def tearDown(self): self.loop.close() - self.loop = None + asyncio.set_event_loop(self.old_loop) + self.old_loop = self.loop = None async def to_list(self, gen): res = [] From 369df0a920211561a38ab34a7ed449d8031ffae3 Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Thu, 17 May 2018 17:13:12 -0400 Subject: [PATCH 3/7] Don't clobber the event loop in test_contextlib_async --- Lib/test/test_contextlib_async.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_contextlib_async.py b/Lib/test/test_contextlib_async.py index 879ddbe0e11853..469824142f9736 100644 --- a/Lib/test/test_contextlib_async.py +++ b/Lib/test/test_contextlib_async.py @@ -11,6 +11,7 @@ def _async_test(func): """Decorator to turn an async function into a test case.""" @functools.wraps(func) def wrapper(*args, **kwargs): + old_loop = asyncio.get_event_loop() coro = func(*args, **kwargs) loop = asyncio.new_event_loop() asyncio.set_event_loop(loop) @@ -18,7 +19,7 @@ def wrapper(*args, **kwargs): return loop.run_until_complete(coro) finally: loop.close() - asyncio.set_event_loop(None) + asyncio.set_event_loop(old_loop) return wrapper @@ -292,10 +293,14 @@ def __exit__(self, *exc_details): exit_stack = SyncAsyncExitStack def setUp(self): + self.old_loop = asyncio.get_event_loop() self.loop = asyncio.new_event_loop() asyncio.set_event_loop(self.loop) self.addCleanup(self.loop.close) + def tearDown(self): + asyncio.set_event_loop(self.old_loop) + @_async_test async def test_async_callback(self): expected = [ From 882df3d0e87138fbe512f54cede1c620821b4200 Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Thu, 17 May 2018 17:14:54 -0400 Subject: [PATCH 4/7] Don't have test_coroutines clobber the global event loop --- Lib/test/test_coroutines.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_coroutines.py b/Lib/test/test_coroutines.py index 47753e2ef03fef..d06d697fd6cf85 100644 --- a/Lib/test/test_coroutines.py +++ b/Lib/test/test_coroutines.py @@ -2134,6 +2134,7 @@ async def f(): raise MyException buffer.append('unreachable') + old_loop = asyncio.get_event_loop() loop = asyncio.new_event_loop() asyncio.set_event_loop(loop) try: @@ -2142,7 +2143,7 @@ async def f(): pass finally: loop.close() - asyncio.set_event_loop(None) + asyncio.set_event_loop(old_loop) self.assertEqual(buffer, [1, 2, 'MyException']) From d90c8ae2a93e611761408bae4d7426d2db377ffd Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Thu, 17 May 2018 17:20:01 -0400 Subject: [PATCH 5/7] Alphabetize the imports in test_socket --- Lib/test/test_socket.py | 44 ++++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py index 44501d922ad348..f9d1d9e670a3ca 100644 --- a/Lib/test/test_socket.py +++ b/Lib/test/test_socket.py @@ -1,37 +1,37 @@ import unittest from test import support +import _thread as thread +import array +import contextlib import errno +try: + import fcntl +except ImportError: + fcntl = None import io import itertools -import socket -import select -import tempfile -import time -import traceback -import queue -import sys -import os -import array -import contextlib -from weakref import proxy -import signal import math +try: + import multiprocessing +except ImportError: + multiprocessing = False +import os import pickle -import struct +import queue import random +import select import shutil +import signal +import socket import string -import _thread as thread +import struct +import sys +import tempfile import threading -try: - import multiprocessing -except ImportError: - multiprocessing = False -try: - import fcntl -except ImportError: - fcntl = None +import time +import traceback +from weakref import proxy HOST = support.HOST MSG = 'Michael Gilfix was here\u1234\r\n'.encode('utf-8') ## test unicode string and carriage return From 42073cbd07d4f168e834b791ee83c532d76916c3 Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Thu, 17 May 2018 17:33:21 -0400 Subject: [PATCH 6/7] Have test_sys_settrace not globber the global event loop --- Lib/test/test_sys_settrace.py | 1 + 1 file changed, 1 insertion(+) diff --git a/Lib/test/test_sys_settrace.py b/Lib/test/test_sys_settrace.py index f5125a450511d2..d34eaca1793a5b 100644 --- a/Lib/test/test_sys_settrace.py +++ b/Lib/test/test_sys_settrace.py @@ -634,6 +634,7 @@ def no_jump_without_trace_function(): class JumpTestCase(unittest.TestCase): def setUp(self): + self.addCleanup(asyncio.set_event_loop, asyncio.get_event_loop()) self.addCleanup(sys.settrace, sys.gettrace()) sys.settrace(None) From 0184e052405b7d650fa301a661057fa424c05e3a Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Thu, 17 May 2018 17:36:32 -0400 Subject: [PATCH 7/7] Simplify resetting the event loop --- Lib/test/test_asyncgen.py | 5 ++--- Lib/test/test_contextlib_async.py | 5 +---- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/Lib/test/test_asyncgen.py b/Lib/test/test_asyncgen.py index 0cdead54d80a7b..dfb28b538d6b39 100644 --- a/Lib/test/test_asyncgen.py +++ b/Lib/test/test_asyncgen.py @@ -322,14 +322,13 @@ async def gen(): class AsyncGenAsyncioTest(unittest.TestCase): def setUp(self): - self.old_loop = asyncio.get_event_loop() + self.addCleanup(asyncio.set_event_loop, asyncio.get_event_loop()) self.loop = asyncio.new_event_loop() asyncio.set_event_loop(None) def tearDown(self): self.loop.close() - asyncio.set_event_loop(self.old_loop) - self.old_loop = self.loop = None + self.loop = None async def to_list(self, gen): res = [] diff --git a/Lib/test/test_contextlib_async.py b/Lib/test/test_contextlib_async.py index 469824142f9736..ee4d60fb3a6ca4 100644 --- a/Lib/test/test_contextlib_async.py +++ b/Lib/test/test_contextlib_async.py @@ -293,14 +293,11 @@ def __exit__(self, *exc_details): exit_stack = SyncAsyncExitStack def setUp(self): - self.old_loop = asyncio.get_event_loop() + self.addCleanup(asyncio.set_event_loop, asyncio.get_event_loop()) self.loop = asyncio.new_event_loop() asyncio.set_event_loop(self.loop) self.addCleanup(self.loop.close) - def tearDown(self): - asyncio.set_event_loop(self.old_loop) - @_async_test async def test_async_callback(self): expected = [