Skip to content

Commit c20318b

Browse files
authored
gh-155648: In IDLE tests, call unittest.main without exit arg (#156249)
* gh-155648: In IDLE tests, call unittest.main without exit arg DD bug 73: In idlelib.idle_test, test_xyz.py files should end with if __name__ == '__main__': unittest.main(verbosity=2) The default exit is True. This need not and should not be added. 5 files add the confusing equivalent exit=2 ("why the weird value?"), 4 files add exit=False. This is nonsensical when there is nothing more to run; main will immediately exit anyway. When running a test file from an IDLE editor, this argument has no visible effect. However, a Claude-based bug finder claims that in other circumstances (such as a program running the test in a shell), the good test may falsely fail. Even if this is not true, it can only confuse a reader. (The only place in idlelib for exit=False is in idlelib/abc.py files where the unittest is followed by an htest. The default exit=True exits the process, skipping the htest.) As part of editing the discussion of this in idle_test/htest.py, I clarified other things.
1 parent b062727 commit c20318b

11 files changed

Lines changed: 45 additions & 43 deletions

Lib/idlelib/idle_test/README.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,9 @@ insert the import and main lines before the htest lines.
3333

3434
if __name__ == "__main__":
3535
from unittest import main
36-
main('idlelib.idle_test.test_abc', verbosity=2, exit=False)
36+
main('idlelib.idle_test.test_abc', verbosity=2)
3737

38-
The ', exit=False' is only needed if an htest follows.
38+
Add ', exit=False' to the main call if and only if an htest follows.
3939

4040

4141

Lib/idlelib/idle_test/htest.py

Lines changed: 34 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,51 @@
11
"""Run human tests of Idle's window, dialog, and popup widgets.
22
3-
run(*tests) Create a master Tk() htest window. Within that, run each
4-
callable in tests after finding the matching test spec in this file. If
5-
tests is empty, run an htest for each spec dict in this file after
6-
finding the matching callable in the module named in the spec. Close
7-
the master window to end testing.
8-
9-
In a tested module, let X be a global name bound to a callable (class or
10-
function) whose .__name__ attribute is also X (the usual situation). The
11-
first parameter of X must be 'parent' or 'master'. When called, the
12-
first argument will be the root window. X must create a child
13-
Toplevel(parent/master) (or subclass thereof). The Toplevel may be a
14-
test widget or dialog, in which case the callable is the corresponding
15-
class. Or the Toplevel may contain the widget to be tested or set up a
16-
context in which a test widget is invoked. In this latter case, the
17-
callable is a wrapper function that sets up the Toplevel and other
18-
objects. Wrapper function names, such as _editor_window', should start
19-
with '_' and be lowercase.
20-
3+
The main function, `run(*tests)`, is defined at the end of this file.
4+
Argument `tests` is a possibly empty tuple of callables defined in some
5+
idlelib.abc module (or possibly modules). Its steps:
6+
1. Create a master Tk() htest window. Within that window ...
7+
2a. If tuple `tests` is not empty, run was likely called from one
8+
module. Run each callable in `tests` after finding the matching
9+
callable_spec test spec in this file.
10+
2b. If tests is empty, run was likely called from this file.
11+
Run an htest for each spec dict in this file after finding the
12+
matching callable in the module named in the spec.
13+
3. Close the master window to end testing.
14+
15+
In a tested module, let X be a global name bound to a callable (class
16+
or function) whose .__name__ attribute (its `class` or `def` definition
17+
name) is also X. X must expect exactly 1 positional argument, a
18+
parent toplevel window. Run passes the htest window. X must create a
19+
child Toplevel(parent/master). The callable may be either a runtime
20+
object or a wrapper function written just for the test. In the latter
21+
case, its name should start with '_' and be lowercase (such as '_ttt').
2122
2223
End the module with
23-
24+
```
2425
if __name__ == '__main__':
25-
<run unittest.main with 'exit=False'>
26+
from unittest import main
27+
main("idlelib.idle_test.test_xyz", verbosity=2, exit=False)
28+
2629
from idlelib.idle_test.htest import run
27-
run(callable) # There could be multiple comma-separated callables.
30+
run(callable)
31+
```
32+
Replace 'xyz' as appropriate and 'callable' with the callable name or
33+
comma-separated names (multiple names is rare). 'exit=False' is needed
34+
for the htest to run.
2835
2936
To have wrapper functions ignored by coverage reports, tag the def
30-
header like so: "def _wrapper(parent): # htest #". Use the same tag
31-
for htest lines in widget code. Make sure that the 'if __name__' line
32-
matches the above. Then have make sure that .coveragerc includes the
33-
following:
34-
37+
header like so: "def _wrapper(root): # htest #". Use the same tag
38+
for htest-only lines in the main code. To ignore the 'if __name__'
39+
statement, match the example above. Add the below to coveragerc.
40+
```
3541
[report]
3642
exclude_lines =
3743
.*# htest #
3844
if __name__ == .__main__.:
39-
40-
(The "." instead of "'" is intentional and necessary.)
41-
45+
```
4246
4347
To run any X, this file must contain a matching instance of the
4448
following template, with X.__name__ prepended to '_spec'.
45-
When all tests are run, the prefix is use to get X.
4649
4750
callable_spec = {
4851
'file': '',
@@ -51,11 +54,10 @@
5154
}
5255
5356
file (no .py): run() imports file.py.
54-
kwds: augmented with {'parent':root} and passed to X as **kwds.
57+
kwds: run() augments with {'parent':root} and passes to X as **kwds.
5558
title: an example kwd; some widgets need this, delete line if not.
5659
msg: master window hints about testing the widget.
5760
58-
5961
TODO test these modules and classes:
6062
autocomplete_w.AutoCompleteWindow
6163
debugger.Debugger

Lib/idlelib/idle_test/test_delegator.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,4 +41,4 @@ def test_mydel(self):
4141

4242

4343
if __name__ == '__main__':
44-
unittest.main(verbosity=2, exit=2)
44+
unittest.main(verbosity=2)

Lib/idlelib/idle_test/test_format.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -665,4 +665,4 @@ def test_rstrip_end(self):
665665

666666

667667
if __name__ == '__main__':
668-
unittest.main(verbosity=2, exit=2)
668+
unittest.main(verbosity=2)

Lib/idlelib/idle_test/test_history.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,4 +169,4 @@ def test_history_prev_next(self):
169169

170170

171171
if __name__ == '__main__':
172-
unittest.main(verbosity=2, exit=2)
172+
unittest.main(verbosity=2)

Lib/idlelib/idle_test/test_pathbrowser.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,4 +83,4 @@ def test_PathBrowserTreeItem(self):
8383

8484

8585
if __name__ == '__main__':
86-
unittest.main(verbosity=2, exit=False)
86+
unittest.main(verbosity=2)

Lib/idlelib/idle_test/test_query.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -448,4 +448,4 @@ def test_click_args(self):
448448

449449

450450
if __name__ == '__main__':
451-
unittest.main(verbosity=2, exit=False)
451+
unittest.main(verbosity=2)

Lib/idlelib/idle_test/test_search.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,4 +77,4 @@ def test_find_selection(self):
7777
text.delete('2.0', 'end')
7878

7979
if __name__ == '__main__':
80-
unittest.main(verbosity=2, exit=2)
80+
unittest.main(verbosity=2)

Lib/idlelib/idle_test/test_searchbase.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,4 +157,4 @@ def test_create_command_buttons(self):
157157

158158

159159
if __name__ == '__main__':
160-
unittest.main(verbosity=2, exit=2)
160+
unittest.main(verbosity=2)

Lib/idlelib/idle_test/test_text.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -233,4 +233,4 @@ def setUp(self):
233233

234234

235235
if __name__ == '__main__':
236-
unittest.main(verbosity=2, exit=False)
236+
unittest.main(verbosity=2)

0 commit comments

Comments
 (0)