diff --git a/Doc/library/sched.rst b/Doc/library/sched.rst index 000dba00c4b..a644ed2a69e 100644 --- a/Doc/library/sched.rst +++ b/Doc/library/sched.rst @@ -14,7 +14,7 @@ The :mod:`sched` module defines a class which implements a general purpose event scheduler: -.. class:: scheduler(timefunc, delayfunc) +.. class:: scheduler(timefunc=time.time, delayfunc=time.sleep) The :class:`scheduler` class defines a generic interface to scheduling events. It needs two functions to actually deal with the "outside world" --- *timefunc* @@ -25,6 +25,9 @@ scheduler: event is run to allow other threads an opportunity to run in multi-threaded applications. + .. versionchanged:: 3.3 + *timefunc* and *delayfunc* parameters are optional. + Example:: >>> import sched, time @@ -79,26 +82,38 @@ Scheduler Objects :class:`scheduler` instances have the following methods and attributes: -.. method:: scheduler.enterabs(time, priority, action, argument) +.. method:: scheduler.enterabs(time, priority, action, argument=[], kwargs={}) Schedule a new event. The *time* argument should be a numeric type compatible with the return value of the *timefunc* function passed to the constructor. Events scheduled for the same *time* will be executed in the order of their *priority*. - Executing the event means executing ``action(*argument)``. *argument* must be a - sequence holding the parameters for *action*. + Executing the event means executing ``action(*argument, **kwargs)``. + *argument* must be a sequence holding the parameters for *action*. + *kwargs* must be a dictionary holding the keyword parameters for *action*. Return value is an event which may be used for later cancellation of the event (see :meth:`cancel`). + .. versionchanged:: 3.3 + *argument* parameter is optional. -.. method:: scheduler.enter(delay, priority, action, argument) + .. versionadded:: 3.3 + *kwargs* parameter was added. + + +.. method:: scheduler.enter(delay, priority, action, argument=[], kwargs={}) Schedule an event for *delay* more time units. Other than the relative time, the other arguments, the effect and the return value are the same as those for :meth:`enterabs`. + .. versionchanged:: 3.3 + *argument* parameter is optional. + + .. versionadded:: 3.3 + *kwargs* parameter was added. .. method:: scheduler.cancel(event) diff --git a/Doc/whatsnew/3.3.rst b/Doc/whatsnew/3.3.rst index fa48623e2c1..4122b980118 100644 --- a/Doc/whatsnew/3.3.rst +++ b/Doc/whatsnew/3.3.rst @@ -572,6 +572,22 @@ should be used. For example, this will send a ``'HEAD'`` request:: (:issue:`1673007`) +sched +----- + +* *timefunc* and *delayfunct* parameters of :class:`~sched.scheduler` class + constructor are now optional and defaults to :func:`time.time` and + :func:`time.sleep` respectively. (Contributed by Matt Mulsow in + :issue:`8809`) + +* :meth:`~sched.scheduler.enter` and :meth:`~sched.scheduler.enterabs` + *argument* parameter is now optional. (Contributed by Matt Mulsow in + :issue:`8809`) + +* :meth:`~sched.scheduler.enter` and :meth:`~sched.scheduler.enterabs` + now accept a *kwargs* parameter. (Contributed by Matt Mulsow in + :issue:`8809`) + Optimizations ============= @@ -744,4 +760,3 @@ Other issues .. Issue #10998: the -Q command-line flag and related artifacts have been removed. Code checking sys.flags.division_warning will need updating. Contributed by Éric Araujo. - diff --git a/Lib/sched.py b/Lib/sched.py index a119892c3f6..6c01e6968aa 100644 --- a/Lib/sched.py +++ b/Lib/sched.py @@ -28,12 +28,13 @@ # 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 __all__ = ["scheduler"] -class Event(namedtuple('Event', 'time, priority, action, argument')): +class Event(namedtuple('Event', 'time, priority, action, argument, kwargs')): def __eq__(s, o): return (s.time, s.priority) == (o.time, o.priority) def __ne__(s, o): return (s.time, s.priority) != (o.time, o.priority) def __lt__(s, o): return (s.time, s.priority) < (o.time, o.priority) @@ -42,32 +43,33 @@ def __gt__(s, o): return (s.time, s.priority) > (o.time, o.priority) def __ge__(s, o): return (s.time, s.priority) >= (o.time, o.priority) class scheduler: - def __init__(self, timefunc, delayfunc): + + def __init__(self, timefunc=time.time, delayfunc=time.sleep): """Initialize a new instance, passing the time and delay functions""" self._queue = [] self.timefunc = timefunc self.delayfunc = delayfunc - def enterabs(self, time, priority, action, argument): + def enterabs(self, time, priority, action, argument=[], kwargs={}): """Enter a new event in the queue at an absolute time. Returns an ID for the event which can be used to remove it, if necessary. """ - event = Event(time, priority, action, argument) + event = Event(time, priority, action, argument, kwargs) heapq.heappush(self._queue, event) return event # The ID - def enter(self, delay, priority, action, argument): + def enter(self, delay, priority, action, argument=[], kwargs={}): """A variant that specifies the time as a relative time. This is actually the more commonly used interface. """ time = self.timefunc() + delay - return self.enterabs(time, priority, action, argument) + return self.enterabs(time, priority, action, argument, kwargs) def cancel(self, event): """Remove an event from the queue. @@ -111,7 +113,7 @@ def run(self): timefunc = self.timefunc pop = heapq.heappop while q: - time, priority, action, argument = checked_event = q[0] + time, priority, action, argument, kwargs = checked_event = q[0] now = timefunc() if now < time: delayfunc(time - now) @@ -120,7 +122,7 @@ def run(self): # Verify that the event was not removed or altered # by another thread after we last looked at q[0]. if event is checked_event: - action(*argument) + action(*argument, **kwargs) delayfunc(0) # Let other threads run else: heapq.heappush(q, event) diff --git a/Lib/test/test_sched.py b/Lib/test/test_sched.py index 29fd277746f..1af43cbaea6 100644 --- a/Lib/test/test_sched.py +++ b/Lib/test/test_sched.py @@ -72,6 +72,18 @@ def test_queue(self): scheduler.run() self.assertEqual(scheduler._queue, []) + def test_args_kwargs(self): + flag = [] + + def fun(*a, **b): + flag.append(None) + self.assertEqual(a, (1,2,3)) + self.assertEqual(b, {"foo":1}) + + scheduler = sched.scheduler(time.time, time.sleep) + z = scheduler.enterabs(0.01, 1, fun, argument=(1,2,3), kwargs={"foo":1}) + scheduler.run() + self.assertEqual(flag, [None]) def test_main(): support.run_unittest(TestCase) diff --git a/Misc/ACKS b/Misc/ACKS index 952644bf156..1036065cae5 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -11,6 +11,7 @@ Without you, I would've stopped working on Python long ago! PS: In the standard Python distribution, this file is encoded in UTF-8 and the list is in rough alphabetical order by last names. +Matt Mulsow Rajiv Abraham David Abrahams Ron Adam diff --git a/Misc/NEWS b/Misc/NEWS index 6f7740b49b6..23a67eed236 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -387,6 +387,11 @@ Core and Builtins Library ------- +- Issue #13245: sched.scheduler class constructor's timefunc and + delayfunct parameters are now optional. + scheduler.enter and scheduler.enterabs methods gained a new kwargs parameter. + Patch contributed by Matt Mulsow. + - Issue #12328: Under Windows, refactor handling of Ctrl-C events and make _multiprocessing.win32.WaitForMultipleObjects interruptible when the wait_flag parameter is false. Patch by sbt.