Skip to content

Commit 6f31717

Browse files
authored
[3.6] bpo-30495: IDLE: improve textview with docstrings, PEP8 names, more tests. (GH-2283) (#2496)
Split TextViewer class into ViewWindow, ViewFrame, and TextFrame classes so that instances of the latter two can be placed with other widgets within a multiframe window. Patch by Cheryl Sabella. (cherry picked from commit 42bc8be)
1 parent 1d56ed5 commit 6f31717

File tree

6 files changed

+141
-100
lines changed

6 files changed

+141
-100
lines changed

‎Lib/idlelib/idle_test/htest.py‎

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
end the test.
99
1010
In a tested module, let X be a global name bound to a callable (class
11-
or function) whose .__name__ attrubute is also X (the usual situation).
11+
or function) whose .__name__ attribute is also X (the usual situation).
1212
The first parameter of X must be 'parent'. When called, the parent
1313
argument will be the root window. X must create a child Toplevel
1414
window (or subclass thereof). The Toplevel may be a test widget or
@@ -306,15 +306,6 @@ def _wrapper(parent): # htest #
306306
"<nothing> is an invalid add page and remove page name.\n"
307307
}
308308

309-
TextViewer_spec = {
310-
'file': 'textview',
311-
'kwds': {'title': 'Test textview',
312-
'text':'The quick brown fox jumps over the lazy dog.\n'*35,
313-
'_htest': True},
314-
'msg': "Test for read-only property of text.\n"
315-
"Text is selectable. Window is scrollable.",
316-
}
317-
318309
_tooltip_spec = {
319310
'file': 'tooltip',
320311
'kwds': {},
@@ -338,6 +329,15 @@ def _wrapper(parent): # htest #
338329
"by printing to the console or the IDLE shell.\n"
339330
}
340331

332+
ViewWindow_spec = {
333+
'file': 'textview',
334+
'kwds': {'title': 'Test textview',
335+
'text': 'The quick brown fox jumps over the lazy dog.\n'*35,
336+
'_htest': True},
337+
'msg': "Test for read-only property of text.\n"
338+
"Select text, scroll window, close"
339+
}
340+
341341
_widget_redirector_spec = {
342342
'file': 'redirector',
343343
'kwds': {},

‎Lib/idlelib/idle_test/test_help_about.py‎

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -50,19 +50,17 @@ def test_dialog_logo(self):
5050
def test_printer_buttons(self):
5151
"""Test buttons whose commands use printer function."""
5252
dialog = self.dialog
53-
button_sources = [(self.dialog.py_license, license),
54-
(self.dialog.py_copyright, copyright),
55-
(self.dialog.py_credits, credits)]
53+
button_sources = [(dialog.py_license, license),
54+
(dialog.py_copyright, copyright),
55+
(dialog.py_credits, credits)]
5656

5757
for button, printer in button_sources:
5858
printer._Printer__setup()
5959
button.invoke()
60+
get = dialog._current_textview.viewframe.textframe.text.get
61+
self.assertEqual(printer._Printer__lines[0], get('1.0', '1.end'))
6062
self.assertEqual(
61-
printer._Printer__lines[0],
62-
dialog._current_textview.text.get('1.0', '1.end'))
63-
self.assertEqual(
64-
printer._Printer__lines[1],
65-
dialog._current_textview.text.get('2.0', '2.end'))
63+
printer._Printer__lines[1], get('2.0', '2.end'))
6664
dialog._current_textview.destroy()
6765

6866
def test_file_buttons(self):
@@ -75,14 +73,11 @@ def test_file_buttons(self):
7573
for button, filename in button_sources:
7674
button.invoke()
7775
fn = findfile(filename, subdir='idlelib')
76+
get = dialog._current_textview.viewframe.textframe.text.get
7877
with open(fn) as f:
79-
self.assertEqual(
80-
f.readline().strip(),
81-
dialog._current_textview.text.get('1.0', '1.end'))
78+
self.assertEqual(f.readline().strip(), get('1.0', '1.end'))
8279
f.readline()
83-
self.assertEqual(
84-
f.readline().strip(),
85-
dialog._current_textview.text.get('3.0', '3.end'))
80+
self.assertEqual(f.readline().strip(), get('3.0', '3.end'))
8681
dialog._current_textview.destroy()
8782

