Skip to content

Commit 46b3d9b

Browse files
committed
Issue #21940: add docstrings to idlelib.WidgetRedirector.
1 parent bf5d158 commit 46b3d9b

File tree

1 file changed

+60
-18
lines changed

1 file changed

+60
-18
lines changed

Lib/idlelib/WidgetRedirector.py

Lines changed: 60 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1-
from tkinter import *
1+
from tkinter import TclError
22

33
class WidgetRedirector:
4-
54
"""Support for redirecting arbitrary widget subcommands.
65
76
Some Tk operations don't normally pass through Tkinter. For example, if a
@@ -18,12 +17,22 @@ class WidgetRedirector:
1817
this command and provide a facility ('register') to intercept the widget
1918
operation.
2019
21-
In IDLE, the function being registered provides access to the top of a
22-
Percolator chain. At the bottom of the chain is a call to the original
23-
Tk widget operation.
24-
20+
In IDLE, WidgetRedirector is used in Percolator to intercept Text
21+
commands. The function being registered provides access to the top
22+
of a Percolator chain. At the bottom of the chain is a call to the
23+
original Tk widget operation.
2524
"""
2625
def __init__(self, widget):
26+
'''Initialize attributes and setup redirection.
27+
28+
_operations: dict mapping operation name to new function.
29+
widget: the widget whose tcl command is to be intercepted.
30+
tk: widget.tk, a convenience attribute, probably not needed.
31+
orig: new name of the original tcl command.
32+
33+
Since renaming to orig fails with TclError when orig already
34+
exists, only one WidgetDirector can exist for a given widget.
35+
'''
2736
self._operations = {}
2837
self.widget = widget # widget instance
2938
self.tk = tk = widget.tk # widget's root
@@ -40,22 +49,34 @@ def __repr__(self):
4049
self.widget._w)
4150

4251
def close(self):
52+
"Unregister operations and revert redirection created by .__init__."
4353
for operation in list(self._operations):
4454
self.unregister(operation)
45-
widget = self.widget; del self.widget
46-
orig = self.orig; del self.orig
55+
widget = self.widget
4756
tk = widget.tk
4857
w = widget._w
58+
# Restore the original widget Tcl command.
4959
tk.deletecommand(w)
50-
# restore the original widget Tcl command:
51-
tk.call("rename", orig, w)
60+
tk.call("rename", self.orig, w)
61+
del self.widget, self.tk # Should not be needed
62+
# if instance is deleted after close, as in Percolator.
5263

5364
def register(self, operation, function):
65+
'''Return OriginalCommand(operation) after registering function.
66+
67+
Registration adds an instance function attribute that masks the
68+
class instance method attribute. If a second function is
69+
registered for the same operation, the first function is replaced.
70+
'''
5471
self._operations[operation] = function
5572
setattr(self.widget, operation, function)
5673
return OriginalCommand(self, operation)
5774

5875
def unregister(self, operation):
76+
'''Return the function for the operation, or None.
77+
78+
Deleting the instance attribute unmasks the class attribute.
79+
'''
5980
if operation in self._operations:
6081
function = self._operations[operation]
6182
del self._operations[operation]
@@ -88,14 +109,29 @@ def dispatch(self, operation, *args):
88109

89110

90111
class OriginalCommand:
112+
'''Callable for original tk command that has been redirected.
113+
114+
Returned by .register; can be used in the function registered.
115+
redir = WidgetRedirector(text)
116+
def my_insert(*args):
117+
print("insert", args)
118+
original_insert(*args)
119+
original_insert = redir.register("insert", my_insert)
120+
'''
91121

92122
def __init__(self, redir, operation):
123+
'''Create .tk_call and .orig_and_operation for .__call__ method.
124+
125+
.redir and .operation store the input args for __repr__.
126+
.tk and .orig copy attributes of .redir (probably not needed).
127+
'''
93128
self.redir = redir
94129
self.operation = operation
95-
self.tk = redir.tk
96-
self.orig = redir.orig
97-
self.tk_call = self.tk.call
98-
self.orig_and_operation = (self.orig, self.operation)
130+
self.tk = redir.tk # redundant with self.redir
131+
self.orig = redir.orig # redundant with self.redir
132+
# These two could be deleted after checking recipient code.
133+
self.tk_call = redir.tk.call
134+
self.orig_and_operation = (redir.orig, operation)
99135

100136
def __repr__(self):
101137
return "OriginalCommand(%r, %r)" % (self.redir, self.operation)
@@ -104,7 +140,10 @@ def __call__(self, *args):
104140
return self.tk_call(self.orig_and_operation + args)
105141

106142

107-
def _widget_redirector(parent):
143+
def _widget_redirector(parent): # htest #
144+
from tkinter import Tk, Text
145+
import re
146+
108147
root = Tk()
109148
root.title("Test WidgetRedirector")
110149
width, height, x, y = list(map(int, re.split('[x+]', parent.geometry())))
@@ -113,13 +152,16 @@ def _widget_redirector(parent):
113152
text.pack()
114153
text.focus_set()
115154
redir = WidgetRedirector(text)
116-
global previous_tcl_fcn
117155
def my_insert(*args):
118156
print("insert", args)
119-
previous_tcl_fcn(*args)
120-
previous_tcl_fcn = redir.register("insert", my_insert)
157+
original_insert(*args)
158+
original_insert = redir.register("insert", my_insert)
121159
root.mainloop()
122160

123161
if __name__ == "__main__":
162+
import unittest
163+
## unittest.main('idlelib.idle_test.test_widgetredir',
164+
## verbosity=2, exit=False)
165+
124166
from idlelib.idle_test.htest import run
125167
run(_widget_redirector)

0 commit comments

Comments
 (0)