Fix 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.
This commit is contained in:
Giampaolo Rodola' 2011-11-22 13:33:34 +01:00
parent ca4f20782e
commit be55d99b3d
6 changed files with 64 additions and 14 deletions

View file

@ -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)

View file

@ -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.

View file

@ -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)

View file

@ -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)

View file

@ -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

View file

@ -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.