1 |
Since the AsynchronousTask.wait() method is prone to event loop |
2 |
recursion, deprecate it, and add an async_wait() method method to |
3 |
replace it. Instead of using task.wait() in order to implicitly run |
4 |
the event loop, now loop.run_until_complete(task.async_wait()) will |
5 |
be used to explicitly run the event loop. This explicit approach will |
6 |
make it more obvious when code will trigger event loop recursion |
7 |
which would not be compatible with asyncio's default event loop. |
8 |
|
9 |
Bug: https://bugs.gentoo.org/653856 |
10 |
--- |
11 |
pym/_emerge/AsynchronousTask.py | 23 +++++++++++++++++++++++ |
12 |
pym/portage/tests/ebuild/test_ipc_daemon.py | 2 +- |
13 |
2 files changed, 24 insertions(+), 1 deletion(-) |
14 |
|
15 |
diff --git a/pym/_emerge/AsynchronousTask.py b/pym/_emerge/AsynchronousTask.py |
16 |
index e29324440..a2f1798fe 100644 |
17 |
--- a/pym/_emerge/AsynchronousTask.py |
18 |
+++ b/pym/_emerge/AsynchronousTask.py |
19 |
@@ -29,6 +29,26 @@ class AsynchronousTask(SlotObject): |
20 |
self._start_hook() |
21 |
self._start() |
22 |
|
23 |
+ def async_wait(self): |
24 |
+ """ |
25 |
+ Wait for returncode asynchronously. Notification is available |
26 |
+ via the add_done_callback method of the returned Future instance. |
27 |
+ |
28 |
+ @returns: Future, result is self.returncode |
29 |
+ """ |
30 |
+ waiter = self.scheduler.create_future() |
31 |
+ exit_listener = lambda self: waiter.set_result(self.returncode) |
32 |
+ self.addExitListener(exit_listener) |
33 |
+ waiter.add_done_callback(lambda waiter: |
34 |
+ self.removeExitListener(exit_listener) if waiter.cancelled() else None) |
35 |
+ if self.returncode is not None: |
36 |
+ # If the returncode is None, it means the exit event has already |
37 |
+ # happened, so use _async_wait() to guarantee that the exit_listener |
38 |
+ # is called. This does not do any harm because a given exit |
39 |
+ # listener is never called more than once. |
40 |
+ self._async_wait() |
41 |
+ return waiter |
42 |
+ |
43 |
def _start(self): |
44 |
self.returncode = os.EX_OK |
45 |
self.wait() |
46 |
@@ -47,6 +67,9 @@ class AsynchronousTask(SlotObject): |
47 |
return self.returncode |
48 |
|
49 |
def wait(self): |
50 |
+ """ |
51 |
+ Deprecated. Use async_wait() instead. |
52 |
+ """ |
53 |
if self.returncode is None: |
54 |
if not self._waiting: |
55 |
self._waiting = True |
56 |
diff --git a/pym/portage/tests/ebuild/test_ipc_daemon.py b/pym/portage/tests/ebuild/test_ipc_daemon.py |
57 |
index bc18cdf64..e6da51a76 100644 |
58 |
--- a/pym/portage/tests/ebuild/test_ipc_daemon.py |
59 |
+++ b/pym/portage/tests/ebuild/test_ipc_daemon.py |
60 |
@@ -157,6 +157,6 @@ class IpcDaemonTestCase(TestCase): |
61 |
try: |
62 |
task_scheduler.start() |
63 |
event_loop.run_until_complete(self._run_done) |
64 |
- task_scheduler.wait() |
65 |
+ event_loop.run_until_complete(task_scheduler.async_wait()) |
66 |
finally: |
67 |
timeout_handle.cancel() |
68 |
-- |
69 |
2.13.6 |