Issue #22115: Fixed tracing Tkinter variables:

* tracing in the "u" mode now works
* trace_vdelete() with wrong mode no longer break tracing
* trace_vinfo() now always returns a list of pairs of strings
This commit is contained in:
Serhiy Storchaka 2016-06-26 17:42:23 +03:00
parent e7614dd07d
commit 745a407df8
3 changed files with 66 additions and 8 deletions

View file

@ -271,7 +271,7 @@ def trace_variable(self, mode, callback):
Return the name of the callback.
"""
f = CallWrapper(callback, None, self).__call__
f = CallWrapper(callback, None, self._root).__call__
cbname = repr(id(f))
try:
callback = callback.__func__
@ -295,14 +295,19 @@ def trace_vdelete(self, mode, cbname):
CBNAME is the name of the callback returned from trace_variable or trace.
"""
self._tk.call("trace", "vdelete", self._name, mode, cbname)
self._tk.deletecommand(cbname)
try:
self._tclCommands.remove(cbname)
except ValueError:
pass
cbname = self._tk.splitlist(cbname)[0]
for m, ca in self.trace_vinfo():
if self._tk.splitlist(ca)[0] == cbname:
break
else:
self._tk.deletecommand(cbname)
try:
self._tclCommands.remove(cbname)
except ValueError:
pass
def trace_vinfo(self):
"""Return all trace callback information."""
return [self._tk.split(x) for x in self._tk.splitlist(
return [self._tk.splitlist(x) for x in self._tk.splitlist(
self._tk.call("trace", "vinfo", self._name))]
def __eq__(self, other):
"""Comparison for equality (==).

View file

@ -1,5 +1,5 @@
import unittest
import gc
from tkinter import (Variable, StringVar, IntVar, DoubleVar, BooleanVar, Tcl,
TclError)
@ -87,6 +87,55 @@ def test_initialize(self):
v.set("value")
self.assertTrue(v.side_effect)
def test_trace(self):
v = Variable(self.root)
vname = str(v)
trace = []
def read_tracer(*args):
trace.append(('read',) + args)
def write_tracer(*args):
trace.append(('write',) + args)
cb1 = v.trace_variable('r', read_tracer)
cb2 = v.trace_variable('wu', write_tracer)
self.assertEqual(sorted(v.trace_vinfo()), [('r', cb1), ('wu', cb2)])
self.assertEqual(trace, [])
v.set('spam')
self.assertEqual(trace, [('write', vname, '', 'w')])
trace = []
v.get()
self.assertEqual(trace, [('read', vname, '', 'r')])
trace = []
info = sorted(v.trace_vinfo())
v.trace_vdelete('w', cb1) # Wrong mode
self.assertEqual(sorted(v.trace_vinfo()), info)
with self.assertRaises(TclError):
v.trace_vdelete('r', 'spam') # Wrong command name
self.assertEqual(sorted(v.trace_vinfo()), info)
v.trace_vdelete('r', (cb1, 43)) # Wrong arguments
self.assertEqual(sorted(v.trace_vinfo()), info)
v.get()
self.assertEqual(trace, [('read', vname, '', 'r')])
trace = []
v.trace_vdelete('r', cb1)
self.assertEqual(v.trace_vinfo(), [('wu', cb2)])
v.get()
self.assertEqual(trace, [])
trace = []
del write_tracer
gc.collect()
v.set('eggs')
self.assertEqual(trace, [('write', vname, '', 'w')])
trace = []
del v
gc.collect()
self.assertEqual(trace, [('write', vname, '', 'u')])
class TestStringVar(TestBase):

View file

@ -13,6 +13,10 @@ Core and Builtins
Library
-------
- Issue #22115: Fixed tracing Tkinter variables: trace_vdelete() with wrong
mode no longer break tracing, trace_vinfo() now always returns a list of
pairs of strings, tracing in the "u" mode now works.
- Fix a scoping issue in importlib.util.LazyLoader which triggered an
UnboundLocalError when lazy-loading a module that was already put into
sys.modules.