diff -r 3fed30fa37f4 Doc/library/sched.rst --- a/Doc/library/sched.rst Tue Oct 04 00:01:03 2016 -0700 +++ b/Doc/library/sched.rst Tue Oct 04 17:05:36 2016 +0530 @@ -131,6 +131,58 @@ .. versionadded:: 3.3 *blocking* parameter was added. +.. method:: scheduler.time() + + Bydefault it takes the value of *timefunc* and calles it. Overriding + this method can lead you to provide custom time function with class. + The return value of this function should be limited to type :class:`integer`. + + .. versionadded:: 3.7 + *scheduler.time()* was added. + +.. method:: scheduler.delay(time_units) + + It provides the delay of given *time_units*. Bydefault the method takes + *delayfun* attribute and calls it with the given *time_units* argument. + Overriding this method will lead you to provide your custom implimentation + of *delayfun*. + + .. versionadded:: 3.7 + *scheduler.delay(time_units)* was added. + + Observe the below example with the change of :func:`Schedule.time` and + :func:`Schedule.delay` as overriden class methods. Rather than attributes + of instances. + +Example:: + + >>> from sched import scheduler + >>> from time import time, sleep + >>> class MyScheduler(scheduler): + ... def time(self): + ... return time() + ... def delay(self, time_units): + ... sleep(time_units) + ... + >>> s = MyScheduler() + >>> def print_time(a='default'): + ... print("From print_time", time(), a) + ... + >>> def print_some_times(): + ... print(time()) + ... s.enter(10, 1, print_time) + ... s.enter(5, 2, print_time, argument=('positional', )) + ... s.enter(5, 1, print_time, kwargs={'a': 'keyword'}) + ... s.run() + ... print(time()) + ... + >>> print_some_times() + 1475579202.6531284 + From print_time 1475579207.655452 positional + From print_time 1475579207.655572 keyword + From print_time 1475579212.6554384 default + 1475579212.6555457 + .. attribute:: scheduler.queue Read-only attribute returning a list of upcoming events in the order they diff -r 3fed30fa37f4 Lib/sched.py --- a/Lib/sched.py Tue Oct 04 00:01:03 2016 -0700 +++ b/Lib/sched.py Tue Oct 04 17:05:36 2016 +0530 @@ -13,6 +13,11 @@ function is allowed to modify the queue. Time can be expressed as integers or floating point numbers, as long as it is consistent. +Another way to customize the time and delay implementation is +by subclassing the scheduler class and override the time and +delay methods, which by default just call the functions passed +when creating an instance. + Events are specified by tuples (time, priority, action, argument, kwargs). As in UNIX, lower priority numbers mean higher priority; in this way the queue can be maintained as a priority queue. Execution of the @@ -23,11 +28,6 @@ has another way to reference private data (besides global variables). """ -# XXX The timefunc and delayfunc should have been defined as methods -# XXX so you can define new kinds of schedulers using subclassing -# XXX instead of having to define a module or class just to hold -# XXX the global state of your particular time and delay functions. - import time import heapq from collections import namedtuple @@ -69,6 +69,20 @@ self.timefunc = timefunc self.delayfunc = delayfunc + def time(self): + """Return the current time. + + The default behavior is to delegate to the timefunc attribute. + """ + return self.timefunc() + + def delay(self, time_units): + """Delay the specified units of time. + + The default behavior is to delegate to the delayfunc attribute. + """ + self.delayfunc(time_units) + def enterabs(self, time, priority, action, argument=(), kwargs=_sentinel): """Enter a new event in the queue at an absolute time. @@ -89,7 +103,7 @@ This is actually the more commonly used interface. """ - time = self.timefunc() + delay + time = self.time() + delay return self.enterabs(time, priority, action, argument, kwargs) def cancel(self, event): @@ -136,27 +150,22 @@ # and to improve thread safety lock = self._lock q = self._queue - delayfunc = self.delayfunc - timefunc = self.timefunc pop = heapq.heappop while True: with lock: if not q: break time, priority, action, argument, kwargs = q[0] - now = timefunc() - if time > now: - delay = True - else: - delay = False - pop(q) + now = self.time() + delay = time > now if delay: if not blocking: return time - now - delayfunc(time - now) + self.delay(time - now) else: + pop(q) action(*argument, **kwargs) - delayfunc(0) # Let other threads run + self.delay(0) # Let other threads run @property def queue(self): diff -r 3fed30fa37f4 Lib/test/test_sched.py --- a/Lib/test/test_sched.py Tue Oct 04 00:01:03 2016 -0700 +++ b/Lib/test/test_sched.py Tue Oct 04 17:05:36 2016 +0530 @@ -2,6 +2,7 @@ import sched import time import unittest +from unittest.mock import Mock try: import threading except ImportError: @@ -193,6 +194,28 @@ scheduler.run(blocking=False) self.assertEqual(l, []) + def test_override_timefunc_and_delayfunc(self): + m_time, m_delay, fun = Mock(), Mock(), Mock() + m_time.side_effect = [1, 2, 3, 4] + + class MyScheduler(sched.scheduler): + def __init__(self): + sched.scheduler.__init__(self) + + def time(self): + return m_time() + + def delay(self, time_units): + m_delay(time_units) + + s = MyScheduler() + s.enter(1, 1, fun, ()) + s.run() + + self.assertEqual(m_time.call_count, 2) + self.assertEqual(m_delay.call_count, 1) + + if __name__ == "__main__": unittest.main()