8883

‎Lib/idlelib/idle_test/test_textview.py‎

Lines changed: 55 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
'''Test idlelib.textview.
22
3-
Since all methods and functions create (or destroy) a TextViewer, which
4-
is a widget containing multiple widgets, all tests must be gui tests.
3+
Since all methods and functions create (or destroy) a ViewWindow, which
4+
is a widget containing a widget, etcetera, all tests must be gui tests.
55
Using mock Text would not change this. Other mocks are used to retrieve
66
information about calls.
77
@@ -13,7 +13,8 @@
1313

1414
import unittest
1515
import os
16-
from tkinter import Tk, Button
16+
from tkinter import Tk
17+
from tkinter.ttk import Button
1718
from idlelib.idle_test.mock_idle import Func
1819
from idlelib.idle_test.mock_tk import Mbox_func
1920

@@ -25,52 +26,73 @@ def setUpModule():
2526
def tearDownModule():
2627
global root
2728
root.update_idletasks()
28-
root.destroy() # Pyflakes falsely sees root as undefined.
29+
root.destroy()
2930
del root
3031

31-
# If we call TextViewer or wrapper functions with defaults
32+
# If we call ViewWindow or wrapper functions with defaults
3233
# modal=True, _utest=False, test hangs on call to wait_window.
3334
# Have also gotten tk error 'can't invoke "event" command'.
3435

3536

36-
class TV(tv.TextViewer): # Used in TextViewTest.
37+
class VW(tv.ViewWindow): # Used in ViewWindowTest.
3738
transient = Func()
3839
grab_set = Func()
3940
wait_window = Func()
4041

4142

42-
# Call wrapper class with mock wait_window.
43-
class TextViewTest(unittest.TestCase):
43+
# Call wrapper class VW with mock wait_window.
44+
class ViewWindowTest(unittest.TestCase):
4445

4546
def setUp(self):
46-
TV.transient.__init__()
47-
TV.grab_set.__init__()
48-
TV.wait_window.__init__()
47+
VW.transient.__init__()
48+
VW.grab_set.__init__()
49+
VW.wait_window.__init__()
4950

5051
def test_init_modal(self):
51-
view = TV(root, 'Title', 'test text')
52-
self.assertTrue(TV.transient.called)
53-
self.assertTrue(TV.grab_set.called)
54-
self.assertTrue(TV.wait_window.called)
52+
view = VW(root, 'Title', 'test text')
53+
self.assertTrue(VW.transient.called)
54+
self.assertTrue(VW.grab_set.called)
55+
self.assertTrue(VW.wait_window.called)
5556
view.ok()
5657

5758
def test_init_nonmodal(self):
58-
view = TV(root, 'Title', 'test text', modal=False)
59-
self.assertFalse(TV.transient.called)
60-
self.assertFalse(TV.grab_set.called)
61-
self.assertFalse(TV.wait_window.called)
59+
view = VW(root, 'Title', 'test text', modal=False)
60+
self.assertFalse(VW.transient.called)
61+
self.assertFalse(VW.grab_set.called)
62+
self.assertFalse(VW.wait_window.called)
6263
view.ok()
6364

6465
def test_ok(self):
65-
view = TV(root, 'Title', 'test text', modal=False)
66+
view = VW(root, 'Title', 'test text', modal=False)
6667
view.destroy = Func()
6768
view.ok()
6869
self.assertTrue(view.destroy.called)
6970
del view.destroy # Unmask real function.
7071
view.destroy()
7172

7273

73-
# Call TextViewer with modal=False.
74+
class TextFrameTest(unittest.TestCase):
75+
76+
@classmethod
77+
def setUpClass(cls):
78+
"By itself, this tests that file parsed without exception."
79+
cls.root = root = Tk()
80+
root.withdraw()
81+
cls.frame = tv.TextFrame(root, 'test text')
82+
83+
@classmethod
84+
def tearDownClass(cls):
85+
del cls.frame
86+
cls.root.update_idletasks()
87+
cls.root.destroy()
88+
del cls.root
89+
90+
def test_line1(self):
91+
get = self.frame.text.get
92+
self.assertEqual(get('1.0', '1.end'), 'test text')
93+
94+
95+
# Call ViewWindow with modal=False.
7496
class ViewFunctionTest(unittest.TestCase):
7597

7698
@classmethod
@@ -85,13 +107,16 @@ def tearDownClass(cls):
85107

86108
def test_view_text(self):
87109
view = tv.view_text(root, 'Title', 'test text', modal=False)
88-
self.assertIsInstance(view, tv.TextViewer)
110+
self.assertIsInstance(view, tv.ViewWindow)
111+
self.assertIsInstance(view.viewframe, tv.ViewFrame)
89112
view.ok()
90113

91114
def test_view_file(self):
92115
view = tv.view_file(root, 'Title', __file__, modal=False)
93-
self.assertIsInstance(view, tv.TextViewer)
94-
self.assertIn('Test', view.text.get('1.0', '1.end'))
116+
self.assertIsInstance(view, tv.ViewWindow)
117+
self.assertIsInstance(view.viewframe, tv.ViewFrame)
118+
get = view.viewframe.textframe.text.get
119+
self.assertIn('Test', get('1.0', '1.end'))
95120
view.ok()
96121

97122
def test_bad_file(self):
@@ -109,8 +134,7 @@ def test_bad_encoding(self):
109134
self.assertEqual(tv.showerror.title, 'Unicode Decode Error')
110135

111136

112-
113-
# Call TextViewer with _utest=True.
137+
# Call ViewWindow with _utest=True.
114138
class ButtonClickTest(unittest.TestCase):
115139

116140
def setUp(self):
@@ -131,7 +155,8 @@ def _command():
131155

132156
self.assertEqual(self.called, True)
133157
self.assertEqual(self.view.title(), 'TITLE_TEXT')
134-
self.assertEqual(self.view.text.get('1.0', '1.end'), 'COMMAND')
158+
self.assertEqual(self.view.viewframe.textframe.text.get('1.0', '1.end'),
159+
'COMMAND')
135160

136161
def test_view_file_bind_with_button(self):
137162
def _command():
@@ -143,12 +168,11 @@ def _command():
143168

144169
self.assertEqual(self.called, True)
145170
self.assertEqual(self.view.title(), 'TITLE_FILE')
171+
get = self.view.viewframe.textframe.text.get
146172
with open(__file__) as f:
147-
self.assertEqual(self.view.text.get('1.0', '1.end'),
148-
f.readline().strip())
173+
self.assertEqual(get('1.0', '1.end'), f.readline().strip())
149174
f.readline()
150-
self.assertEqual(self.view.text.get('3.0', '3.end'),
151-
f.readline().strip())
175+
self.assertEqual(get('3.0', '3.end'), f.readline().strip())
152176

153177

154178
if __name__ == '__main__':

‎Lib/idlelib/pyshell.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -892,7 +892,7 @@ def __init__(self, flist=None):
892892
try:
893893
# page help() text to shell.
894894
import pydoc # import must be done here to capture i/o rebinding.
895-
# XXX KBK 27Dec07 use TextViewer someday, but must work w/o subproc
895+
# XXX KBK 27Dec07 use text viewer someday, but must work w/o subproc
896896
pydoc.pager = pydoc.plainpager
897897
except:
898898
sys.stderr = sys.__stderr__

0 commit comments

Comments
 (0)