[Python-checkins] cpython (3.5): Issue #22115: Fixed tracing Tkinter variables:

serhiy.storchaka python-checkins at python.org
Sun Jun 26 10:48:13 EDT 2016


https://hg.python.org/cpython/rev/293ec9547334
changeset:   102182:293ec9547334
branch:      3.5
parent:      102178:b76e23fb3c71
user:        Serhiy Storchaka <storchaka at gmail.com>
date:        Sun Jun 26 17:42:23 2016 +0300
summary:
  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

files:
  Lib/tkinter/__init__.py                         |  19 ++-
  Lib/tkinter/test/test_tkinter/test_variables.py |  51 +++++++++-
  Misc/NEWS                                       |   4 +
  3 files changed, 66 insertions(+), 8 deletions(-)


diff --git a/Lib/tkinter/__init__.py b/Lib/tkinter/__init__.py
--- a/Lib/tkinter/__init__.py
+++ b/Lib/tkinter/__init__.py
@@ -271,7 +271,7 @@
 
         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 @@
         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 (==).
diff --git a/Lib/tkinter/test/test_tkinter/test_variables.py b/Lib/tkinter/test/test_tkinter/test_variables.py
--- a/Lib/tkinter/test/test_tkinter/test_variables.py
+++ b/Lib/tkinter/test/test_tkinter/test_variables.py
@@ -1,5 +1,5 @@
 import unittest
-
+import gc
 from tkinter import (Variable, StringVar, IntVar, DoubleVar, BooleanVar, Tcl,
                      TclError)
 
@@ -87,6 +87,55 @@
         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):
 
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -13,6 +13,10 @@
 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.

-- 
Repository URL: https://hg.python.org/cpython


More information about the Python-checkins mailing list