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