Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 745a407

Browse files
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
1 parent e7614dd commit 745a407

3 files changed

Lines changed: 66 additions & 8 deletions

File tree

Lib/tkinter/__init__.py

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,7 @@ def trace_variable(self, mode, callback):
271271
272272
Return the name of the callback.
273273
"""
274-
f = CallWrapper(callback, None, self).__call__
274+
f = CallWrapper(callback, None, self._root).__call__
275275
cbname = repr(id(f))
276276
try:
277277
callback = callback.__func__
@@ -295,14 +295,19 @@ def trace_vdelete(self, mode, cbname):
295295
CBNAME is the name of the callback returned from trace_variable or trace.
296296
"""
297297
self._tk.call("trace", "vdelete", self._name, mode, cbname)
298-
self._tk.deletecommand(cbname)
299-
try:
300-
self._tclCommands.remove(cbname)
301-
except ValueError:
302-
pass
298+
cbname = self._tk.splitlist(cbname)[0]
299+
for m, ca in self.trace_vinfo():
300+
if self._tk.splitlist(ca)[0] == cbname:
301+
break
302+
else:
303+
self._tk.deletecommand(cbname)
304+
try:
305+
self._tclCommands.remove(cbname)
306+
except ValueError:
307+
pass
303308
def trace_vinfo(self):
304309
"""Return all trace callback information."""
305-
return [self._tk.split(x) for x in self._tk.splitlist(
310+
return [self._tk.splitlist(x) for x in self._tk.splitlist(
306311
self._tk.call("trace", "vinfo", self._name))]
307312
def __eq__(self, other):
308313
"""Comparison for equality (==).

Lib/tkinter/test/test_tkinter/test_variables.py

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import unittest
2-
2+
import gc
33
from tkinter import (Variable, StringVar, IntVar, DoubleVar, BooleanVar, Tcl,
44
TclError)
55

@@ -87,6 +87,55 @@ def test_initialize(self):
8787
v.set("value")
8888
self.assertTrue(v.side_effect)
8989

90+
def test_trace(self):
91+
v = Variable(self.root)
92+
vname = str(v)
93+
trace = []
94+
def read_tracer(*args):
95+
trace.append(('read',) + args)
96+
def write_tracer(*args):
97+
trace.append(('write',) + args)
98+
cb1 = v.trace_variable('r', read_tracer)
99+
cb2 = v.trace_variable('wu', write_tracer)
100+
self.assertEqual(sorted(v.trace_vinfo()), [('r', cb1), ('wu', cb2)])
101+
self.assertEqual(trace, [])
102+
103+
v.set('spam')
104+
self.assertEqual(trace, [('write', vname, '', 'w')])
105+
106+
trace = []
107+
v.get()
108+
self.assertEqual(trace, [('read', vname, '', 'r')])
109+
110+
trace = []
111+
info = sorted(v.trace_vinfo())
112+
v.trace_vdelete('w', cb1) # Wrong mode
113+
self.assertEqual(sorted(v.trace_vinfo()), info)
114+
with self.assertRaises(TclError):
115+
v.trace_vdelete('r', 'spam') # Wrong command name
116+
self.assertEqual(sorted(v.trace_vinfo()), info)
117+
v.trace_vdelete('r', (cb1, 43)) # Wrong arguments
118+
self.assertEqual(sorted(v.trace_vinfo()), info)
119+
v.get()
120+
self.assertEqual(trace, [('read', vname, '', 'r')])
121+
122+
trace = []
123+
v.trace_vdelete('r', cb1)
124+
self.assertEqual(v.trace_vinfo(), [('wu', cb2)])
125+
v.get()
126+
self.assertEqual(trace, [])
127+
128+
trace = []
129+
del write_tracer
130+
gc.collect()
131+
v.set('eggs')
132+
self.assertEqual(trace, [('write', vname, '', 'w')])
133+
134+
trace = []
135+
del v
136+
gc.collect()
137+
self.assertEqual(trace, [('write', vname, '', 'u')])
138+
90139

91140
class TestStringVar(TestBase):
92141

Misc/NEWS

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ Core and Builtins
1313
Library
1414
-------
1515

16+
- Issue #22115: Fixed tracing Tkinter variables: trace_vdelete() with wrong
17+
mode no longer break tracing, trace_vinfo() now always returns a list of
18+
pairs of strings, tracing in the "u" mode now works.
19+
1620
- Fix a scoping issue in importlib.util.LazyLoader which triggered an
1721
UnboundLocalError when lazy-loading a module that was already put into
1822
sys.modules.

0 commit comments

Comments
 (0)