8000 bpo-33562: Check for asyncio global setting changes in tests by brettcannon · Pull Request #6958 · python/cpython · GitHub
[go: up one dir, main page]

Skip to content

bpo-33562: Check for asyncio global setting changes in tests #6958

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
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
33 changes: 33 additions & 0 deletions Lib/test/libregrtest/save_env.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import asyncio
import builtins
import locale
import logging
Expand Down Expand Up @@ -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()
Copy link
Member

Choose a reason for hiding this comment

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

This function creates a new policy if there is no current policy. The function has a side effect, so I don't think that it's ok to call it from here.

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()
Copy link
Member

Choose a reason for hiding this comment

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

This function has a side effect: if there is no current event loop, it does create a new one. So I don't think that it's safe to call it. I don't think that we have an API to get the event loop without side effect.

Copy link
Member Author
@brettcannon brettcannon Jun 1, 2018

Choose a reason for hiding this comment

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

Then basically the whole PR is pointless as every single thing here fetches the event loop somehow to check its state. (Which is fine, but we have to be aware that we the asyncio API is slightly deficient such that we can't do this).

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):
Expand Down
1 change: 1 addition & 0 deletions Lib/test/test_asyncgen.py
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,7 @@ async def gen():
class AsyncGenAsyncioTest(unittest.TestCase):

def setUp(self):
self.addCleanup(asyncio.set_event_loop, asyncio.get_event_loop())
Copy link
Member

Choose a reason for hiding this comment

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

Why do we need this?

Copy link
Member Author
self.loop = asyncio.new_event_loop()
asyncio.set_event_loop(None)

Expand Down
4 changes: 3 additions & 1 deletion Lib/test/test_contextlib_async.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,15 @@ 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()
Copy link
Member

Choose a reason for hiding this comment

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

Since asyncio.get_event_loop() API is weird, maybe an context manager helper should be added to test.support?

coro = func(*args, **kwargs)
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
try:
return loop.run_until_complete(coro)
finally:
loop.close()
asyncio.set_event_loop(None)
asyncio.set_event_loop(old_loop)
return wrapper


Expand Down Expand Up @@ -292,6 +293,7 @@ def __exit__(self, *exc_details):
exit_stack = SyncAsyncExitStack

def setUp(self):
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)
Expand Down
3 changes: 2 additions & 1 deletion Lib/test/test_coroutines.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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'])

Expand Down
44 changes: 22 additions & 22 deletions Lib/test/test_socket.py
Original file line number Diff line number Diff line change
@@ -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
Expand Down
1 change: 1 addition & 0 deletions Lib/test/test_sys_settrace.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Verify that tests are not modifying global settings for asyncio.
0