Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions Lib/tkinter/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -739,6 +739,7 @@ def after(self, ms, func=None, *args):
if not func:
# I'd rather use time.sleep(ms*0.001)
self.tk.call('after', ms)
return None
else:
def callit():
try:
Expand All @@ -762,11 +763,13 @@ def after_cancel(self, id):
"""Cancel scheduling of function identified with ID.

Identifier returned by after or after_idle must be
given as first parameter."""
given as first parameter.
"""
if not id:
raise ValueError('id must be a valid identifier returned from '
'after or after_idle')
try:
data = self.tk.call('after', 'info', id)
# In Tk 8.3, splitlist returns: (script, type)
# In Tk 8.4, splitlist may return (script, type) or (script,)
script = self.tk.splitlist(data)[0]
self.deletecommand(script)
except TclError:
Expand Down
108 changes: 108 additions & 0 deletions Lib/tkinter/test/test_tkinter/test_misc.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,114 @@ def test_tk_setPalette(self):
'^must specify a background color$',
root.tk_setPalette, highlightColor='blue')

def test_after(self):
root = self.root

def callback(start=0, step=1):
nonlocal count
count = start + step

# Without function, sleeps for ms.
self.assertIsNone(root.after(1))

# Set up with callback with no args.
count = 0
timer1 = root.after(0, callback)
self.assertIn(timer1, root.tk.call('after', 'info'))
(script, _) = root.tk.splitlist(root.tk.call('after', 'info', timer1))
root.update() # Process all pending events.
self.assertEqual(count, 1)
with self.assertRaises(tkinter.TclError):
root.tk.call(script)

# Set up with callback with args.
count = 0
timer1 = root.after(0, callback, 42, 11)
root.update() # Process all pending events.
self.assertEqual(count, 53)

# Cancel before called.
timer1 = root.after(1000, callback)
self.assertIn(timer1, root.tk.call('after', 'info'))
(script, _) = root.tk.splitlist(root.tk.call('after', 'info', timer1))
root.after_cancel(timer1) # Cancel this event.
self.assertEqual(count, 53)
with self.assertRaises(tkinter.TclError):
root.tk.call(script)

def test_after_idle(self):
root = self.root

def callback(start=0, step=1):
nonlocal count
count = start + step

# Set up with callback with no args.
count = 0
idle1 = root.after_idle(callback)
self.assertIn(idle1, root.tk.call('after', 'info'))
(script, _) = root.tk.splitlist(root.tk.call('after', 'info', idle1))
root.update_idletasks() # Process all pending events.
self.assertEqual(count, 1)
with self.assertRaises(tkinter.TclError):
root.tk.call(script)

# Set up with callback with args.
count = 0
idle1 = root.after_idle(callback, 42, 11)
root.update_idletasks() # Process all pending events.
self.assertEqual(count, 53)

# Cancel before called.
idle1 = root.after_idle(callback)
self.assertIn(idle1, root.tk.call('after', 'info'))
(script, _) = root.tk.splitlist(root.tk.call('after', 'info', idle1))
root.after_cancel(idle1) # Cancel this event.
self.assertEqual(count, 53)
with self.assertRaises(tkinter.TclError):
root.tk.call(script)

def test_after_cancel(self):
root = self.root

def callback():
nonlocal count
count += 1

timer1 = root.after(5000, callback)
idle1 = root.after_idle(callback)

# No value for id raises a ValueError.
with self.assertRaises(ValueError):
root.after_cancel(None)

# Cancel timer event.
count = 0
(script, _) = root.tk.splitlist(root.tk.call('after', 'info', timer1))
root.tk.call(script)
self.assertEqual(count, 1)
root.after_cancel(timer1)
with self.assertRaises(tkinter.TclError):
root.tk.call(script)
self.assertEqual(count, 1)
with self.assertRaises(tkinter.TclError):
root.tk.call('after', 'info', timer1)

# Cancel same event - nothing happens.
root.after_cancel(timer1)

# Cancel idle event.
count = 0
(script, _) = root.tk.splitlist(root.tk.call('after', 'info', idle1))
root.tk.call(script)
self.assertEqual(count, 1)
root.after_cancel(idle1)
with self.assertRaises(tkinter.TclError):
root.tk.call(script)
self.assertEqual(count, 1)
with self.assertRaises(tkinter.TclError):
root.tk.call('after', 'info', idle1)


tests_gui = (MiscTest, )

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
In :mod:`tkinter`, ``after_cancel(None)`` now raises a :exc:`ValueError` instead of canceling the first scheduled function. Patch by Cheryl Sabella.