Skip to content

Commit a92bfa4

Browse files
committed
Merge with 3.3
2 parents 912bad7 + 95a3f11 commit a92bfa4

3 files changed

Lines changed: 162 additions & 49 deletions

File tree

Lib/idlelib/PyShell.py

Lines changed: 53 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -45,35 +45,55 @@
4545
# internal warnings to the console. ScriptBinding.check_syntax() will
4646
# temporarily redirect the stream to the shell window to display warnings when
4747
# checking user's code.
48-
global warning_stream
49-
warning_stream = sys.__stderr__
50-
try:
51-
import warnings
52-
except ImportError:
53-
pass
54-
else:
55-
def idle_showwarning(message, category, filename, lineno,
56-
file=None, line=None):
57-
if file is None:
58-
file = warning_stream
59-
try:
60-
file.write(warnings.formatwarning(message, category, filename,
61-
lineno, line=line))
62-
except OSError:
63-
pass ## file (probably __stderr__) is invalid, warning dropped.
64-
warnings.showwarning = idle_showwarning
65-
def idle_formatwarning(message, category, filename, lineno, line=None):
66-
"""Format warnings the IDLE way"""
67-
s = "\nWarning (from warnings module):\n"
68-
s += ' File \"%s\", line %s\n' % (filename, lineno)
69-
if line is None:
70-
line = linecache.getline(filename, lineno)
71-
line = line.strip()
72-
if line:
73-
s += " %s\n" % line
74-
s += "%s: %s\n>>> " % (category.__name__, message)
75-
return s
76-
warnings.formatwarning = idle_formatwarning
48+
warning_stream = sys.__stderr__ # None, at least on Windows, if no console.
49+
import warnings
50+
51+
def idle_formatwarning(message, category, filename, lineno, line=None):
52+
"""Format warnings the IDLE way."""
53+
54+
s = "\nWarning (from warnings module):\n"
55+
s += ' File \"%s\", line %s\n' % (filename, lineno)
56+
if line is None:
57+
line = linecache.getline(filename, lineno)
58+
line = line.strip()
59+
if line:
60+
s += " %s\n" % line
61+
s += "%s: %s\n" % (category.__name__, message)
62+
return s
63+
64+
def idle_showwarning(
65+
message, category, filename, lineno, file=None, line=None):
66+
"""Show Idle-format warning (after replacing warnings.showwarning).
67+
68+
The differences are the formatter called, the file=None replacement,
69+
which can be None, the capture of the consequence AttributeError,
70+
and the output of a hard-coded prompt.
71+
"""
72+
if file is None:
73+
file = warning_stream
74+
try:
75+
file.write(idle_formatwarning(
76+
message, category, filename, lineno, line=line))
77+
file.write(">>> ")
78+
except (AttributeError, OSError):
79+
pass # if file (probably __stderr__) is invalid, skip warning.
80+
81+
_warnings_showwarning = None
82+
83+
def capture_warnings(capture):
84+
"Replace warning.showwarning with idle_showwarning, or reverse."
85+
86+
global _warnings_showwarning
87+
if capture:
88+
if _warnings_showwarning is None:
89+
_warnings_showwarning = warnings.showwarning
90+
warnings.showwarning = idle_showwarning
91+
else:
92+
if _warnings_showwarning is not None:
93+
warnings.showwarning = _warnings_showwarning
94+
_warnings_showwarning = None
95+
96+
capture_warnings(True)
7797

7898
def extended_linecache_checkcache(filename=None,
7999
orig_checkcache=linecache.checkcache):
@@ -1425,6 +1445,7 @@ def close(self):
14251445
def main():
14261446
global flist, root, use_subprocess
14271447

1448+
capture_warnings(True)
14281449
use_subprocess = True
14291450
enable_shell = False
14301451
enable_edit = False
@@ -1559,7 +1580,10 @@ def main():
15591580
while flist.inversedict: # keep IDLE running while files are open.
15601581
root.mainloop()
15611582
root.destroy()
1583+
capture_warnings(False)
15621584

