summaryrefslogtreecommitdiffstats
path: root/Lib/test/test_asyncio
diff options
context:
space:
mode:
authorMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>2019-06-30 10:22:34 (GMT)
committerGitHub <noreply@github.com>2019-06-30 10:22:34 (GMT)
commitbf8cb31803558f1105efb15b0ee4bd184f3218c8 (patch)
tree3b4f661e23b6affdc972fb3b49bd5869fa741f08 /Lib/test/test_asyncio
parentffcc161c753a72e7c4237c1e3c433d47b020978e (diff)
downloadcpython-bf8cb31803558f1105efb15b0ee4bd184f3218c8.zip
cpython-bf8cb31803558f1105efb15b0ee4bd184f3218c8.tar.gz
cpython-bf8cb31803558f1105efb15b0ee4bd184f3218c8.tar.bz2
bpo-35621: Support running subprocesses in asyncio when loop is executed in non-main thread (GH-14344)
(cherry picked from commit 0d671c04c39b52e44597491b893eb0b6c86b3d45) Co-authored-by: Andrew Svetlov <andrew.svetlov@gmail.com>
Diffstat (limited to 'Lib/test/test_asyncio')
-rw-r--r--Lib/test/test_asyncio/test_subprocess.py40
-rw-r--r--Lib/test/test_asyncio/test_unix_events.py34
-rw-r--r--Lib/test/test_asyncio/utils.py13
3 files changed, 61 insertions, 26 deletions
diff --git a/Lib/test/test_asyncio/test_subprocess.py b/Lib/test/test_asyncio/test_subprocess.py
index e9a9e50..b9578b2 100644
--- a/Lib/test/test_asyncio/test_subprocess.py
+++ b/Lib/test/test_asyncio/test_subprocess.py
@@ -633,6 +633,7 @@ class SubprocessMixin:
self.assertIsNone(self.loop.run_until_complete(execute()))
+
if sys.platform != 'win32':
# Unix
class SubprocessWatcherMixin(SubprocessMixin):
@@ -648,7 +649,24 @@ if sys.platform != 'win32':
watcher = self.Watcher()
watcher.attach_loop(self.loop)
policy.set_child_watcher(watcher)
- self.addCleanup(policy.set_child_watcher, None)
+
+ def tearDown(self):
+ super().tearDown()
+ policy = asyncio.get_event_loop_policy()
+ watcher = policy.get_child_watcher()
+ policy.set_child_watcher(None)
+ watcher.attach_loop(None)
+ watcher.close()
+
+ class SubprocessThreadedWatcherTests(SubprocessWatcherMixin,
+ test_utils.TestCase):
+
+ Watcher = unix_events.ThreadedChildWatcher
+
+ class SubprocessMultiLoopWatcherTests(SubprocessWatcherMixin,
+ test_utils.TestCase):
+
+ Watcher = unix_events.MultiLoopChildWatcher
class SubprocessSafeWatcherTests(SubprocessWatcherMixin,
test_utils.TestCase):
@@ -670,5 +688,25 @@ else:
self.set_event_loop(self.loop)
+class GenericWatcherTests:
+
+ def test_create_subprocess_fails_with_inactive_watcher(self):
+
+ async def execute():
+ watcher = mock.create_authspec(asyncio.AbstractChildWatcher)
+ watcher.is_active.return_value = False
+ asyncio.set_child_watcher(watcher)
+
+ with self.assertRaises(RuntimeError):
+ await subprocess.create_subprocess_exec(
+ support.FakePath(sys.executable), '-c', 'pass')
+
+ watcher.add_child_handler.assert_not_called()
+
+ self.assertIsNone(self.loop.run_until_complete(execute()))
+
+
+
+
if __name__ == '__main__':
unittest.main()
diff --git a/Lib/test/test_asyncio/test_unix_events.py b/Lib/test/test_asyncio/test_unix_events.py
index 5c610cd..462a8b3 100644
--- a/Lib/test/test_asyncio/test_unix_events.py
+++ b/Lib/test/test_asyncio/test_unix_events.py
@@ -1083,6 +1083,8 @@ class AbstractChildWatcherTests(unittest.TestCase):
self.assertRaises(
NotImplementedError, watcher.close)
self.assertRaises(
+ NotImplementedError, watcher.is_active)
+ self.assertRaises(
NotImplementedError, watcher.__enter__)
self.assertRaises(
NotImplementedError, watcher.__exit__, f, f, f)
@@ -1784,15 +1786,6 @@ class ChildWatcherTestsMixin:
if isinstance(self.watcher, asyncio.FastChildWatcher):
self.assertFalse(self.watcher._zombies)
- @waitpid_mocks
- def test_add_child_handler_with_no_loop_attached(self, m):
- callback = mock.Mock()
- with self.create_watcher() as watcher:
- with self.assertRaisesRegex(
- RuntimeError,
- 'the child watcher does not have a loop attached'):
- watcher.add_child_handler(100, callback)
-
class SafeChildWatcherTests (ChildWatcherTestsMixin, test_utils.TestCase):
def create_watcher(self):
@@ -1809,17 +1802,16 @@ class PolicyTests(unittest.TestCase):
def create_policy(self):
return asyncio.DefaultEventLoopPolicy()
- def test_get_child_watcher(self):
+ def test_get_default_child_watcher(self):
policy = self.create_policy()
self.assertIsNone(policy._watcher)
watcher = policy.get_child_watcher()
- self.assertIsInstance(watcher, asyncio.SafeChildWatcher)
+ self.assertIsInstance(watcher, asyncio.ThreadedChildWatcher)
self.assertIs(policy._watcher, watcher)
self.assertIs(watcher, policy.get_child_watcher())
- self.assertIsNone(watcher._loop)
def test_get_child_watcher_after_set(self):
policy = self.create_policy()
@@ -1829,18 +1821,6 @@ class PolicyTests(unittest.TestCase):
self.assertIs(policy._watcher, watcher)
self.assertIs(watcher, policy.get_child_watcher())
- def test_get_child_watcher_with_mainloop_existing(self):
- policy = self.create_policy()
- loop = policy.get_event_loop()
-
- self.assertIsNone(policy._watcher)
- watcher = policy.get_child_watcher()
-
- self.assertIsInstance(watcher, asyncio.SafeChildWatcher)
- self.assertIs(watcher._loop, loop)
-
- loop.close()
-
def test_get_child_watcher_thread(self):
def f():
@@ -1866,7 +1846,11 @@ class PolicyTests(unittest.TestCase):
policy = self.create_policy()
loop = policy.get_event_loop()
- watcher = policy.get_child_watcher()
+ # Explicitly setup SafeChildWatcher,
+ # default ThreadedChildWatcher has no _loop property
+ watcher = asyncio.SafeChildWatcher()
+ policy.set_child_watcher(watcher)
+ watcher.attach_loop(loop)
self.assertIs(watcher._loop, loop)
diff --git a/Lib/test/test_asyncio/utils.py b/Lib/test/test_asyncio/utils.py
index cb373d5..5b4bb12 100644
--- a/Lib/test/test_asyncio/utils.py
+++ b/Lib/test/test_asyncio/utils.py
@@ -1,5 +1,6 @@
"""Utilities shared by tests."""
+import asyncio
import collections
import contextlib
import io
@@ -512,6 +513,18 @@ class TestCase(unittest.TestCase):
if executor is not None:
executor.shutdown(wait=True)
loop.close()
+ policy = support.maybe_get_event_loop_policy()
+ if policy is not None:
+ try:
+ watcher = policy.get_child_watcher()
+ except NotImplementedError:
+ # watcher is not implemented by EventLoopPolicy, e.g. Windows
+ pass
+ else:
+ if isinstance(watcher, asyncio.ThreadedChildWatcher):
+ threads = list(watcher._threads.values())
+ for thread in threads:
+ thread.join()
def set_event_loop(self, loop, *, cleanup=True):
assert loop is not None