Skip to content

Commit

Permalink
Implement PeriodicCallback
Browse files Browse the repository at this point in the history
  • Loading branch information
philippjfr committed Mar 31, 2019
1 parent a09e829 commit 145983b
Show file tree
Hide file tree
Showing 2 changed files with 109 additions and 0 deletions.
78 changes: 78 additions & 0 deletions panel/callbacks.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
"""
Defines callbacks to be executed on a thread or by scheduling it
on a running bokeh server.
"""
from __future__ import absolute_import, division, unicode_literals


import time
import param

from bokeh.io import curdoc as _curdoc

from .viewable import Reactive


class PeriodicCallback(param.Parameterized):
"""
Periodic encapsulates a periodic callback which will run both
in tornado based notebook environments and on bokeh server. By
default the callback will run until the stop method is called,
but count and timeout values can be set to limit the number of
executions or the maximum length of time for which the callback
will run.
"""

callback = param.Callable(doc="""
The callback to execute periodically.""")

count = param.Integer(default=None, doc="""
Number of times the callback will be executed, by default
this is unlimited.""")

period = param.Integer(default=500, doc="""
Period in milliseconds at which the callback is executed.""")

timeout = param.Integer(default=None, doc="""
Timeout in seconds from the start time at which the callback
expires""")

def __init__(self, **params):
super(PeriodicCallback, self).__init__(**params)
self._counter = 0
self._start_time = None
self._timeout = None
self._cb = None

def start(self):
if self._cb is not None:
raise RuntimeError('Periodic callback has already started.')
self._start_time = time.time()
if _curdoc().session_context:
doc = _curdoc()
self._cb = doc.add_periodic_callback(self._periodic_callback, self.period)
else:
from tornado.ioloop import PeriodicCallback
self._cb = PeriodicCallback(self._periodic_callback, self.period)
self._cb.start()

def _periodic_callback(self):
self.callback()
self._counter += 1
if self._timeout is not None:
dt = (time.time() - self._start_time)
if dt > self._timeout:
self.stop()
if self._counter == self.count:
self.stop()

def stop(self):
self._counter = 0
self._timeout = None
if _curdoc().session_context:
doc = _curdoc()
doc.remove_periodic_callback(self._cb)
else:
self._cb.stop()
self._cb = None

31 changes: 31 additions & 0 deletions panel/viewable.py
Original file line number Diff line number Diff line change
Expand Up @@ -753,6 +753,37 @@ def link(*events):
self._callbacks.append(cb)
return cb

def add_periodic_callback(self, callback, period=500, count=None,
timeout=None, start=True):
"""
Schedules a periodic callback to be run at an interval set by
the period. Returns a PeriodicCallback object with the option
to stop and start the callback.
Arguments
---------
callback: callable
Callable function to be called at timeout.
period: int
Interval in milliseconds at which callback will be executed.
count: int
Maximum number of times callback will be invoked.
timeout: int
Timeout in seconds when the callback should be stopped.
start: boolean (default=True)
Whether to start callback immediately.
Returns
-------
Return a PeriodicCallback object with start and stop methods.
"""
from .callbacks import PeriodicCallback
cb = PeriodicCallback(callback=callback, period=period,
count=count, timeout=timeout)
if start:
cb.start()
return cb

def jslink(self, target, code=None, **links):
"""
Links properties on the source object to those on the target
Expand Down

0 comments on commit 145983b

Please sign in to comment.