15631585
if __name__ == "__main__":
15641586
sys.modules['PyShell'] = sys.modules['__main__']
15651587
main()
1588+
1589+
capture_warnings(False) # Make sure turned off; see issue 18081
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
'''Test warnings replacement in PyShell.py and run.py.
2+
3+
This file could be expanded to include traceback overrides
4+
(in same two modules). If so, change name.
5+
Revise if output destination changes (http://bugs.python.org/issue18318).
6+
Make sure warnings module is left unaltered (http://bugs.python.org/issue18081).
7+
'''
8+
9+
import unittest
10+
from test.support import captured_stderr
11+
12+
import warnings
13+
# Try to capture default showwarning before Idle modules are imported.
14+
showwarning = warnings.showwarning
15+
# But if we run this file within idle, we are in the middle of the run.main loop
16+
# and default showwarnings has already been replaced.
17+
running_in_idle = 'idle' in showwarning.__name__
18+
19+
from idlelib import run
20+
from idlelib import PyShell as shell
21+
22+
# The following was generated from PyShell.idle_formatwarning
23+
# and checked as matching expectation.
24+
idlemsg = '''
25+
Warning (from warnings module):
26+
File "test_warning.py", line 99
27+
Line of code
28+
UserWarning: Test
29+
'''
30+
shellmsg = idlemsg + ">>> "
31+
32+
class RunWarnTest(unittest.TestCase):
33+
34+
@unittest.skipIf(running_in_idle, "Does not work when run within Idle.")
35+
def test_showwarnings(self):
36+
self.assertIs(warnings.showwarning, showwarning)
37+
run.capture_warnings(True)
38+
self.assertIs(warnings.showwarning, run.idle_showwarning_subproc)
39+
run.capture_warnings(False)
40+
self.assertIs(warnings.showwarning, showwarning)
41+
42+
def test_run_show(self):
43+
with captured_stderr() as f:
44+
run.idle_showwarning_subproc(
45+
'Test', UserWarning, 'test_warning.py', 99, f, 'Line of code')
46+
# The following uses .splitlines to erase line-ending differences
47+
self.assertEqual(idlemsg.splitlines(), f.getvalue().splitlines())
48+
49+
class ShellWarnTest(unittest.TestCase):
50+
51+
@unittest.skipIf(running_in_idle, "Does not work when run within Idle.")
52+
def test_showwarnings(self):
53+
self.assertIs(warnings.showwarning, showwarning)
54+
shell.capture_warnings(True)
55+
self.assertIs(warnings.showwarning, shell.idle_showwarning)
56+
shell.capture_warnings(False)
57+
self.assertIs(warnings.showwarning, showwarning)
58+
59+
def test_idle_formatter(self):
60+
# Will fail if format changed without regenerating idlemsg
61+
s = shell.idle_formatwarning(
62+
'Test', UserWarning, 'test_warning.py', 99, 'Line of code')
63+
self.assertEqual(idlemsg, s)
64+
65+
def test_shell_show(self):
66+
with captured_stderr() as f:
67+
shell.idle_showwarning(
68+
'Test', UserWarning, 'test_warning.py', 99, f, 'Line of code')
69+
self.assertEqual(shellmsg.splitlines(), f.getvalue().splitlines())
70+
71+
72+
if __name__ == '__main__':
73+
unittest.main(verbosity=2, exit=False)

Lib/idlelib/run.py

Lines changed: 36 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -23,36 +23,46 @@
2323

2424
LOCALHOST = '127.0.0.1'
2525

26-
try:
27-
import warnings
28-
except ImportError:
29-
pass
30-
else:
31-
def idle_formatwarning_subproc(message, category, filename, lineno,
32-
line=None):
33-
"""Format warnings the IDLE way"""
34-
s = "\nWarning (from warnings module):\n"
35-
s += ' File \"%s\", line %s\n' % (filename, lineno)
36-
if line is None:
37-
line = linecache.getline(filename, lineno)
38-
line = line.strip()
39-
if line:
40-
s += " %s\n" % line
41-
s += "%s: %s\n" % (category.__name__, message)
42-
return s
43-
warnings.formatwarning = idle_formatwarning_subproc
26+
import warnings
4427

28+
def idle_showwarning_subproc(
29+
message, category, filename, lineno, file=None, line=None):
30+
"""Show Idle-format warning after replacing warnings.showwarning.
4531
46-
tcl = tkinter.Tcl()
32+
The only difference is the formatter called.
33+
"""
34+
if file is None:
35+
file = sys.stderr
36+
try:
37+
file.write(PyShell.idle_formatwarning(
38+
message, category, filename, lineno, line))
39+
except IOError:
40+
pass # the file (probably stderr) is invalid - this warning gets lost.
4741

42+
_warnings_showwarning = None
43+
44+
def capture_warnings(capture):
45+
"Replace warning.showwarning with idle_showwarning_subproc, or reverse."
46+
47+
global _warnings_showwarning
48+
if capture:
49+
if _warnings_showwarning is None:
50+
_warnings_showwarning = warnings.showwarning
51+
warnings.showwarning = idle_showwarning_subproc
52+
else:
53+
if _warnings_showwarning is not None:
54+
warnings.showwarning = _warnings_showwarning
55+
_warnings_showwarning = None
56+
57+
capture_warnings(True)
58+
tcl = tkinter.Tcl()
4859

4960
def handle_tk_events(tcl=tcl):
5061
"""Process any tk events that are ready to be dispatched if tkinter
5162
has been imported, a tcl interpreter has been created and tk has been
5263
loaded."""
5364
tcl.eval("update")
5465

55-
5666
# Thread shared globals: Establish a queue between a subthread (which handles
5767
# the socket) and the main thread (which runs user code), plus global
5868
# completion, exit and interruptable (the main thread) flags:
@@ -91,6 +101,8 @@ def main(del_exitfunc=False):
91101
print("IDLE Subprocess: no IP port passed in sys.argv.",
92102
file=sys.__stderr__)
93103
return
104+
105+
capture_warnings(True)
94106
sys.argv[:] = [""]
95107
sockthread = threading.Thread(target=manage_socket,
96108
name='SockThread',
@@ -118,6 +130,7 @@ def main(del_exitfunc=False):
118130
exit_now = True
119131
continue
120132
except SystemExit:
133+
capture_warnings(False)
121134
raise
122135
except:
123136
type, value, tb = sys.exc_info()
@@ -247,6 +260,7 @@ def exit():
247260
if no_exitfunc:
248261
import atexit
249262
atexit._clear()
263+
capture_warnings(False)
250264
sys.exit(0)
251265

252266
class MyRPCServer(rpc.RPCServer):
@@ -386,3 +400,5 @@ def stackviewer(self, flist_oid=None):
386400
sys.last_value = val
387401
item = StackViewer.StackTreeItem(flist, tb)
388402
return RemoteObjectBrowser.remote_object_tree_item(item)
403+
404+
capture_warnings(False) # Make sure turned off; see issue 18081

0 commit comments

Comments
 (0)