Browse code

add methods to the async runner for displaying its current status

Joseph Weston authored on 15/02/2018 17:40:52
Showing 2 changed files
... ...
@@ -253,6 +253,74 @@ class AsyncRunner(BaseRunner):
253 253
         end_time = self.end_time if self.task.done() else time.time()
254 254
         return end_time - self.start_time
255 255
 
256
+    def status(self):
257
+        """Return the runner status as a string.
258
+
259
+        The possible statuses are: running, cancelled, failed, and finished.
260
+        """
261
+        try:
262
+            self.task.result()
263
+        except asyncio.CancelledError:
264
+            return 'cancelled'
265
+        except asyncio.InvalidStateError:
266
+            return 'running'
267
+        except Exception:
268
+            return 'failed'
269
+        else:
270
+            return 'finished'
271
+
272
+    def live_info(self, *, update_interval=0.5):
273
+        """Display live information about the runner.
274
+
275
+        Returns an interactive ipywidget that can be
276
+        visualized in a Jupyter notebook.
277
+        """
278
+        import ipywidgets as widgets
279
+        from IPython.display import display
280
+
281
+        status = widgets.HTML(value=self._info_html())
282
+
283
+        cancel = widgets.Button(description='cancel runner',
284
+                                layout=widgets.Layout(width='100px'))
285
+        cancel.on_click(lambda _: self.cancel())
286
+
287
+        async def update():
288
+            while not self.task.done():
289
+                await asyncio.sleep(update_interval)
290
+                status.value = self._info_html()
291
+            status.value = self._info_html()
292
+
293
+        self.ioloop.create_task(update())
294
+
295
+        hbox = widgets.HBox(
296
+            (status, cancel),
297
+            description='Runner stats',
298
+            layout=widgets.Layout(border='solid 1px',
299
+                                  width='200px',
300
+                                  align_items='center'),
301
+        )
302
+        return display(hbox)
303
+
304
+    def _info_html(self):
305
+        info = [
306
+            ('status', self.status()),
307
+            ('elapsed time', datetime.timedelta(seconds=self.elapsed_time())),
308
+        ]
309
+
310
+        try:
311
+            info.append(('# of points', self.learner.n))
312
+        except Exception:
313
+            pass
314
+
315
+        template = '<dt>{}</dt><dd>{}</dd>'
316
+        table = '\n'.join(template.format(k, v) for k, v in info)
317
+
318
+        return f'''
319
+            <dl>
320
+            {table}
321
+            </dl>
322
+        '''
323
+
256 324
     def cancel(self):
257 325
         """Cancel the runner.
258 326
 
... ...
@@ -12,9 +12,13 @@ install_requires = [
12 12
     'jupyter_client>=5.2.2',  # because https://github.com/jupyter/jupyter_client/pull/314
13 13
 ]
14 14
 
15
-extras_require = {'recommended': ['holoviews>=1.9.1',
16
-                                  'ipyparallel',
17
-                                  'distributed']}
15
+extras_require = {
16
+    'recommended': [
17
+        'holoviews>=1.9.1',
18
+        'ipyparallel',
19
+        'distributed',
20
+        'ipywidgets',
21
+    ],
18 22
 
19 23
 setup(
20 24
     name='adaptive',