bpo-19270: Fixed sched.scheduler.cancel to cancel correct event (GH-22729)

This commit is contained in:
Bar Harel 2020-10-19 10:33:43 +03:00 committed by GitHub
parent 155938907c
commit 5368c2b6e2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 23 additions and 10 deletions

View File

@ -26,23 +26,19 @@ has another way to reference private data (besides global variables).
import time import time
import heapq import heapq
from collections import namedtuple from collections import namedtuple
from itertools import count
import threading import threading
from time import monotonic as _time from time import monotonic as _time
__all__ = ["scheduler"] __all__ = ["scheduler"]
class Event(namedtuple('Event', 'time, priority, action, argument, kwargs')): Event = namedtuple('Event', 'time, priority, sequence, action, argument, kwargs')
__slots__ = []
def __eq__(s, o): return (s.time, s.priority) == (o.time, o.priority)
def __lt__(s, o): return (s.time, s.priority) < (o.time, o.priority)
def __le__(s, o): return (s.time, s.priority) <= (o.time, o.priority)
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)
Event.time.__doc__ = ('''Numeric type compatible with the return value of the Event.time.__doc__ = ('''Numeric type compatible with the return value of the
timefunc function passed to the constructor.''') timefunc function passed to the constructor.''')
Event.priority.__doc__ = ('''Events scheduled for the same time will be executed Event.priority.__doc__ = ('''Events scheduled for the same time will be executed
in the order of their priority.''') in the order of their priority.''')
Event.sequence.__doc__ = ('''A continually increasing sequence number that
separates events if time and priority are equal.''')
Event.action.__doc__ = ('''Executing the event means executing Event.action.__doc__ = ('''Executing the event means executing
action(*argument, **kwargs)''') action(*argument, **kwargs)''')
Event.argument.__doc__ = ('''argument is a sequence holding the positional Event.argument.__doc__ = ('''argument is a sequence holding the positional
@ -61,6 +57,7 @@ class scheduler:
self._lock = threading.RLock() self._lock = threading.RLock()
self.timefunc = timefunc self.timefunc = timefunc
self.delayfunc = delayfunc self.delayfunc = delayfunc
self._sequence_generator = count()
def enterabs(self, time, priority, action, argument=(), kwargs=_sentinel): def enterabs(self, time, priority, action, argument=(), kwargs=_sentinel):
"""Enter a new event in the queue at an absolute time. """Enter a new event in the queue at an absolute time.
@ -71,8 +68,10 @@ class scheduler:
""" """
if kwargs is _sentinel: if kwargs is _sentinel:
kwargs = {} kwargs = {}
event = Event(time, priority, action, argument, kwargs)
with self._lock: with self._lock:
event = Event(time, priority, next(self._sequence_generator),
action, argument, kwargs)
heapq.heappush(self._queue, event) heapq.heappush(self._queue, event)
return event # The ID return event # The ID
@ -136,7 +135,8 @@ class scheduler:
with lock: with lock:
if not q: if not q:
break break
time, priority, action, argument, kwargs = q[0] (time, priority, sequence, action,
argument, kwargs) = q[0]
now = timefunc() now = timefunc()
if time > now: if time > now:
delay = True delay = True

View File

@ -142,6 +142,17 @@ class TestCase(unittest.TestCase):
self.assertTrue(q.empty()) self.assertTrue(q.empty())
self.assertEqual(timer.time(), 4) self.assertEqual(timer.time(), 4)
def test_cancel_correct_event(self):
# bpo-19270
events = []
scheduler = sched.scheduler()
scheduler.enterabs(1, 1, events.append, ("a",))
b = scheduler.enterabs(1, 1, events.append, ("b",))
scheduler.enterabs(1, 1, events.append, ("c",))
scheduler.cancel(b)
scheduler.run()
self.assertEqual(events, ["a", "c"])
def test_empty(self): def test_empty(self):
l = [] l = []
fun = lambda x: l.append(x) fun = lambda x: l.append(x)

View File

@ -0,0 +1,2 @@
:meth:`sched.scheduler.cancel()` will now cancel the correct event, if two
events with same priority are scheduled for the same time. Patch by Bar Harel.