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/lib-tk/Tkinter.py
Original file line number Diff line number Diff line change
Expand Up @@ -586,6 +586,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 @@ -609,11 +610,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
122 changes: 122 additions & 0 deletions Lib/lib-tk/test/test_tkinter/test_misc.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
import unittest
import Tkinter as tkinter
from test.test_support import requires, run_unittest
from test_ttk.support import AbstractTkTest

requires('gui')

class MiscTest(AbstractTkTest, unittest.TestCase):

def test_after(self):
root = self.root
cbcount = {'count': 0}

def callback(start=0, step=1):
cbcount['count'] = start + step

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

# Set up with callback with no args.
cbcount['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(cbcount['count'], 1)
with self.assertRaises(tkinter.TclError):
root.tk.call(script)

# Set up with callback with args.
cbcount['count'] = 0
timer1 = root.after(0, callback, 42, 11)
root.update() # Process all pending events.
self.assertEqual(cbcount['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(cbcount['count'], 53)
with self.assertRaises(tkinter.TclError):
root.tk.call(script)

def test_after_idle(self):
root = self.root
cbcount = {'count': 0}

def callback(start=0, step=1):
cbcount['count'] = start + step

# Set up with callback with no args.
cbcount['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(cbcount['count'], 1)
with self.assertRaises(tkinter.TclError):
root.tk.call(script)

# Set up with callback with args.
cbcount['count'] = 0
idle1 = root.after_idle(callback, 42, 11)
root.update_idletasks() # Process all pending events.
self.assertEqual(cbcount['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(cbcount['count'], 53)
with self.assertRaises(tkinter.TclError):
root.tk.call(script)

def test_after_cancel(self):
root = self.root
cbcount = {'count': 0}

def callback():
cbcount['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.
cbcount['count'] = 0
(script, _) = root.tk.splitlist(root.tk.call('after', 'info', timer1))
root.tk.call(script)
self.assertEqual(cbcount['count'], 1)
root.after_cancel(timer1)
with self.assertRaises(tkinter.TclError):
root.tk.call(script)
self.assertEqual(cbcount['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.
cbcount['count'] = 0
(script, _) = root.tk.splitlist(root.tk.call('after', 'info', idle1))
root.tk.call(script)
self.assertEqual(cbcount['count'], 1)
root.after_cancel(idle1)
with self.assertRaises(tkinter.TclError):
root.tk.call(script)
self.assertEqual(cbcount['count'], 1)
with self.assertRaises(tkinter.TclError):
root.tk.call('after', 'info', idle1)


tests_gui = (MiscTest, )

if __name__ == "__main__":
run_unittest(*tests_gui)
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.