blob: e8890d1746e19f7c20fd37cd611190545c5428c1 [file] [log] [blame]
Benjamin Peterson90f5ba52010-03-11 22:53:45 +00001#! /usr/bin/env python3
David Scherer7aced172000-08-15 01:13:23 +00002
Victor Stinner979482a2011-09-02 01:00:40 +02003import getopt
David Scherer7aced172000-08-15 01:13:23 +00004import os
Kurt B. Kaiser6e44cc22002-11-30 06:18:00 +00005import os.path
David Scherer7aced172000-08-15 01:13:23 +00006import re
Chui Tey5d2af632002-05-26 13:36:41 +00007import socket
Victor Stinner979482a2011-09-02 01:00:40 +02008import subprocess
9import sys
Kurt B. Kaiser003091c2003-02-17 18:57:16 +000010import threading
Victor Stinner979482a2011-09-02 01:00:40 +020011import time
12import tokenize
Chui Tey5d2af632002-05-26 13:36:41 +000013import traceback
Kurt B. Kaiser62833982002-09-18 17:07:05 +000014import types
Martin v. Löwisc882b7c2012-07-25 10:47:20 +020015import io
David Scherer7aced172000-08-15 01:13:23 +000016
17import linecache
18from code import InteractiveInterpreter
Terry Jan Reedya7c07d32014-02-08 09:02:26 -050019from platform import python_version, system
David Scherer7aced172000-08-15 01:13:23 +000020
Kurt B. Kaiser2303b1c2003-11-24 05:26:16 +000021try:
Georg Brandl14fc4272008-05-17 18:39:55 +000022 from tkinter import *
Kurt B. Kaiser2303b1c2003-11-24 05:26:16 +000023except ImportError:
Guido van Rossumbe19ed72007-02-09 05:37:30 +000024 print("** IDLE can't import Tkinter. " \
Kurt B. Kaiser2d7f6a02007-08-22 23:01:33 +000025 "Your Python may not be configured for Tk. **", file=sys.__stderr__)
Kurt B. Kaiser2303b1c2003-11-24 05:26:16 +000026 sys.exit(1)
Georg Brandl14fc4272008-05-17 18:39:55 +000027import tkinter.messagebox as tkMessageBox
David Scherer7aced172000-08-15 01:13:23 +000028
Kurt B. Kaiser2d7f6a02007-08-22 23:01:33 +000029from idlelib.EditorWindow import EditorWindow, fixwordbreaks
30from idlelib.FileList import FileList
31from idlelib.ColorDelegator import ColorDelegator
32from idlelib.UndoDelegator import UndoDelegator
33from idlelib.OutputWindow import OutputWindow
34from idlelib.configHandler import idleConf
35from idlelib import idlever
36from idlelib import rpc
37from idlelib import Debugger
38from idlelib import RemoteDebugger
39from idlelib import macosxSupport
Chui Tey5d2af632002-05-26 13:36:41 +000040
Kurt B. Kaisere866c812009-04-04 21:07:39 +000041HOST = '127.0.0.1' # python execution server on localhost loopback
42PORT = 0 # someday pass in host, port for remote debug capability
Kurt B. Kaiserb9764192002-09-23 04:10:37 +000043
Kurt B. Kaiser49a5fe12004-07-04 01:25:56 +000044# Override warnings module to write to warning_stream. Initialize to send IDLE
45# internal warnings to the console. ScriptBinding.check_syntax() will
46# temporarily redirect the stream to the shell window to display warnings when
47# checking user's code.
Terry Jan Reedy95a3f112013-06-28 23:50:12 -040048warning_stream = sys.__stderr__ # None, at least on Windows, if no console.
49import warnings
50
51def 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
64def 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
83def 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
96capture_warnings(True)
Chui Tey5d2af632002-05-26 13:36:41 +000097
Kurt B. Kaiserf7a88992004-11-13 21:05:58 +000098def extended_linecache_checkcache(filename=None,
99 orig_checkcache=linecache.checkcache):
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000100 """Extend linecache.checkcache to preserve the <pyshell#...> entries
101
Kurt B. Kaiserf7a88992004-11-13 21:05:58 +0000102 Rather than repeating the linecache code, patch it to save the
103 <pyshell#...> entries, call the original linecache.checkcache()
Guilherme Polo1fff0082009-08-14 15:05:30 +0000104 (skipping them), and then restore the saved entries.
Kurt B. Kaiserf7a88992004-11-13 21:05:58 +0000105
106 orig_checkcache is bound at definition time to the original
107 method, allowing it to be patched.
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000108 """
David Scherer7aced172000-08-15 01:13:23 +0000109 cache = linecache.cache
110 save = {}
Guilherme Polo1fff0082009-08-14 15:05:30 +0000111 for key in list(cache):
112 if key[:1] + key[-1:] == '<>':
113 save[key] = cache.pop(key)
114 orig_checkcache(filename)
David Scherer7aced172000-08-15 01:13:23 +0000115 cache.update(save)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000116
Kurt B. Kaiser81885592002-11-29 22:10:53 +0000117# Patch linecache.checkcache():
118linecache.checkcache = extended_linecache_checkcache
David Scherer7aced172000-08-15 01:13:23 +0000119
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000120
David Scherer7aced172000-08-15 01:13:23 +0000121class PyShellEditorWindow(EditorWindow):
Kurt B. Kaiser183403a2004-08-22 05:14:32 +0000122 "Regular text edit window in IDLE, supports breakpoints"
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000123
David Scherer7aced172000-08-15 01:13:23 +0000124 def __init__(self, *args):
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000125 self.breakpoints = []
Raymond Hettinger931237e2003-07-09 18:48:24 +0000126 EditorWindow.__init__(self, *args)
David Scherer7aced172000-08-15 01:13:23 +0000127 self.text.bind("<<set-breakpoint-here>>", self.set_breakpoint_here)
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000128 self.text.bind("<<clear-breakpoint-here>>", self.clear_breakpoint_here)
David Scherer7aced172000-08-15 01:13:23 +0000129 self.text.bind("<<open-python-shell>>", self.flist.open_shell)
130
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000131 self.breakpointPath = os.path.join(idleConf.GetUserCfgDir(),
132 'breakpoints.lst')
Chui Teya2adb0f2002-11-04 22:14:54 +0000133 # whenever a file is changed, restore breakpoints
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000134 def filename_changed_hook(old_hook=self.io.filename_change_hook,
135 self=self):
Chui Teya2adb0f2002-11-04 22:14:54 +0000136 self.restore_file_breaks()
137 old_hook()
138 self.io.set_filename_change_hook(filename_changed_hook)
Roger Serwyd7c9d9c2013-04-02 22:37:12 -0500139 if self.io.filename:
140 self.restore_file_breaks()
Chui Teya2adb0f2002-11-04 22:14:54 +0000141
Andrew Svetlovd1837672012-11-01 22:41:19 +0200142 rmenu_specs = [
143 ("Cut", "<<cut>>", "rmenu_check_cut"),
144 ("Copy", "<<copy>>", "rmenu_check_copy"),
145 ("Paste", "<<paste>>", "rmenu_check_paste"),
146 (None, None, None),
147 ("Set Breakpoint", "<<set-breakpoint-here>>", None),
148 ("Clear Breakpoint", "<<clear-breakpoint-here>>", None)
149 ]
David Scherer7aced172000-08-15 01:13:23 +0000150
Chui Teya2adb0f2002-11-04 22:14:54 +0000151 def set_breakpoint(self, lineno):
152 text = self.text
153 filename = self.io.filename
154 text.tag_add("BREAK", "%d.0" % lineno, "%d.0" % (lineno+1))
155 try:
156 i = self.breakpoints.index(lineno)
157 except ValueError: # only add if missing, i.e. do once
158 self.breakpoints.append(lineno)
159 try: # update the subprocess debugger
160 debug = self.flist.pyshell.interp.debugger
161 debug.set_breakpoint_here(filename, lineno)
162 except: # but debugger may not be active right now....
163 pass
164
David Scherer7aced172000-08-15 01:13:23 +0000165 def set_breakpoint_here(self, event=None):
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000166 text = self.text
167 filename = self.io.filename
168 if not filename:
169 text.bell()
David Scherer7aced172000-08-15 01:13:23 +0000170 return
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000171 lineno = int(float(text.index("insert")))
Chui Teya2adb0f2002-11-04 22:14:54 +0000172 self.set_breakpoint(lineno)
David Scherer7aced172000-08-15 01:13:23 +0000173
Kurt B. Kaiser669f4c32002-06-20 04:01:47 +0000174 def clear_breakpoint_here(self, event=None):
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000175 text = self.text
176 filename = self.io.filename
177 if not filename:
178 text.bell()
Kurt B. Kaiser669f4c32002-06-20 04:01:47 +0000179 return
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000180 lineno = int(float(text.index("insert")))
181 try:
182 self.breakpoints.remove(lineno)
183 except:
184 pass
185 text.tag_remove("BREAK", "insert linestart",\
186 "insert lineend +1char")
187 try:
188 debug = self.flist.pyshell.interp.debugger
189 debug.clear_breakpoint_here(filename, lineno)
190 except:
191 pass
192
193 def clear_file_breaks(self):
194 if self.breakpoints:
195 text = self.text
196 filename = self.io.filename
197 if not filename:
198 text.bell()
199 return
200 self.breakpoints = []
201 text.tag_remove("BREAK", "1.0", END)
202 try:
203 debug = self.flist.pyshell.interp.debugger
204 debug.clear_file_breaks(filename)
205 except:
206 pass
207
Chui Teya2adb0f2002-11-04 22:14:54 +0000208 def store_file_breaks(self):
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000209 "Save breakpoints when file is saved"
210 # XXX 13 Dec 2002 KBK Currently the file must be saved before it can
211 # be run. The breaks are saved at that time. If we introduce
212 # a temporary file save feature the save breaks functionality
213 # needs to be re-verified, since the breaks at the time the
214 # temp file is created may differ from the breaks at the last
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000215 # permanent save of the file. Currently, a break introduced
216 # after a save will be effective, but not persistent.
217 # This is necessary to keep the saved breaks synched with the
218 # saved file.
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000219 #
220 # Breakpoints are set as tagged ranges in the text. Certain
221 # kinds of edits cause these ranges to be deleted: Inserting
222 # or deleting a line just before a breakpoint, and certain
223 # deletions prior to a breakpoint. These issues need to be
224 # investigated and understood. It's not clear if they are
225 # Tk issues or IDLE issues, or whether they can actually
226 # be fixed. Since a modified file has to be saved before it is
227 # run, and since self.breakpoints (from which the subprocess
228 # debugger is loaded) is updated during the save, the visible
229 # breaks stay synched with the subprocess even if one of these
230 # unexpected breakpoint deletions occurs.
231 breaks = self.breakpoints
232 filename = self.io.filename
Chui Teya2adb0f2002-11-04 22:14:54 +0000233 try:
Victor Stinner85c67722011-09-02 00:57:04 +0200234 with open(self.breakpointPath, "r") as fp:
235 lines = fp.readlines()
Andrew Svetlovf7a17b42012-12-25 16:47:37 +0200236 except OSError:
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000237 lines = []
Ned Deilyf505b742011-12-14 14:58:24 -0800238 try:
239 with open(self.breakpointPath, "w") as new_file:
240 for line in lines:
241 if not line.startswith(filename + '='):
242 new_file.write(line)
243 self.update_breakpoints()
244 breaks = self.breakpoints
245 if breaks:
246 new_file.write(filename + '=' + str(breaks) + '\n')
Andrew Svetlovf7a17b42012-12-25 16:47:37 +0200247 except OSError as err:
Ned Deilyf505b742011-12-14 14:58:24 -0800248 if not getattr(self.root, "breakpoint_error_displayed", False):
249 self.root.breakpoint_error_displayed = True
250 tkMessageBox.showerror(title='IDLE Error',
251 message='Unable to update breakpoint list:\n%s'
252 % str(err),
253 parent=self.text)
Chui Teya2adb0f2002-11-04 22:14:54 +0000254
255 def restore_file_breaks(self):
256 self.text.update() # this enables setting "BREAK" tags to be visible
Roger Serwyd7c9d9c2013-04-02 22:37:12 -0500257 if self.io is None:
258 # can happen if IDLE closes due to the .update() call
259 return
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000260 filename = self.io.filename
261 if filename is None:
262 return
Chui Tey69371d62002-11-04 23:39:45 +0000263 if os.path.isfile(self.breakpointPath):
Victor Stinner85c67722011-09-02 00:57:04 +0200264 with open(self.breakpointPath, "r") as fp:
265 lines = fp.readlines()
Chui Tey69371d62002-11-04 23:39:45 +0000266 for line in lines:
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000267 if line.startswith(filename + '='):
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000268 breakpoint_linenumbers = eval(line[len(filename)+1:])
Chui Tey69371d62002-11-04 23:39:45 +0000269 for breakpoint_linenumber in breakpoint_linenumbers:
270 self.set_breakpoint(breakpoint_linenumber)
Chui Teya2adb0f2002-11-04 22:14:54 +0000271
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000272 def update_breakpoints(self):
273 "Retrieves all the breakpoints in the current window"
Chui Teya2adb0f2002-11-04 22:14:54 +0000274 text = self.text
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000275 ranges = text.tag_ranges("BREAK")
276 linenumber_list = self.ranges_to_linenumbers(ranges)
277 self.breakpoints = linenumber_list
278
279 def ranges_to_linenumbers(self, ranges):
280 lines = []
281 for index in range(0, len(ranges), 2):
Andrew Svetlov06c5c6d2012-07-31 19:48:00 +0300282 lineno = int(float(ranges[index].string))
283 end = int(float(ranges[index+1].string))
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000284 while lineno < end:
285 lines.append(lineno)
286 lineno += 1
287 return lines
288
Kurt B. Kaiser11220fa2002-12-24 00:57:22 +0000289# XXX 13 Dec 2002 KBK Not used currently
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000290# def saved_change_hook(self):
291# "Extend base method - clear breaks if module is modified"
292# if not self.get_saved():
293# self.clear_file_breaks()
294# EditorWindow.saved_change_hook(self)
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000295
296 def _close(self):
297 "Extend base method - clear breaks when module is closed"
298 self.clear_file_breaks()
299 EditorWindow._close(self)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000300
David Scherer7aced172000-08-15 01:13:23 +0000301
302class PyShellFileList(FileList):
Kurt B. Kaiser183403a2004-08-22 05:14:32 +0000303 "Extend base class: IDLE supports a shell and breakpoints"
David Scherer7aced172000-08-15 01:13:23 +0000304
Kurt B. Kaiser183403a2004-08-22 05:14:32 +0000305 # override FileList's class variable, instances return PyShellEditorWindow
306 # instead of EditorWindow when new edit windows are created.
David Scherer7aced172000-08-15 01:13:23 +0000307 EditorWindow = PyShellEditorWindow
308
309 pyshell = None
310
311 def open_shell(self, event=None):
312 if self.pyshell:
Kurt B. Kaiser183403a2004-08-22 05:14:32 +0000313 self.pyshell.top.wakeup()
David Scherer7aced172000-08-15 01:13:23 +0000314 else:
315 self.pyshell = PyShell(self)
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000316 if self.pyshell:
317 if not self.pyshell.begin():
318 return None
David Scherer7aced172000-08-15 01:13:23 +0000319 return self.pyshell
320
321
322class ModifiedColorDelegator(ColorDelegator):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000323 "Extend base class: colorizer for the shell window itself"
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000324
Steven M. Gavab77d3432002-03-02 07:16:21 +0000325 def __init__(self):
326 ColorDelegator.__init__(self)
327 self.LoadTagDefs()
David Scherer7aced172000-08-15 01:13:23 +0000328
329 def recolorize_main(self):
330 self.tag_remove("TODO", "1.0", "iomark")
331 self.tag_add("SYNC", "1.0", "iomark")
332 ColorDelegator.recolorize_main(self)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000333
Steven M. Gavab77d3432002-03-02 07:16:21 +0000334 def LoadTagDefs(self):
335 ColorDelegator.LoadTagDefs(self)
336 theme = idleConf.GetOption('main','Theme','name')
337 self.tagdefs.update({
338 "stdin": {'background':None,'foreground':None},
339 "stdout": idleConf.GetHighlight(theme, "stdout"),
340 "stderr": idleConf.GetHighlight(theme, "stderr"),
341 "console": idleConf.GetHighlight(theme, "console"),
Steven M. Gavab77d3432002-03-02 07:16:21 +0000342 })
David Scherer7aced172000-08-15 01:13:23 +0000343
Ned Deily8b2a56b2012-05-31 09:17:29 -0700344 def removecolors(self):
345 # Don't remove shell color tags before "iomark"
346 for tag in self.tagdefs:
347 self.tag_remove(tag, "iomark", "end")
348
David Scherer7aced172000-08-15 01:13:23 +0000349class ModifiedUndoDelegator(UndoDelegator):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000350 "Extend base class: forbid insert/delete before the I/O mark"
David Scherer7aced172000-08-15 01:13:23 +0000351
352 def insert(self, index, chars, tags=None):
353 try:
354 if self.delegate.compare(index, "<", "iomark"):
355 self.delegate.bell()
356 return
357 except TclError:
358 pass
359 UndoDelegator.insert(self, index, chars, tags)
360
361 def delete(self, index1, index2=None):
362 try:
363 if self.delegate.compare(index1, "<", "iomark"):
364 self.delegate.bell()
365 return
366 except TclError:
367 pass
368 UndoDelegator.delete(self, index1, index2)
369
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000370
371class MyRPCClient(rpc.RPCClient):
372
373 def handle_EOF(self):
374 "Override the base class - just re-raise EOFError"
375 raise EOFError
376
Kurt B. Kaiser8d1f11b2003-05-26 22:20:34 +0000377
David Scherer7aced172000-08-15 01:13:23 +0000378class ModifiedInterpreter(InteractiveInterpreter):
379
380 def __init__(self, tkconsole):
381 self.tkconsole = tkconsole
382 locals = sys.modules['__main__'].__dict__
383 InteractiveInterpreter.__init__(self, locals=locals)
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000384 self.save_warnings_filters = None
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000385 self.restarting = False
Kurt B. Kaisere866c812009-04-04 21:07:39 +0000386 self.subprocess_arglist = None
387 self.port = PORT
Ned Deily7aff4512011-10-30 20:01:35 -0700388 self.original_compiler_flags = self.compile.compiler.flags
David Scherer7aced172000-08-15 01:13:23 +0000389
Roger Serwy036e8492013-06-11 22:13:17 -0500390 _afterid = None
Chui Tey5d2af632002-05-26 13:36:41 +0000391 rpcclt = None
Ned Deilye5cad232011-08-02 18:47:13 -0700392 rpcsubproc = None
Chui Tey5d2af632002-05-26 13:36:41 +0000393
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000394 def spawn_subprocess(self):
Florent Xiclunafd1b0932010-03-28 00:25:02 +0000395 if self.subprocess_arglist is None:
Kurt B. Kaisere866c812009-04-04 21:07:39 +0000396 self.subprocess_arglist = self.build_subprocess_arglist()
Ned Deilye5cad232011-08-02 18:47:13 -0700397 self.rpcsubproc = subprocess.Popen(self.subprocess_arglist)
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000398
Tony Lowndsf53dec22002-12-20 04:24:43 +0000399 def build_subprocess_arglist(self):
Kurt B. Kaisere866c812009-04-04 21:07:39 +0000400 assert (self.port!=0), (
401 "Socket should have been assigned a port number.")
Tony Lownds2398d572003-05-13 15:28:21 +0000402 w = ['-W' + s for s in sys.warnoptions]
403 # Maybe IDLE is installed and is being accessed via sys.path,
404 # or maybe it's not installed and the idle.py script is being
405 # run from the IDLE source directory.
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000406 del_exitf = idleConf.GetOption('main', 'General', 'delete-exitfunc',
407 default=False, type='bool')
Tony Lownds2398d572003-05-13 15:28:21 +0000408 if __name__ == 'idlelib.PyShell':
Walter Dörwald70a6b492004-02-12 17:35:32 +0000409 command = "__import__('idlelib.run').run.main(%r)" % (del_exitf,)
Tony Lowndsf2324b92002-09-29 00:34:10 +0000410 else:
Walter Dörwald70a6b492004-02-12 17:35:32 +0000411 command = "__import__('run').main(%r)" % (del_exitf,)
Ned Deilye5cad232011-08-02 18:47:13 -0700412 return [sys.executable] + w + ["-c", command, str(self.port)]
Tony Lowndsf2324b92002-09-29 00:34:10 +0000413
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000414 def start_subprocess(self):
Kurt B. Kaisere866c812009-04-04 21:07:39 +0000415 addr = (HOST, self.port)
416 # GUI makes several attempts to acquire socket, listens for connection
Kurt B. Kaiser5db48432003-05-15 03:40:51 +0000417 for i in range(3):
Chui Tey5d2af632002-05-26 13:36:41 +0000418 time.sleep(i)
419 try:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000420 self.rpcclt = MyRPCClient(addr)
Chui Tey5d2af632002-05-26 13:36:41 +0000421 break
Andrew Svetlov0832af62012-12-18 23:10:48 +0200422 except OSError as err:
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000423 pass
Chui Tey5d2af632002-05-26 13:36:41 +0000424 else:
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000425 self.display_port_binding_error()
426 return None
Kurt B. Kaisere866c812009-04-04 21:07:39 +0000427 # if PORT was 0, system will assign an 'ephemeral' port. Find it out:
428 self.port = self.rpcclt.listening_sock.getsockname()[1]
429 # if PORT was not 0, probably working with a remote execution server
430 if PORT != 0:
431 # To allow reconnection within the 2MSL wait (cf. Stevens TCP
432 # V1, 18.6), set SO_REUSEADDR. Note that this can be problematic
433 # on Windows since the implementation allows two active sockets on
434 # the same address!
435 self.rpcclt.listening_sock.setsockopt(socket.SOL_SOCKET,
436 socket.SO_REUSEADDR, 1)
437 self.spawn_subprocess()
438 #time.sleep(20) # test to simulate GUI not accepting connection
Kurt B. Kaiserb4179362002-07-26 00:06:42 +0000439 # Accept the connection from the Python execution server
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000440 self.rpcclt.listening_sock.settimeout(10)
441 try:
442 self.rpcclt.accept()
Guido van Rossumb940e112007-01-10 16:19:56 +0000443 except socket.timeout as err:
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000444 self.display_no_subprocess_error()
445 return None
Serhiy Storchaka39e70a42013-01-25 15:30:58 +0200446 self.rpcclt.register("console", self.tkconsole)
447 self.rpcclt.register("stdin", self.tkconsole.stdin)
Kurt B. Kaiser969de452002-06-12 03:28:57 +0000448 self.rpcclt.register("stdout", self.tkconsole.stdout)
449 self.rpcclt.register("stderr", self.tkconsole.stderr)
Chui Tey5d2af632002-05-26 13:36:41 +0000450 self.rpcclt.register("flist", self.tkconsole.flist)
Kurt B. Kaiser8cd0def2003-01-31 05:06:43 +0000451 self.rpcclt.register("linecache", linecache)
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000452 self.rpcclt.register("interp", self)
Terry Jan Reedyda4c4672012-01-31 02:26:32 -0500453 self.transfer_path(with_cwd=True)
Chui Tey5d2af632002-05-26 13:36:41 +0000454 self.poll_subprocess()
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000455 return self.rpcclt
Chui Tey5d2af632002-05-26 13:36:41 +0000456
Terry Jan Reedyda4c4672012-01-31 02:26:32 -0500457 def restart_subprocess(self, with_cwd=False):
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000458 if self.restarting:
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000459 return self.rpcclt
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000460 self.restarting = True
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000461 # close only the subprocess debugger
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000462 debug = self.getdebugger()
463 if debug:
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000464 try:
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000465 # Only close subprocess debugger, don't unregister gui_adap!
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000466 RemoteDebugger.close_subprocess_debugger(self.rpcclt)
467 except:
468 pass
469 # Kill subprocess, spawn a new one, accept connection.
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000470 self.rpcclt.close()
Ned Deilye5cad232011-08-02 18:47:13 -0700471 self.terminate_subprocess()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000472 console = self.tkconsole
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000473 was_executing = console.executing
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000474 console.executing = False
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000475 self.spawn_subprocess()
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000476 try:
477 self.rpcclt.accept()
Guido van Rossumb940e112007-01-10 16:19:56 +0000478 except socket.timeout as err:
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000479 self.display_no_subprocess_error()
480 return None
Terry Jan Reedyda4c4672012-01-31 02:26:32 -0500481 self.transfer_path(with_cwd=with_cwd)
Roger Serwy6b7a5ae2013-04-03 00:42:24 -0500482 console.stop_readline()
Kurt B. Kaiser1061e722003-01-04 01:43:53 +0000483 # annotate restart in shell window and mark it
Kurt B. Kaiser4cc5ef52003-01-22 00:23:23 +0000484 console.text.delete("iomark", "end-1c")
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000485 if was_executing:
486 console.write('\n')
487 console.showprompt()
Kurt B. Kaiser1061e722003-01-04 01:43:53 +0000488 halfbar = ((int(console.width) - 16) // 2) * '='
489 console.write(halfbar + ' RESTART ' + halfbar)
490 console.text.mark_set("restart", "end-1c")
491 console.text.mark_gravity("restart", "left")
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000492 console.showprompt()
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000493 # restart subprocess debugger
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000494 if debug:
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000495 # Restarted debugger connects to current instance of debug GUI
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000496 gui = RemoteDebugger.restart_subprocess_debugger(self.rpcclt)
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000497 # reload remote debugger breakpoints for all PyShellEditWindows
498 debug.load_breakpoints()
Ned Deily7aff4512011-10-30 20:01:35 -0700499 self.compile.compiler.flags = self.original_compiler_flags
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000500 self.restarting = False
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000501 return self.rpcclt
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000502
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000503 def __request_interrupt(self):
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000504 self.rpcclt.remotecall("exec", "interrupt_the_server", (), {})
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000505
506 def interrupt_subprocess(self):
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000507 threading.Thread(target=self.__request_interrupt).start()
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000508
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000509 def kill_subprocess(self):
Roger Serwy036e8492013-06-11 22:13:17 -0500510 if self._afterid is not None:
511 self.tkconsole.text.after_cancel(self._afterid)
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000512 try:
Ned Deily55f87572011-11-05 22:36:44 -0700513 self.rpcclt.listening_sock.close()
514 except AttributeError: # no socket
515 pass
516 try:
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000517 self.rpcclt.close()
518 except AttributeError: # no socket
519 pass
Ned Deilye5cad232011-08-02 18:47:13 -0700520 self.terminate_subprocess()
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000521 self.tkconsole.executing = False
522 self.rpcclt = None
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000523
Ned Deilye5cad232011-08-02 18:47:13 -0700524 def terminate_subprocess(self):
525 "Make sure subprocess is terminated"
526 try:
527 self.rpcsubproc.kill()
528 except OSError:
529 # process already terminated
530 return
531 else:
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000532 try:
Ned Deilye5cad232011-08-02 18:47:13 -0700533 self.rpcsubproc.wait()
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000534 except OSError:
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000535 return
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000536
Terry Jan Reedyda4c4672012-01-31 02:26:32 -0500537 def transfer_path(self, with_cwd=False):
538 if with_cwd: # Issue 13506
539 path = [''] # include Current Working Directory
540 path.extend(sys.path)
541 else:
542 path = sys.path
Terry Jan Reedy4d82ade2012-01-31 02:57:29 -0500543
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000544 self.runcommand("""if 1:
545 import sys as _sys
Walter Dörwald70a6b492004-02-12 17:35:32 +0000546 _sys.path = %r
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000547 del _sys
Terry Jan Reedyda4c4672012-01-31 02:26:32 -0500548 \n""" % (path,))
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000549
Chui Tey5d2af632002-05-26 13:36:41 +0000550 active_seq = None
551
552 def poll_subprocess(self):
553 clt = self.rpcclt
554 if clt is None:
555 return
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000556 try:
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000557 response = clt.pollresponse(self.active_seq, wait=0.05)
Andrew Svetlovf7a17b42012-12-25 16:47:37 +0200558 except (EOFError, OSError, KeyboardInterrupt):
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000559 # lost connection or subprocess terminated itself, restart
560 # [the KBI is from rpc.SocketIO.handle_EOF()]
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000561 if self.tkconsole.closing:
562 return
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000563 response = None
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000564 self.restart_subprocess()
Chui Tey5d2af632002-05-26 13:36:41 +0000565 if response:
566 self.tkconsole.resetoutput()
567 self.active_seq = None
568 how, what = response
Kurt B. Kaiserbc286132003-01-25 21:33:40 +0000569 console = self.tkconsole.console
Chui Tey5d2af632002-05-26 13:36:41 +0000570 if how == "OK":
571 if what is not None:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000572 print(repr(what), file=console)
Chui Tey5d2af632002-05-26 13:36:41 +0000573 elif how == "EXCEPTION":
Chui Tey5d2af632002-05-26 13:36:41 +0000574 if self.tkconsole.getvar("<<toggle-jit-stack-viewer>>"):
575 self.remote_stack_viewer()
576 elif how == "ERROR":
Kurt B. Kaiser0930c432002-12-06 21:45:24 +0000577 errmsg = "PyShell.ModifiedInterpreter: Subprocess ERROR:\n"
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000578 print(errmsg, what, file=sys.__stderr__)
579 print(errmsg, what, file=console)
Kurt B. Kaiserbc286132003-01-25 21:33:40 +0000580 # we received a response to the currently active seq number:
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000581 try:
582 self.tkconsole.endexecuting()
583 except AttributeError: # shell may have closed
584 pass
Kurt B. Kaiser88957d82003-05-19 23:11:51 +0000585 # Reschedule myself
586 if not self.tkconsole.closing:
Roger Serwy036e8492013-06-11 22:13:17 -0500587 self._afterid = self.tkconsole.text.after(
588 self.tkconsole.pollinterval, self.poll_subprocess)
Chui Tey5d2af632002-05-26 13:36:41 +0000589
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000590 debugger = None
591
592 def setdebugger(self, debugger):
593 self.debugger = debugger
594
595 def getdebugger(self):
596 return self.debugger
597
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000598 def open_remote_stack_viewer(self):
599 """Initiate the remote stack viewer from a separate thread.
600
601 This method is called from the subprocess, and by returning from this
602 method we allow the subprocess to unblock. After a bit the shell
603 requests the subprocess to open the remote stack viewer which returns a
Ezio Melotti60861182010-07-23 16:48:22 +0000604 static object looking at the last exception. It is queried through
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000605 the RPC mechanism.
606
607 """
608 self.tkconsole.text.after(300, self.remote_stack_viewer)
609 return
610
Chui Tey5d2af632002-05-26 13:36:41 +0000611 def remote_stack_viewer(self):
Kurt B. Kaiser2d7f6a02007-08-22 23:01:33 +0000612 from idlelib import RemoteObjectBrowser
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000613 oid = self.rpcclt.remotequeue("exec", "stackviewer", ("flist",), {})
Chui Tey5d2af632002-05-26 13:36:41 +0000614 if oid is None:
615 self.tkconsole.root.bell()
616 return
617 item = RemoteObjectBrowser.StubObjectTreeItem(self.rpcclt, oid)
Kurt B. Kaiser2d7f6a02007-08-22 23:01:33 +0000618 from idlelib.TreeWidget import ScrolledCanvas, TreeNode
Chui Tey5d2af632002-05-26 13:36:41 +0000619 top = Toplevel(self.tkconsole.root)
Kurt B. Kaiser73360a32004-03-08 18:15:31 +0000620 theme = idleConf.GetOption('main','Theme','name')
621 background = idleConf.GetHighlight(theme, 'normal')['background']
622 sc = ScrolledCanvas(top, bg=background, highlightthickness=0)
Chui Tey5d2af632002-05-26 13:36:41 +0000623 sc.frame.pack(expand=1, fill="both")
624 node = TreeNode(sc.canvas, None, item)
625 node.expand()
626 # XXX Should GC the remote tree when closing the window
627
David Scherer7aced172000-08-15 01:13:23 +0000628 gid = 0
629
630 def execsource(self, source):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000631 "Like runsource() but assumes complete exec source"
David Scherer7aced172000-08-15 01:13:23 +0000632 filename = self.stuffsource(source)
633 self.execfile(filename, source)
634
635 def execfile(self, filename, source=None):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000636 "Execute an existing file"
David Scherer7aced172000-08-15 01:13:23 +0000637 if source is None:
Victor Stinner979482a2011-09-02 01:00:40 +0200638 with tokenize.open(filename) as fp:
Victor Stinner85c67722011-09-02 00:57:04 +0200639 source = fp.read()
David Scherer7aced172000-08-15 01:13:23 +0000640 try:
641 code = compile(source, filename, "exec")
642 except (OverflowError, SyntaxError):
643 self.tkconsole.resetoutput()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000644 tkerr = self.tkconsole.stderr
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000645 print('*** Error in script or command!\n', file=tkerr)
646 print('Traceback (most recent call last):', file=tkerr)
David Scherer7aced172000-08-15 01:13:23 +0000647 InteractiveInterpreter.showsyntaxerror(self, filename)
Kurt B. Kaiser6e44cc22002-11-30 06:18:00 +0000648 self.tkconsole.showprompt()
David Scherer7aced172000-08-15 01:13:23 +0000649 else:
650 self.runcode(code)
651
652 def runsource(self, source):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000653 "Extend base class method: Stuff the source in the line cache first"
David Scherer7aced172000-08-15 01:13:23 +0000654 filename = self.stuffsource(source)
655 self.more = 0
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000656 self.save_warnings_filters = warnings.filters[:]
657 warnings.filterwarnings(action="error", category=SyntaxWarning)
Martin v. Löwis98ff8982007-08-13 06:03:15 +0000658 # at the moment, InteractiveInterpreter expects str
659 assert isinstance(source, str)
660 #if isinstance(source, str):
Kurt B. Kaiser2d7f6a02007-08-22 23:01:33 +0000661 # from idlelib import IOBinding
Martin v. Löwis98ff8982007-08-13 06:03:15 +0000662 # try:
663 # source = source.encode(IOBinding.encoding)
664 # except UnicodeError:
665 # self.tkconsole.resetoutput()
666 # self.write("Unsupported characters in input\n")
667 # return
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000668 try:
Kurt B. Kaiser935ea9a2005-05-10 03:44:24 +0000669 # InteractiveInterpreter.runsource() calls its runcode() method,
670 # which is overridden (see below)
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000671 return InteractiveInterpreter.runsource(self, source, filename)
672 finally:
673 if self.save_warnings_filters is not None:
674 warnings.filters[:] = self.save_warnings_filters
675 self.save_warnings_filters = None
David Scherer7aced172000-08-15 01:13:23 +0000676
677 def stuffsource(self, source):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000678 "Stuff source in the filename cache"
David Scherer7aced172000-08-15 01:13:23 +0000679 filename = "<pyshell#%d>" % self.gid
680 self.gid = self.gid + 1
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +0000681 lines = source.split("\n")
David Scherer7aced172000-08-15 01:13:23 +0000682 linecache.cache[filename] = len(source)+1, 0, lines, filename
683 return filename
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000684
Kurt B. Kaiser11659ad2003-05-15 23:23:21 +0000685 def prepend_syspath(self, filename):
686 "Prepend sys.path with file's directory if not already included"
687 self.runcommand("""if 1:
Walter Dörwald70a6b492004-02-12 17:35:32 +0000688 _filename = %r
Kurt B. Kaiser11659ad2003-05-15 23:23:21 +0000689 import sys as _sys
690 from os.path import dirname as _dirname
691 _dir = _dirname(_filename)
692 if not _dir in _sys.path:
693 _sys.path.insert(0, _dir)
694 del _filename, _sys, _dirname, _dir
Walter Dörwald70a6b492004-02-12 17:35:32 +0000695 \n""" % (filename,))
Kurt B. Kaiser11659ad2003-05-15 23:23:21 +0000696
David Scherer7aced172000-08-15 01:13:23 +0000697 def showsyntaxerror(self, filename=None):
Guido van Rossum33d26892007-08-05 15:29:28 +0000698 """Override Interactive Interpreter method: Use Colorizing
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000699
700 Color the offending position instead of printing it and pointing at it
701 with a caret.
702
703 """
Guido van Rossum33d26892007-08-05 15:29:28 +0000704 tkconsole = self.tkconsole
705 text = tkconsole.text
706 text.tag_remove("ERROR", "1.0", "end")
David Scherer7aced172000-08-15 01:13:23 +0000707 type, value, tb = sys.exc_info()
Ned Deily79746422011-09-14 14:49:14 -0700708 msg = getattr(value, 'msg', '') or value or "<no detail available>"
709 lineno = getattr(value, 'lineno', '') or 1
710 offset = getattr(value, 'offset', '') or 0
Guido van Rossum33d26892007-08-05 15:29:28 +0000711 if offset == 0:
712 lineno += 1 #mark end of offending line
713 if lineno == 1:
714 pos = "iomark + %d chars" % (offset-1)
David Scherer7aced172000-08-15 01:13:23 +0000715 else:
Guido van Rossum33d26892007-08-05 15:29:28 +0000716 pos = "iomark linestart + %d lines + %d chars" % \
717 (lineno-1, offset-1)
718 tkconsole.colorize_syntax_error(text, pos)
719 tkconsole.resetoutput()
720 self.write("SyntaxError: %s\n" % msg)
721 tkconsole.showprompt()
David Scherer7aced172000-08-15 01:13:23 +0000722
723 def showtraceback(self):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000724 "Extend base class method to reset output properly"
David Scherer7aced172000-08-15 01:13:23 +0000725 self.tkconsole.resetoutput()
726 self.checklinecache()
727 InteractiveInterpreter.showtraceback(self)
Chui Tey5d2af632002-05-26 13:36:41 +0000728 if self.tkconsole.getvar("<<toggle-jit-stack-viewer>>"):
729 self.tkconsole.open_stack_viewer()
David Scherer7aced172000-08-15 01:13:23 +0000730
731 def checklinecache(self):
732 c = linecache.cache
Guido van Rossum36e0a922007-07-20 04:05:57 +0000733 for key in list(c.keys()):
David Scherer7aced172000-08-15 01:13:23 +0000734 if key[:1] + key[-1:] != "<>":
735 del c[key]
736
Chui Tey5d2af632002-05-26 13:36:41 +0000737 def runcommand(self, code):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000738 "Run the code without invoking the debugger"
Chui Tey5d2af632002-05-26 13:36:41 +0000739 # The code better not raise an exception!
740 if self.tkconsole.executing:
Neal Norwitzf4c4f112002-11-30 18:49:10 +0000741 self.display_executing_dialog()
Chui Tey5d2af632002-05-26 13:36:41 +0000742 return 0
743 if self.rpcclt:
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000744 self.rpcclt.remotequeue("exec", "runcode", (code,), {})
Chui Tey5d2af632002-05-26 13:36:41 +0000745 else:
Georg Brandl7cae87c2006-09-06 06:51:57 +0000746 exec(code, self.locals)
Chui Tey5d2af632002-05-26 13:36:41 +0000747 return 1
748
David Scherer7aced172000-08-15 01:13:23 +0000749 def runcode(self, code):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000750 "Override base class method"
Chui Tey5d2af632002-05-26 13:36:41 +0000751 if self.tkconsole.executing:
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000752 self.interp.restart_subprocess()
Chui Tey5d2af632002-05-26 13:36:41 +0000753 self.checklinecache()
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000754 if self.save_warnings_filters is not None:
755 warnings.filters[:] = self.save_warnings_filters
756 self.save_warnings_filters = None
David Scherer7aced172000-08-15 01:13:23 +0000757 debugger = self.debugger
758 try:
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000759 self.tkconsole.beginexecuting()
Thomas Wouterscf297e42007-02-23 15:07:44 +0000760 if not debugger and self.rpcclt is not None:
761 self.active_seq = self.rpcclt.asyncqueue("exec", "runcode",
762 (code,), {})
763 elif debugger:
764 debugger.run(code, self.locals)
765 else:
766 exec(code, self.locals)
767 except SystemExit:
768 if not self.tkconsole.closing:
769 if tkMessageBox.askyesno(
770 "Exit?",
771 "Do you want to exit altogether?",
772 default="yes",
773 master=self.tkconsole.text):
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000774 raise
Thomas Wouterscf297e42007-02-23 15:07:44 +0000775 else:
Guido van Rossum5dc0d972007-02-25 22:37:36 +0000776 self.showtraceback()
Thomas Wouterscf297e42007-02-23 15:07:44 +0000777 else:
778 raise
779 except:
780 if use_subprocess:
781 print("IDLE internal error in runcode()",
782 file=self.tkconsole.stderr)
David Scherer7aced172000-08-15 01:13:23 +0000783 self.showtraceback()
Thomas Wouterscf297e42007-02-23 15:07:44 +0000784 self.tkconsole.endexecuting()
785 else:
786 if self.tkconsole.canceled:
787 self.tkconsole.canceled = False
788 print("KeyboardInterrupt", file=self.tkconsole.stderr)
789 else:
790 self.showtraceback()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000791 finally:
792 if not use_subprocess:
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000793 try:
794 self.tkconsole.endexecuting()
795 except AttributeError: # shell may have closed
796 pass
David Scherer7aced172000-08-15 01:13:23 +0000797
798 def write(self, s):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000799 "Override base class method"
Martin v. Löwis30d5e6c2012-07-25 11:32:26 +0200800 return self.tkconsole.stderr.write(s)
David Scherer7aced172000-08-15 01:13:23 +0000801
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000802 def display_port_binding_error(self):
803 tkMessageBox.showerror(
804 "Port Binding Error",
Kurt B. Kaisere866c812009-04-04 21:07:39 +0000805 "IDLE can't bind to a TCP/IP port, which is necessary to "
806 "communicate with its Python execution server. This might be "
807 "because no networking is installed on this computer. "
808 "Run IDLE with the -n command line switch to start without a "
809 "subprocess and refer to Help/IDLE Help 'Running without a "
810 "subprocess' for further details.",
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000811 master=self.tkconsole.text)
812
813 def display_no_subprocess_error(self):
814 tkMessageBox.showerror(
815 "Subprocess Startup Error",
816 "IDLE's subprocess didn't make connection. Either IDLE can't "
817 "start a subprocess or personal firewall software is blocking "
818 "the connection.",
819 master=self.tkconsole.text)
820
821 def display_executing_dialog(self):
822 tkMessageBox.showerror(
823 "Already executing",
824 "The Python Shell window is already executing a command; "
825 "please wait until it is finished.",
826 master=self.tkconsole.text)
827
828
David Scherer7aced172000-08-15 01:13:23 +0000829class PyShell(OutputWindow):
830
Terry Jan Reedy32622232013-03-30 18:32:19 -0400831 shell_title = "Python " + python_version() + " Shell"
David Scherer7aced172000-08-15 01:13:23 +0000832
833 # Override classes
834 ColorDelegator = ModifiedColorDelegator
835 UndoDelegator = ModifiedUndoDelegator
836
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000837 # Override menus
Kurt B. Kaiserdc1e7092002-07-11 04:33:41 +0000838 menu_specs = [
839 ("file", "_File"),
840 ("edit", "_Edit"),
Kurt B. Kaiser4cc5ef52003-01-22 00:23:23 +0000841 ("debug", "_Debug"),
Kurt B. Kaiser1061e722003-01-04 01:43:53 +0000842 ("options", "_Options"),
Kurt B. Kaiserdc1e7092002-07-11 04:33:41 +0000843 ("windows", "_Windows"),
844 ("help", "_Help"),
845 ]
David Scherer7aced172000-08-15 01:13:23 +0000846
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000847 if macosxSupport.runningAsOSXApp():
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000848 menu_specs[-2] = ("windows", "_Window")
849
850
David Scherer7aced172000-08-15 01:13:23 +0000851 # New classes
Kurt B. Kaiser2d7f6a02007-08-22 23:01:33 +0000852 from idlelib.IdleHistory import History
David Scherer7aced172000-08-15 01:13:23 +0000853
854 def __init__(self, flist=None):
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +0000855 if use_subprocess:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000856 ms = self.menu_specs
857 if ms[2][0] != "shell":
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000858 ms.insert(2, ("shell", "She_ll"))
David Scherer7aced172000-08-15 01:13:23 +0000859 self.interp = ModifiedInterpreter(self)
860 if flist is None:
861 root = Tk()
862 fixwordbreaks(root)
863 root.withdraw()
864 flist = PyShellFileList(root)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000865 #
David Scherer7aced172000-08-15 01:13:23 +0000866 OutputWindow.__init__(self, flist, None, None)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000867 #
Kurt B. Kaiser6af44982005-01-19 00:22:59 +0000868## self.config(usetabs=1, indentwidth=8, context_use_ps1=1)
869 self.usetabs = True
870 # indentwidth must be 8 when using tabs. See note in EditorWindow:
871 self.indentwidth = 8
872 self.context_use_ps1 = True
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000873 #
David Scherer7aced172000-08-15 01:13:23 +0000874 text = self.text
875 text.configure(wrap="char")
876 text.bind("<<newline-and-indent>>", self.enter_callback)
877 text.bind("<<plain-newline-and-indent>>", self.linefeed_callback)
878 text.bind("<<interrupt-execution>>", self.cancel_callback)
David Scherer7aced172000-08-15 01:13:23 +0000879 text.bind("<<end-of-file>>", self.eof_callback)
880 text.bind("<<open-stack-viewer>>", self.open_stack_viewer)
Kurt B. Kaiser57bfe5d2003-05-10 00:09:52 +0000881 text.bind("<<toggle-debugger>>", self.toggle_debugger)
David Scherer7aced172000-08-15 01:13:23 +0000882 text.bind("<<toggle-jit-stack-viewer>>", self.toggle_jit_stack_viewer)
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +0000883 if use_subprocess:
884 text.bind("<<view-restart>>", self.view_restart_mark)
885 text.bind("<<restart-shell>>", self.restart_shell)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000886 #
David Scherer7aced172000-08-15 01:13:23 +0000887 self.save_stdout = sys.stdout
888 self.save_stderr = sys.stderr
889 self.save_stdin = sys.stdin
Kurt B. Kaiser2d7f6a02007-08-22 23:01:33 +0000890 from idlelib import IOBinding
Serhiy Storchaka39e70a42013-01-25 15:30:58 +0200891 self.stdin = PseudoInputFile(self, "stdin", IOBinding.encoding)
892 self.stdout = PseudoOutputFile(self, "stdout", IOBinding.encoding)
893 self.stderr = PseudoOutputFile(self, "stderr", IOBinding.encoding)
894 self.console = PseudoOutputFile(self, "console", IOBinding.encoding)
Chui Tey5d2af632002-05-26 13:36:41 +0000895 if not use_subprocess:
896 sys.stdout = self.stdout
Kurt B. Kaiser7cec2522007-08-31 04:15:13 +0000897 sys.stderr = self.stderr
Martin v. Löwisc882b7c2012-07-25 10:47:20 +0200898 sys.stdin = self.stdin
Kurt B. Kaiserf609a342007-12-28 03:57:56 +0000899 try:
900 # page help() text to shell.
901 import pydoc # import must be done here to capture i/o rebinding.
902 # XXX KBK 27Dec07 use a textView someday, but must work w/o subproc
903 pydoc.pager = pydoc.plainpager
904 except:
905 sys.stderr = sys.__stderr__
906 raise
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000907 #
David Scherer7aced172000-08-15 01:13:23 +0000908 self.history = self.History(self.text)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000909 #
Kurt B. Kaiser88957d82003-05-19 23:11:51 +0000910 self.pollinterval = 50 # millisec
Chui Tey5d2af632002-05-26 13:36:41 +0000911
Kurt B. Kaiser4d5bc602004-06-06 01:29:22 +0000912 def get_standard_extension_names(self):
913 return idleConf.GetExtensions(shell_only=True)
914
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000915 reading = False
916 executing = False
917 canceled = False
918 endoffile = False
919 closing = False
Roger Serwy6b7a5ae2013-04-03 00:42:24 -0500920 _stop_readline_flag = False
David Scherer7aced172000-08-15 01:13:23 +0000921
Kurt B. Kaiser49a5fe12004-07-04 01:25:56 +0000922 def set_warning_stream(self, stream):
Skip Montanarod9161422004-07-06 21:53:27 +0000923 global warning_stream
924 warning_stream = stream
Kurt B. Kaiser49a5fe12004-07-04 01:25:56 +0000925
926 def get_warning_stream(self):
927 return warning_stream
928
David Scherer7aced172000-08-15 01:13:23 +0000929 def toggle_debugger(self, event=None):
930 if self.executing:
931 tkMessageBox.showerror("Don't debug now",
932 "You can only toggle the debugger when idle",
933 master=self.text)
934 self.set_debugger_indicator()
935 return "break"
936 else:
937 db = self.interp.getdebugger()
938 if db:
939 self.close_debugger()
940 else:
941 self.open_debugger()
942
943 def set_debugger_indicator(self):
944 db = self.interp.getdebugger()
945 self.setvar("<<toggle-debugger>>", not not db)
946
Kurt B. Kaiser1061e722003-01-04 01:43:53 +0000947 def toggle_jit_stack_viewer(self, event=None):
David Scherer7aced172000-08-15 01:13:23 +0000948 pass # All we need is the variable
949
950 def close_debugger(self):
951 db = self.interp.getdebugger()
952 if db:
953 self.interp.setdebugger(None)
954 db.close()
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000955 if self.interp.rpcclt:
956 RemoteDebugger.close_remote_debugger(self.interp.rpcclt)
David Scherer7aced172000-08-15 01:13:23 +0000957 self.resetoutput()
958 self.console.write("[DEBUG OFF]\n")
959 sys.ps1 = ">>> "
960 self.showprompt()
961 self.set_debugger_indicator()
962
963 def open_debugger(self):
Chui Tey5d2af632002-05-26 13:36:41 +0000964 if self.interp.rpcclt:
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000965 dbg_gui = RemoteDebugger.start_remote_debugger(self.interp.rpcclt,
966 self)
967 else:
968 dbg_gui = Debugger.Debugger(self)
969 self.interp.setdebugger(dbg_gui)
970 dbg_gui.load_breakpoints()
Chui Tey5d2af632002-05-26 13:36:41 +0000971 sys.ps1 = "[DEBUG ON]\n>>> "
972 self.showprompt()
973 self.set_debugger_indicator()
974
David Scherer7aced172000-08-15 01:13:23 +0000975 def beginexecuting(self):
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000976 "Helper for ModifiedInterpreter"
David Scherer7aced172000-08-15 01:13:23 +0000977 self.resetoutput()
978 self.executing = 1
David Scherer7aced172000-08-15 01:13:23 +0000979
980 def endexecuting(self):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000981 "Helper for ModifiedInterpreter"
David Scherer7aced172000-08-15 01:13:23 +0000982 self.executing = 0
983 self.canceled = 0
Chui Tey5d2af632002-05-26 13:36:41 +0000984 self.showprompt()
David Scherer7aced172000-08-15 01:13:23 +0000985
986 def close(self):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000987 "Extend EditorWindow.close()"
David Scherer7aced172000-08-15 01:13:23 +0000988 if self.executing:
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000989 response = tkMessageBox.askokcancel(
David Scherer7aced172000-08-15 01:13:23 +0000990 "Kill?",
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000991 "The program is still running!\n Do you want to kill it?",
David Scherer7aced172000-08-15 01:13:23 +0000992 default="ok",
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000993 parent=self.text)
Benjamin Peterson2a691a82008-03-31 01:51:45 +0000994 if response is False:
David Scherer7aced172000-08-15 01:13:23 +0000995 return "cancel"
Roger Serwy6b7a5ae2013-04-03 00:42:24 -0500996 self.stop_readline()
Kurt B. Kaiser5c3df352004-12-23 04:20:59 +0000997 self.canceled = True
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000998 self.closing = True
Kurt B. Kaiser88957d82003-05-19 23:11:51 +0000999 return EditorWindow.close(self)
David Scherer7aced172000-08-15 01:13:23 +00001000
1001 def _close(self):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +00001002 "Extend EditorWindow._close(), shut down debugger and execution server"
David Scherer7aced172000-08-15 01:13:23 +00001003 self.close_debugger()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +00001004 if use_subprocess:
1005 self.interp.kill_subprocess()
David Scherer7aced172000-08-15 01:13:23 +00001006 # Restore std streams
1007 sys.stdout = self.save_stdout
1008 sys.stderr = self.save_stderr
1009 sys.stdin = self.save_stdin
1010 # Break cycles
1011 self.interp = None
1012 self.console = None
David Scherer7aced172000-08-15 01:13:23 +00001013 self.flist.pyshell = None
1014 self.history = None
Kurt B. Kaiser83118c62002-06-24 17:03:37 +00001015 EditorWindow._close(self)
David Scherer7aced172000-08-15 01:13:23 +00001016
1017 def ispythonsource(self, filename):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +00001018 "Override EditorWindow method: never remove the colorizer"
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +00001019 return True
David Scherer7aced172000-08-15 01:13:23 +00001020
1021 def short_title(self):
1022 return self.shell_title
1023
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +00001024 COPYRIGHT = \
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001025 'Type "copyright", "credits" or "license()" for more information.'
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +00001026
David Scherer7aced172000-08-15 01:13:23 +00001027 def begin(self):
Kurt B. Kaiser7378df72007-08-11 04:20:51 +00001028 self.text.mark_set("iomark", "insert")
David Scherer7aced172000-08-15 01:13:23 +00001029 self.resetoutput()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +00001030 if use_subprocess:
1031 nosub = ''
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +00001032 client = self.interp.start_subprocess()
1033 if not client:
1034 self.close()
Kurt B. Kaiser76637292004-01-21 22:10:01 +00001035 return False
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +00001036 else:
Andrew Svetlov9b1e59a2012-10-05 22:12:44 +03001037 nosub = ("==== No Subprocess ====\n\n" +
Andrew Svetlov64478ac2012-10-05 22:16:55 +03001038 "WARNING: Running IDLE without a Subprocess is deprecated\n" +
Andrew Svetlov9b1e59a2012-10-05 22:12:44 +03001039 "and will be removed in a later version. See Help/IDLE Help\n" +
1040 "for details.\n\n")
Andrew Svetlovcd49d532012-03-25 11:43:02 +03001041 sys.displayhook = rpc.displayhook
1042
Raymond Hettingera2a8e8b2009-01-27 00:28:36 +00001043 self.write("Python %s on %s\n%s\n%s" %
1044 (sys.version, sys.platform, self.COPYRIGHT, nosub))
David Scherer7aced172000-08-15 01:13:23 +00001045 self.showprompt()
Georg Brandl14fc4272008-05-17 18:39:55 +00001046 import tkinter
1047 tkinter._default_root = None # 03Jan04 KBK What's this?
Kurt B. Kaiser76637292004-01-21 22:10:01 +00001048 return True
David Scherer7aced172000-08-15 01:13:23 +00001049
Roger Serwy6b7a5ae2013-04-03 00:42:24 -05001050 def stop_readline(self):
1051 if not self.reading: # no nested mainloop to exit.
1052 return
1053 self._stop_readline_flag = True
1054 self.top.quit()
1055
David Scherer7aced172000-08-15 01:13:23 +00001056 def readline(self):
1057 save = self.reading
1058 try:
1059 self.reading = 1
Kurt B. Kaiser5c3df352004-12-23 04:20:59 +00001060 self.top.mainloop() # nested mainloop()
David Scherer7aced172000-08-15 01:13:23 +00001061 finally:
1062 self.reading = save
Roger Serwy6b7a5ae2013-04-03 00:42:24 -05001063 if self._stop_readline_flag:
1064 self._stop_readline_flag = False
1065 return ""
David Scherer7aced172000-08-15 01:13:23 +00001066 line = self.text.get("iomark", "end-1c")
Kurt B. Kaiser5c3df352004-12-23 04:20:59 +00001067 if len(line) == 0: # may be EOF if we quit our mainloop with Ctrl-C
1068 line = "\n"
David Scherer7aced172000-08-15 01:13:23 +00001069 self.resetoutput()
1070 if self.canceled:
1071 self.canceled = 0
Kurt B. Kaiser5c3df352004-12-23 04:20:59 +00001072 if not use_subprocess:
1073 raise KeyboardInterrupt
David Scherer7aced172000-08-15 01:13:23 +00001074 if self.endoffile:
1075 self.endoffile = 0
Kurt B. Kaiser5c3df352004-12-23 04:20:59 +00001076 line = ""
David Scherer7aced172000-08-15 01:13:23 +00001077 return line
1078
1079 def isatty(self):
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +00001080 return True
David Scherer7aced172000-08-15 01:13:23 +00001081
Kurt B. Kaiser003091c2003-02-17 18:57:16 +00001082 def cancel_callback(self, event=None):
David Scherer7aced172000-08-15 01:13:23 +00001083 try:
1084 if self.text.compare("sel.first", "!=", "sel.last"):
1085 return # Active selection -- always use default binding
1086 except:
1087 pass
1088 if not (self.executing or self.reading):
1089 self.resetoutput()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +00001090 self.interp.write("KeyboardInterrupt\n")
David Scherer7aced172000-08-15 01:13:23 +00001091 self.showprompt()
1092 return "break"
1093 self.endoffile = 0
Kurt B. Kaiser003091c2003-02-17 18:57:16 +00001094 self.canceled = 1
Kurt B. Kaiser5c3df352004-12-23 04:20:59 +00001095 if (self.executing and self.interp.rpcclt):
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +00001096 if self.interp.getdebugger():
1097 self.interp.restart_subprocess()
1098 else:
1099 self.interp.interrupt_subprocess()
Kurt B. Kaiser5c3df352004-12-23 04:20:59 +00001100 if self.reading:
1101 self.top.quit() # exit the nested mainloop() in readline()
David Scherer7aced172000-08-15 01:13:23 +00001102 return "break"
1103
1104 def eof_callback(self, event):
1105 if self.executing and not self.reading:
1106 return # Let the default binding (delete next char) take over
1107 if not (self.text.compare("iomark", "==", "insert") and
1108 self.text.compare("insert", "==", "end-1c")):
1109 return # Let the default binding (delete next char) take over
1110 if not self.executing:
David Scherer7aced172000-08-15 01:13:23 +00001111 self.resetoutput()
1112 self.close()
1113 else:
1114 self.canceled = 0
1115 self.endoffile = 1
1116 self.top.quit()
1117 return "break"
1118
David Scherer7aced172000-08-15 01:13:23 +00001119 def linefeed_callback(self, event):
1120 # Insert a linefeed without entering anything (still autoindented)
1121 if self.reading:
1122 self.text.insert("insert", "\n")
1123 self.text.see("insert")
1124 else:
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +00001125 self.newline_and_indent_event(event)
David Scherer7aced172000-08-15 01:13:23 +00001126 return "break"
1127
1128 def enter_callback(self, event):
1129 if self.executing and not self.reading:
1130 return # Let the default binding (insert '\n') take over
1131 # If some text is selected, recall the selection
1132 # (but only if this before the I/O mark)
1133 try:
1134 sel = self.text.get("sel.first", "sel.last")
1135 if sel:
1136 if self.text.compare("sel.last", "<=", "iomark"):
Kurt B. Kaisera7daba62005-06-19 18:56:15 +00001137 self.recall(sel, event)
David Scherer7aced172000-08-15 01:13:23 +00001138 return "break"
1139 except:
1140 pass
1141 # If we're strictly before the line containing iomark, recall
1142 # the current line, less a leading prompt, less leading or
1143 # trailing whitespace
1144 if self.text.compare("insert", "<", "iomark linestart"):
1145 # Check if there's a relevant stdin range -- if so, use it
1146 prev = self.text.tag_prevrange("stdin", "insert")
1147 if prev and self.text.compare("insert", "<", prev[1]):
Kurt B. Kaisera7daba62005-06-19 18:56:15 +00001148 self.recall(self.text.get(prev[0], prev[1]), event)
David Scherer7aced172000-08-15 01:13:23 +00001149 return "break"
1150 next = self.text.tag_nextrange("stdin", "insert")
1151 if next and self.text.compare("insert lineend", ">=", next[0]):
Kurt B. Kaisera7daba62005-06-19 18:56:15 +00001152 self.recall(self.text.get(next[0], next[1]), event)
David Scherer7aced172000-08-15 01:13:23 +00001153 return "break"
Kurt B. Kaiser4ada7ad2002-12-29 22:03:38 +00001154 # No stdin mark -- just get the current line, less any prompt
Kurt B. Kaiserb1754452005-11-18 22:05:48 +00001155 indices = self.text.tag_nextrange("console", "insert linestart")
1156 if indices and \
1157 self.text.compare(indices[0], "<=", "insert linestart"):
1158 self.recall(self.text.get(indices[1], "insert lineend"), event)
1159 else:
1160 self.recall(self.text.get("insert linestart", "insert lineend"), event)
David Scherer7aced172000-08-15 01:13:23 +00001161 return "break"
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +00001162 # If we're between the beginning of the line and the iomark, i.e.
Kurt B. Kaiser4ada7ad2002-12-29 22:03:38 +00001163 # in the prompt area, move to the end of the prompt
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +00001164 if self.text.compare("insert", "<", "iomark"):
Kurt B. Kaiser4ada7ad2002-12-29 22:03:38 +00001165 self.text.mark_set("insert", "iomark")
David Scherer7aced172000-08-15 01:13:23 +00001166 # If we're in the current input and there's only whitespace
1167 # beyond the cursor, erase that whitespace first
1168 s = self.text.get("insert", "end-1c")
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +00001169 if s and not s.strip():
David Scherer7aced172000-08-15 01:13:23 +00001170 self.text.delete("insert", "end-1c")
1171 # If we're in the current input before its last line,
1172 # insert a newline right at the insert point
1173 if self.text.compare("insert", "<", "end-1c linestart"):
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +00001174 self.newline_and_indent_event(event)
David Scherer7aced172000-08-15 01:13:23 +00001175 return "break"
1176 # We're in the last line; append a newline and submit it
1177 self.text.mark_set("insert", "end-1c")
1178 if self.reading:
1179 self.text.insert("insert", "\n")
1180 self.text.see("insert")
1181 else:
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +00001182 self.newline_and_indent_event(event)
David Scherer7aced172000-08-15 01:13:23 +00001183 self.text.tag_add("stdin", "iomark", "end-1c")
1184 self.text.update_idletasks()
1185 if self.reading:
Neal Norwitzce96f692006-03-17 06:49:51 +00001186 self.top.quit() # Break out of recursive mainloop()
David Scherer7aced172000-08-15 01:13:23 +00001187 else:
1188 self.runit()
1189 return "break"
1190
Kurt B. Kaisera7daba62005-06-19 18:56:15 +00001191 def recall(self, s, event):
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001192 # remove leading and trailing empty or whitespace lines
1193 s = re.sub(r'^\s*\n', '' , s)
1194 s = re.sub(r'\n\s*$', '', s)
1195 lines = s.split('\n')
Kurt B. Kaisera7daba62005-06-19 18:56:15 +00001196 self.text.undo_block_start()
1197 try:
1198 self.text.tag_remove("sel", "1.0", "end")
1199 self.text.mark_set("insert", "end-1c")
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001200 prefix = self.text.get("insert linestart", "insert")
1201 if prefix.rstrip().endswith(':'):
Kurt B. Kaiser8fa7eb52005-06-21 02:42:17 +00001202 self.newline_and_indent_event(event)
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001203 prefix = self.text.get("insert linestart", "insert")
1204 self.text.insert("insert", lines[0].strip())
Kurt B. Kaiser8fa7eb52005-06-21 02:42:17 +00001205 if len(lines) > 1:
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001206 orig_base_indent = re.search(r'^([ \t]*)', lines[0]).group(0)
1207 new_base_indent = re.search(r'^([ \t]*)', prefix).group(0)
Kurt B. Kaiser8fa7eb52005-06-21 02:42:17 +00001208 for line in lines[1:]:
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001209 if line.startswith(orig_base_indent):
1210 # replace orig base indentation with new indentation
1211 line = new_base_indent + line[len(orig_base_indent):]
1212 self.text.insert('insert', '\n'+line.rstrip())
Kurt B. Kaisera7daba62005-06-19 18:56:15 +00001213 finally:
1214 self.text.see("insert")
1215 self.text.undo_block_stop()
David Scherer7aced172000-08-15 01:13:23 +00001216
1217 def runit(self):
1218 line = self.text.get("iomark", "end-1c")
1219 # Strip off last newline and surrounding whitespace.
1220 # (To allow you to hit return twice to end a statement.)
1221 i = len(line)
1222 while i > 0 and line[i-1] in " \t":
1223 i = i-1
1224 if i > 0 and line[i-1] == "\n":
1225 i = i-1
1226 while i > 0 and line[i-1] in " \t":
1227 i = i-1
1228 line = line[:i]
1229 more = self.interp.runsource(line)
David Scherer7aced172000-08-15 01:13:23 +00001230
David Scherer7aced172000-08-15 01:13:23 +00001231 def open_stack_viewer(self, event=None):
Chui Tey5d2af632002-05-26 13:36:41 +00001232 if self.interp.rpcclt:
1233 return self.interp.remote_stack_viewer()
David Scherer7aced172000-08-15 01:13:23 +00001234 try:
1235 sys.last_traceback
1236 except:
1237 tkMessageBox.showerror("No stack trace",
1238 "There is no stack trace yet.\n"
1239 "(sys.last_traceback is not defined)",
1240 master=self.text)
1241 return
Kurt B. Kaiser2d7f6a02007-08-22 23:01:33 +00001242 from idlelib.StackViewer import StackBrowser
David Scherer7aced172000-08-15 01:13:23 +00001243 sv = StackBrowser(self.root, self.flist)
1244
Kurt B. Kaiser1061e722003-01-04 01:43:53 +00001245 def view_restart_mark(self, event=None):
1246 self.text.see("iomark")
1247 self.text.see("restart")
1248
1249 def restart_shell(self, event=None):
Terry Jan Reedyda4c4672012-01-31 02:26:32 -05001250 "Callback for Run/Restart Shell Cntl-F6"
1251 self.interp.restart_subprocess(with_cwd=True)
Kurt B. Kaiser1061e722003-01-04 01:43:53 +00001252
David Scherer7aced172000-08-15 01:13:23 +00001253 def showprompt(self):
1254 self.resetoutput()
1255 try:
1256 s = str(sys.ps1)
1257 except:
1258 s = ""
1259 self.console.write(s)
1260 self.text.mark_set("insert", "end-1c")
Chui Tey5d2af632002-05-26 13:36:41 +00001261 self.set_line_and_column()
Kurt B. Kaiserdc1e7092002-07-11 04:33:41 +00001262 self.io.reset_undo()
David Scherer7aced172000-08-15 01:13:23 +00001263
1264 def resetoutput(self):
1265 source = self.text.get("iomark", "end-1c")
1266 if self.history:
Terry Jan Reedy0a01ac42013-08-13 19:51:04 -04001267 self.history.store(source)
David Scherer7aced172000-08-15 01:13:23 +00001268 if self.text.get("end-2c") != "\n":
1269 self.text.insert("end-1c", "\n")
1270 self.text.mark_set("iomark", "end-1c")
Chui Tey5d2af632002-05-26 13:36:41 +00001271 self.set_line_and_column()
David Scherer7aced172000-08-15 01:13:23 +00001272
1273 def write(self, s, tags=()):
Andrew Svetlov05bab932012-03-14 13:22:12 -07001274 if isinstance(s, str) and len(s) and max(s) > '\uffff':
1275 # Tk doesn't support outputting non-BMP characters
1276 # Let's assume what printed string is not very long,
1277 # find first non-BMP character and construct informative
1278 # UnicodeEncodeError exception.
1279 for start, char in enumerate(s):
1280 if char > '\uffff':
1281 break
1282 raise UnicodeEncodeError("UCS-2", char, start, start+1,
1283 'Non-BMP character not supported in Tk')
Kurt B. Kaiser003091c2003-02-17 18:57:16 +00001284 try:
1285 self.text.mark_gravity("iomark", "right")
Martin v. Löwis30d5e6c2012-07-25 11:32:26 +02001286 count = OutputWindow.write(self, s, tags, "iomark")
Kurt B. Kaiser003091c2003-02-17 18:57:16 +00001287 self.text.mark_gravity("iomark", "left")
1288 except:
Kurt B. Kaisercbbe98f2007-08-12 01:52:35 +00001289 raise ###pass # ### 11Aug07 KBK if we are expecting exceptions
1290 # let's find out what they are and be specific.
David Scherer7aced172000-08-15 01:13:23 +00001291 if self.canceled:
1292 self.canceled = 0
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +00001293 if not use_subprocess:
1294 raise KeyboardInterrupt
Martin v. Löwis30d5e6c2012-07-25 11:32:26 +02001295 return count
David Scherer7aced172000-08-15 01:13:23 +00001296
Andrew Svetlovd1837672012-11-01 22:41:19 +02001297 def rmenu_check_cut(self):
1298 try:
1299 if self.text.compare('sel.first', '<', 'iomark'):
1300 return 'disabled'
1301 except TclError: # no selection, so the index 'sel.first' doesn't exist
1302 return 'disabled'
1303 return super().rmenu_check_cut()
1304
1305 def rmenu_check_paste(self):
1306 if self.text.compare('insert','<','iomark'):
1307 return 'disabled'
1308 return super().rmenu_check_paste()
1309
Serhiy Storchaka39e70a42013-01-25 15:30:58 +02001310class PseudoFile(io.TextIOBase):
David Scherer7aced172000-08-15 01:13:23 +00001311
Martin v. Löwisbcc651a2003-06-22 07:52:56 +00001312 def __init__(self, shell, tags, encoding=None):
David Scherer7aced172000-08-15 01:13:23 +00001313 self.shell = shell
1314 self.tags = tags
Serhiy Storchaka39e70a42013-01-25 15:30:58 +02001315 self._encoding = encoding
David Scherer7aced172000-08-15 01:13:23 +00001316
Serhiy Storchaka39e70a42013-01-25 15:30:58 +02001317 @property
1318 def encoding(self):
1319 return self._encoding
David Scherer7aced172000-08-15 01:13:23 +00001320
Serhiy Storchaka39e70a42013-01-25 15:30:58 +02001321 @property
1322 def name(self):
1323 return '<%s>' % self.tags
David Scherer7aced172000-08-15 01:13:23 +00001324
1325 def isatty(self):
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +00001326 return True
David Scherer7aced172000-08-15 01:13:23 +00001327
Serhiy Storchaka39e70a42013-01-25 15:30:58 +02001328
1329class PseudoOutputFile(PseudoFile):
1330
1331 def writable(self):
1332 return True
Martin v. Löwisc882b7c2012-07-25 10:47:20 +02001333
1334 def write(self, s):
Serhiy Storchaka39e70a42013-01-25 15:30:58 +02001335 if self.closed:
1336 raise ValueError("write to closed file")
Serhiy Storchaka9df8a1c2013-12-10 10:05:19 +02001337 if type(s) is not str:
1338 if not isinstance(s, str):
1339 raise TypeError('must be str, not ' + type(s).__name__)
1340 # See issue #19481
1341 s = str.__str__(s)
Serhiy Storchaka39e70a42013-01-25 15:30:58 +02001342 return self.shell.write(s, self.tags)
1343
1344
1345class PseudoInputFile(PseudoFile):
1346
1347 def __init__(self, shell, tags, encoding=None):
1348 PseudoFile.__init__(self, shell, tags, encoding)
1349 self._line_buffer = ''
1350
1351 def readable(self):
1352 return True
1353
1354 def read(self, size=-1):
1355 if self.closed:
1356 raise ValueError("read from closed file")
1357 if size is None:
1358 size = -1
1359 elif not isinstance(size, int):
1360 raise TypeError('must be int, not ' + type(size).__name__)
1361 result = self._line_buffer
1362 self._line_buffer = ''
1363 if size < 0:
1364 while True:
1365 line = self.shell.readline()
1366 if not line: break
1367 result += line
1368 else:
1369 while len(result) < size:
1370 line = self.shell.readline()
1371 if not line: break
1372 result += line
1373 self._line_buffer = result[size:]
1374 result = result[:size]
1375 return result
1376
1377 def readline(self, size=-1):
1378 if self.closed:
1379 raise ValueError("read from closed file")
1380 if size is None:
1381 size = -1
1382 elif not isinstance(size, int):
1383 raise TypeError('must be int, not ' + type(size).__name__)
1384 line = self._line_buffer or self.shell.readline()
1385 if size < 0:
1386 size = len(line)
Serhiy Storchaka0fd55762013-12-25 14:24:35 +02001387 eol = line.find('\n', 0, size)
1388 if eol >= 0:
1389 size = eol + 1
Serhiy Storchaka39e70a42013-01-25 15:30:58 +02001390 self._line_buffer = line[size:]
1391 return line[:size]
Martin v. Löwisc882b7c2012-07-25 10:47:20 +02001392
Roger Serwy1eafd102013-04-11 19:16:44 -05001393 def close(self):
1394 self.shell.close()
1395
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001396
David Scherer7aced172000-08-15 01:13:23 +00001397usage_msg = """\
David Scherer7aced172000-08-15 01:13:23 +00001398
Kurt B. Kaiser11659ad2003-05-15 23:23:21 +00001399USAGE: idle [-deins] [-t title] [file]*
1400 idle [-dns] [-t title] (-c cmd | -r file) [arg]*
1401 idle [-dns] [-t title] - [arg]*
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001402
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001403 -h print this help message and exit
Andrew Svetlov9b1e59a2012-10-05 22:12:44 +03001404 -n run IDLE without a subprocess (DEPRECATED,
1405 see Help/IDLE Help for details)
David Scherer7aced172000-08-15 01:13:23 +00001406
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001407The following options will override the IDLE 'settings' configuration:
Kurt B. Kaiser96d88422001-07-17 04:59:01 +00001408
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001409 -e open an edit window
1410 -i open a shell window
1411
1412The following options imply -i and will open a shell:
1413
1414 -c cmd run the command in a shell, or
1415 -r file run script from file
1416
1417 -d enable the debugger
1418 -s run $IDLESTARTUP or $PYTHONSTARTUP before anything else
1419 -t title set title of shell window
1420
1421A default edit window will be bypassed when -c, -r, or - are used.
1422
1423[arg]* are passed to the command (-c) or script (-r) in sys.argv[1:].
1424
1425Examples:
1426
1427idle
1428 Open an edit window or shell depending on IDLE's configuration.
1429
1430idle foo.py foobar.py
1431 Edit the files, also open a shell if configured to start with shell.
1432
1433idle -est "Baz" foo.py
1434 Run $IDLESTARTUP or $PYTHONSTARTUP, edit foo.py, and open a shell
1435 window with the title "Baz".
1436
Neal Norwitz752abd02008-05-13 04:55:24 +00001437idle -c "import sys; print(sys.argv)" "foo"
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001438 Open a shell window and run the command, passing "-c" in sys.argv[0]
1439 and "foo" in sys.argv[1].
1440
1441idle -d -s -r foo.py "Hello World"
1442 Open a shell window, run a startup script, enable the debugger, and
1443 run foo.py, passing "foo.py" in sys.argv[0] and "Hello World" in
1444 sys.argv[1].
1445
Neal Norwitz752abd02008-05-13 04:55:24 +00001446echo "import sys; print(sys.argv)" | idle - "foobar"
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001447 Open a shell window, run the script piped in, passing '' in sys.argv[0]
1448 and "foobar" in sys.argv[1].
David Scherer7aced172000-08-15 01:13:23 +00001449"""
1450
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001451def main():
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001452 global flist, root, use_subprocess
David Scherer7aced172000-08-15 01:13:23 +00001453
Terry Jan Reedy95a3f112013-06-28 23:50:12 -04001454 capture_warnings(True)
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001455 use_subprocess = True
Roger Serwyc35151c2013-03-31 23:28:55 -05001456 enable_shell = False
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001457 enable_edit = False
1458 debug = False
1459 cmd = None
1460 script = None
1461 startup = False
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001462 try:
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001463 opts, args = getopt.getopt(sys.argv[1:], "c:deihnr:st:")
Guido van Rossumb940e112007-01-10 16:19:56 +00001464 except getopt.error as msg:
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001465 sys.stderr.write("Error: %s\n" % str(msg))
1466 sys.stderr.write(usage_msg)
1467 sys.exit(2)
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001468 for o, a in opts:
1469 if o == '-c':
1470 cmd = a
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001471 enable_shell = True
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001472 if o == '-d':
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001473 debug = True
1474 enable_shell = True
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001475 if o == '-e':
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001476 enable_edit = True
1477 if o == '-h':
1478 sys.stdout.write(usage_msg)
1479 sys.exit()
1480 if o == '-i':
1481 enable_shell = True
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001482 if o == '-n':
Andrew Svetlov9b1e59a2012-10-05 22:12:44 +03001483 print(" Warning: running IDLE without a subprocess is deprecated.",
1484 file=sys.stderr)
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001485 use_subprocess = False
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001486 if o == '-r':
1487 script = a
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001488 if os.path.isfile(script):
1489 pass
1490 else:
Guido van Rossumbe19ed72007-02-09 05:37:30 +00001491 print("No script file: ", script)
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001492 sys.exit()
1493 enable_shell = True
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001494 if o == '-s':
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001495 startup = True
1496 enable_shell = True
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001497 if o == '-t':
1498 PyShell.shell_title = a
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001499 enable_shell = True
1500 if args and args[0] == '-':
1501 cmd = sys.stdin.read()
1502 enable_shell = True
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001503 # process sys.argv and sys.path:
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001504 for i in range(len(sys.path)):
1505 sys.path[i] = os.path.abspath(sys.path[i])
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001506 if args and args[0] == '-':
1507 sys.argv = [''] + args[1:]
1508 elif cmd:
1509 sys.argv = ['-c'] + args
1510 elif script:
1511 sys.argv = [script] + args
1512 elif args:
1513 enable_edit = True
1514 pathx = []
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001515 for filename in args:
1516 pathx.append(os.path.dirname(filename))
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001517 for dir in pathx:
1518 dir = os.path.abspath(dir)
1519 if not dir in sys.path:
1520 sys.path.insert(0, dir)
Kurt B. Kaiserff002b92002-12-21 21:39:11 +00001521 else:
Neal Norwitzd082b6e2007-08-26 23:37:53 +00001522 dir = os.getcwd()
1523 if dir not in sys.path:
Kurt B. Kaiserff002b92002-12-21 21:39:11 +00001524 sys.path.insert(0, dir)
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001525 # check the IDLE settings configuration (but command line overrides)
1526 edit_start = idleConf.GetOption('main', 'General',
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001527 'editor-on-startup', type='bool')
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001528 enable_edit = enable_edit or edit_start
Roger Serwyc35151c2013-03-31 23:28:55 -05001529 enable_shell = enable_shell or not enable_edit
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001530 # start editor and/or shell windows:
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001531 root = Tk(className="Idle")
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001532
Terry Jan Reedya7c07d32014-02-08 09:02:26 -05001533 # set application icon
1534 icondir = os.path.join(os.path.dirname(__file__), 'Icons')
1535 if system() == 'Windows':
1536 iconfile = os.path.join(icondir, 'idle.ico')
1537 root.wm_iconbitmap(default=iconfile)
1538 elif TkVersion >= 8.5:
1539 ext = '.png' if TkVersion >= 8.6 else '.gif'
1540 iconfiles = [os.path.join(icondir, 'idle_%d%s' % (size, ext))
1541 for size in (16, 32, 48)]
1542 icons = [PhotoImage(file=iconfile) for iconfile in iconfiles]
1543 root.wm_iconphoto(True, *icons)
1544
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001545 fixwordbreaks(root)
1546 root.withdraw()
1547 flist = PyShellFileList(root)
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001548 macosxSupport.setupApp(root, flist)
1549
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001550 if enable_edit:
1551 if not (cmd or script):
Andrew Svetlov6b6e4372012-03-20 23:03:26 +02001552 for filename in args[:]:
1553 if flist.open(filename) is None:
1554 # filename is a directory actually, disconsider it
1555 args.remove(filename)
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001556 if not args:
1557 flist.new()
Ned Deilyf3c65892013-12-10 16:24:01 -08001558
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +00001559 if enable_shell:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001560 shell = flist.open_shell()
1561 if not shell:
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +00001562 return # couldn't open shell
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001563 if macosxSupport.runningAsOSXApp() and flist.dict:
1564 # On OSX: when the user has double-clicked on a file that causes
1565 # IDLE to be launched the shell window will open just in front of
1566 # the file she wants to see. Lower the interpreter window when
1567 # there are open files.
1568 shell.top.lower()
Ned Deilyf3c65892013-12-10 16:24:01 -08001569 else:
1570 shell = flist.pyshell
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001571
Ned Deilyf3c65892013-12-10 16:24:01 -08001572 # Handle remaining options. If any of these are set, enable_shell
1573 # was set also, so shell must be true to reach here.
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001574 if debug:
1575 shell.open_debugger()
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001576 if startup:
1577 filename = os.environ.get("IDLESTARTUP") or \
1578 os.environ.get("PYTHONSTARTUP")
1579 if filename and os.path.isfile(filename):
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001580 shell.interp.execfile(filename)
Ned Deilyf3c65892013-12-10 16:24:01 -08001581 if cmd or script:
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001582 shell.interp.runcommand("""if 1:
1583 import sys as _sys
Walter Dörwald70a6b492004-02-12 17:35:32 +00001584 _sys.argv = %r
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001585 del _sys
Walter Dörwald70a6b492004-02-12 17:35:32 +00001586 \n""" % (sys.argv,))
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001587 if cmd:
1588 shell.interp.execsource(cmd)
1589 elif script:
Kurt B. Kaiser11659ad2003-05-15 23:23:21 +00001590 shell.interp.prepend_syspath(script)
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001591 shell.interp.execfile(script)
Ned Deilyf3c65892013-12-10 16:24:01 -08001592 elif shell:
1593 # If there is a shell window and no cmd or script in progress,
1594 # check for problematic OS X Tk versions and print a warning
1595 # message in the IDLE shell window; this is less intrusive
1596 # than always opening a separate window.
1597 tkversionwarning = macosxSupport.tkVersionWarning(root)
1598 if tkversionwarning:
1599 shell.interp.runcommand("print('%s')" % tkversionwarning)
Ned Deily4ce92b22011-01-15 04:37:12 +00001600
Terry Jan Reedycd6b8c62012-05-26 20:23:45 -04001601 while flist.inversedict: # keep IDLE running while files are open.
1602 root.mainloop()
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001603 root.destroy()
Terry Jan Reedy95a3f112013-06-28 23:50:12 -04001604 capture_warnings(False)
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001605
David Scherer7aced172000-08-15 01:13:23 +00001606if __name__ == "__main__":
Kurt B. Kaiser9e8b8282003-06-15 17:38:45 +00001607 sys.modules['PyShell'] = sys.modules['__main__']
David Scherer7aced172000-08-15 01:13:23 +00001608 main()
Terry Jan Reedy95a3f112013-06-28 23:50:12 -04001609
1610capture_warnings(False) # Make sure turned off; see issue 18081