Skip to content

Commit 5368c2b

Browse files
authored
bpo-19270: Fixed sched.scheduler.cancel to cancel correct event (GH-22729)
1 parent 1559389 commit 5368c2b

File tree

3 files changed

+23
-10
lines changed

3 files changed

+23
-10
lines changed

Lib/sched.py

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -26,23 +26,19 @@
2626
import time
2727
import heapq
2828
from collections import namedtuple
29+
from itertools import count
2930
import threading
3031
from time import monotonic as _time
3132

3233
__all__ = ["scheduler"]
3334

34-
class Event(namedtuple('Event', 'time, priority, action, argument, kwargs')):
35-
__slots__ = []
36-
def __eq__(s, o): return (s.time, s.priority) == (o.time, o.priority)
37-
def __lt__(s, o): return (s.time, s.priority) < (o.time, o.priority)
38-
def __le__(s, o): return (s.time, s.priority) <= (o.time, o.priority)
39-
def __gt__(s, o): return (s.time, s.priority) > (o.time, o.priority)
40-
def __ge__(s, o): return (s.time, s.priority) >= (o.time, o.priority)
41-
35+
Event = namedtuple('Event', 'time, priority, sequence, action, argument, kwargs')
4236
Event.time.__doc__ = ('''Numeric type compatible with the return value of the
4337
timefunc function passed to the constructor.''')
4438
Event.priority.__doc__ = ('''Events scheduled for the same time will be executed
4539
in the order of their priority.''')
40+
Event.sequence.__doc__ = ('''A continually increasing sequence number that
41+
separates events if time and priority are equal.''')
4642
Event.action.__doc__ = ('''Executing the event means executing
4743
action(*argument, **kwargs)''')
4844
Event.argument.__doc__ = ('''argument is a sequence holding the positional
@@ -61,6 +57,7 @@ def __init__(self, timefunc=_time, delayfunc=time.sleep):
6157
self._lock = threading.RLock()
6258
self.timefunc = timefunc
6359
self.delayfunc = delayfunc
60+
self._sequence_generator = count()
6461

6562
def enterabs(self, time, priority, action, argument=(), kwargs=_sentinel):
6663
"""Enter a new event in the queue at an absolute time.
@@ -71,8 +68,10 @@ def enterabs(self, time, priority, action, argument=(), kwargs=_sentinel):
7168
"""
7269
if kwargs is _sentinel:
7370
kwargs = {}
74-
event = Event(time, priority, action, argument, kwargs)
71+
7572
with self._lock:
73+
event = Event(time, priority, next(self._sequence_generator),
74+
action, argument, kwargs)
7675
heapq.heappush(self._queue, event)
7776
return event # The ID
7877

@@ -136,7 +135,8 @@ def run(self, blocking=True):
136135
with lock:
137136
if not q:
138137
break
139-
time, priority, action, argument, kwargs = q[0]
138+
(time, priority, sequence, action,
139+
argument, kwargs) = q[0]
140140
now = timefunc()
141141
if time > now:
142142
delay = True

Lib/test/test_sched.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,17 @@ def test_cancel_concurrent(self):
142142
self.assertTrue(q.empty())
143143
self.assertEqual(timer.time(), 4)
144144

145+
def test_cancel_correct_event(self):
146+
# bpo-19270
147+
events = []
148+
scheduler = sched.scheduler()
149+
scheduler.enterabs(1, 1, events.append, ("a",))
150+
b = scheduler.enterabs(1, 1, events.append, ("b",))
151+
scheduler.enterabs(1, 1, events.append, ("c",))
152+
scheduler.cancel(b)
153+
scheduler.run()
154+
self.assertEqual(events, ["a", "c"])
155+
145156
def test_empty(self):
146157
l = []
147158
fun = lambda x: l.append(x)
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
:meth:`sched.scheduler.cancel()` will now cancel the correct event, if two
2+
events with same priority are scheduled for the same time. Patch by Bar Harel.

0 commit comments

Comments
 (0)