]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
bpo-19270: Fixed sched.scheduler.cancel to cancel correct event (GH-22729)
authorBar Harel <bzvi7919@gmail.com>
Mon, 19 Oct 2020 07:33:43 +0000 (10:33 +0300)
committerGitHub <noreply@github.com>
Mon, 19 Oct 2020 07:33:43 +0000 (10:33 +0300)
Lib/sched.py
Lib/test/test_sched.py
Misc/NEWS.d/next/Library/2020-10-16-22-48-01.bpo-19270.jd_gkA.rst [new file with mode: 0644]

index ff87874a3a4b70cea3592d3ecf8235910491e14e..14613cf29874da539490accd7d83abce51499964 100644 (file)
@@ -26,23 +26,19 @@ has another way to reference private data (besides global variables).
 import time
 import heapq
 from collections import namedtuple
+from itertools import count
 import threading
 from time import monotonic as _time
 
 __all__ = ["scheduler"]
 
-class Event(namedtuple('Event', 'time, priority, 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 = namedtuple('Event', 'time, priority, sequence, action, argument, kwargs')
 Event.time.__doc__ = ('''Numeric type compatible with the return value of the
 timefunc function passed to the constructor.''')
 Event.priority.__doc__ = ('''Events scheduled for the same time will be executed
 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
 action(*argument, **kwargs)''')
 Event.argument.__doc__ = ('''argument is a sequence holding the positional
@@ -61,6 +57,7 @@ class scheduler:
         self._lock = threading.RLock()
         self.timefunc = timefunc
         self.delayfunc = delayfunc
+        self._sequence_generator = count()
 
     def enterabs(self, time, priority, action, argument=(), kwargs=_sentinel):
         """Enter a new event in the queue at an absolute time.
@@ -71,8 +68,10 @@ class scheduler:
         """
         if kwargs is _sentinel:
             kwargs = {}
-        event = Event(time, priority, action, argument, kwargs)
+
         with self._lock:
+            event = Event(time, priority, next(self._sequence_generator),
+                          action, argument, kwargs)
             heapq.heappush(self._queue, event)
         return event # The ID
 
@@ -136,7 +135,8 @@ class scheduler:
             with lock:
                 if not q:
                     break
-                time, priority, action, argument, kwargs = q[0]
+                (time, priority, sequence, action,
+                 argument, kwargs) = q[0]
                 now = timefunc()
                 if time > now:
                     delay = True
index 491d7b3a745b4d27b0155f1b3bf440ad8c962f0b..7ae7baae85e2c9ac02538950e30ed3ffe53020e8 100644 (file)
@@ -142,6 +142,17 @@ class TestCase(unittest.TestCase):
         self.assertTrue(q.empty())
         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):
         l = []
         fun = lambda x: l.append(x)
diff --git a/Misc/NEWS.d/next/Library/2020-10-16-22-48-01.bpo-19270.jd_gkA.rst b/Misc/NEWS.d/next/Library/2020-10-16-22-48-01.bpo-19270.jd_gkA.rst
new file mode 100644 (file)
index 0000000..6330a91
--- /dev/null
@@ -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.