-
-
Notifications
You must be signed in to change notification settings - Fork 32.4k
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
Changes from all commits
c528e05
a00094c
369df0a
882df3d
d90c8ae
42073cb
0184e05
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. There was a problem hiding this comment. Choose a reason for hiding this commentThe 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): | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -322,6 +322,7 @@ async def gen(): | |
class AsyncGenAsyncioTest(unittest.TestCase): | ||
|
||
def setUp(self): | ||
self.addCleanup(asyncio.set_event_loop, asyncio.get_event_loop()) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why do we need this? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Because the tests were wiping out the event loop and were triggering the mutated environment check for the event loop. |
||
self.loop = asyncio.new_event_loop() | ||
asyncio.set_event_loop(None) | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 | ||
|
||
|
||
|
@@ -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) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
Verify that tests are not modifying global settings for asyncio. |
There was a problem hiding this comment.
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.