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.