Timers¶
Pyface provides a unified interface for toolkit timers. There are two levels to this inferface: a simple functional interface for simple single-shot deferred callbacks, and a more complex interface for application-level timers such as heartbeats and periodic monitors.
It is worth remembering that timers are only as accurate as the underlying toolkit and operating system permit; in particular the toolkits usually guarantee that they will be called no sooner than any specified delay, but they may be called much later (eg. worst case, if an operating system sleep occurs between a timer being set and being run, the delay can be arbitrarily long).
Functional Interface¶
The basic functional interface is found in pyface.timer.do_later
.
This provides two functions do_later()
and
do_after()
. These two functions behave in
essentially the same way, expecting a callback with arguments to be performed
once at some later time, the difference being that
do_later
hard-codes the time to be 50
milliseconds.
import datetime
from pyface.timer.api import do_after, do_later
DEFAULT_DELTA = datetime.timedelta(milliseconds=50)
def report_time(time_started, expected_delay=DEFAULT_DELTA):
time_now = datetime.datetime.utcnow()
print("Time started: {}".format(time_started))
print("Time now: {}".format(time_now))
print("Expected delay: {}".format(expected_delay))
print("Actual delay: {}".format(time_now - time_started))
now = datetime.utcnow()
delay=datetime.timedelta(seconds=10)
do_after(10 * 1000, report_time, now, expected_delay=delay)
now = datetime.utcnow()
do_later(report_time, now)
Note
For historical reasons, the pyface.timer.do_later
API expects
times to be specified in milliseconds instead of seconds.
An alternative functional interface with similar capabilties is available via
the pyface.timer.timer.CallbackTimer.single_shot()
class method.
Timer Classes¶
For more complex needs, the pyface.timer.timer
module provides a
base timer class and several convenience subclasses for common use cases.
PyfaceTimer¶
The pyface.timer.timer.PyfaceTimer
is a base class that can be
subclassed by providing a _perform()
method.
import datetime
from pyface.timer.api import PyfaceTimer
class CustomTimer(PyfaceTimer):
def _perform(self):
print("The time is {}".format(datetime.datetime.now()))
PyfaceTimer
and its subclasses provide a
number of traits and methods to control the frequency and number of times the
timer performs its action. The most important of these is
interval
which determines the time
until the first call and between any subsequent calls.
Timers are explicitly started by explicitly calling their
start()
method, or by setting their
active
trait to True
. By
default, the timer will repeat indefinately until it is explicitly
halted via stop()
or setting
active
trait to False
(or by the
application shutting down).
Rather than controlling the active state of the timer explicitly, the number of
invocations of the perfom()
method can
be controlled either via setting the
repeat
trait to an explicit number
of times to repeat and/or setting the
expire
trait to a maximum number of
seconds for the timer to run (which could potentially mean that the timer never
gets performed).
For example, a timer which repeats every 0.5 seconds and runs no more than 10 times and for no longer than 10 seconds can be started like this -
timer = CustomTimer(interval=0.5, repeat=10, expire=10)
timer.start()
PyfaceTimer
also provides two convenience class
methods for creating and starting a timer in one line. The above example
could instead be written as -
timer = CustomTimer.timer(interval=0.5, repeat=10, expire=10)
For the common case of a “single-shot” timer that is only performed once,
there is the single_shot()
class
method that creates a timer that will be called once after the specified
interval -
CustomTimer.single_shot(interval=0.5)
Note
To avoid the Python timer objects being garbage-collected prematurely, references are kept to all active timers by Pyface. This means that you can safely create timers without having to explicitly hold a long-term reference to them if you do not need it for other reasons.
CallbackTimer¶
Rather than subclassing PyfaceTimer
for every
timer that you want, it is often enough to supply a callback function (possibly
with arguments) to be called by the timer. Pyface provides the
CallbackTimer
class for this purpose.
This class is meant to be directly instantiated, providing at a minimum a
callable value for the callback
trait, along with an optional tuple of
args
and/or optional dict of
kwargs
.
from pyface.timer.api import CallbackTimer
def print_time():
print("The time is {}".format(datetime.datetime.now()))
CallbackTimer.timer(callback=print_time, interval=0.5, expire=60)
EventTimer¶
Another common use case is that you want a Traits Event to be fired
periodically or at some future time. This permits many possible listeners
to be called from the same timer, and have them be turned on and turned off
dynamically, if desired, via
Traits’ observe
(note that observe listeners are required to take a single event argument).
The EventTimer
provides this functionality via
its timeout
event trait.
from pyface.timer.api import EventTimer
def print_time(event):
print("The time is {}".format(datetime.datetime.now()))
timer = EventTimer(interval=0.5, expire=60)
timer.observe(print_time, 'timeout')
timer.start()
The EventTimer
class is particularly suited to
be used as an application “heartbeat” that arbitrary code can hook into to be
run periodically without having to create its own timer.
Deprecated Classes¶
Pyface also provides a deprecated Timer
class for backwards compatability. This class shouldn’t be used in new code.