diff -r 5673cf852daa Lib/sched.py --- a/Lib/sched.py Sat Oct 01 01:06:51 2016 -0500 +++ b/Lib/sched.py Sat Oct 01 21:04:57 2016 +0800 @@ -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,12 @@ self.timefunc = timefunc self.delayfunc = delayfunc + def time(self): + return self.timefunc() + + def delay(self, time_units): + 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 +95,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 +142,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 5673cf852daa Lib/test/test_sched.py --- a/Lib/test/test_sched.py Sat Oct 01 01:06:51 2016 -0500 +++ b/Lib/test/test_sched.py Sat Oct 01 21:04:57 2016 +0800 @@ -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()