blob: 91e0e828fb4d23d06d0a8e13f73b183f32b2e2ac [file] [log] [blame]
David Scherer7aced172000-08-15 01:13:23 +00001#! /usr/bin/env python
Terry Jan Reedybee003c2014-09-19 22:37:24 -04002from __future__ import print_function
David Scherer7aced172000-08-15 01:13:23 +00003
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 sys
7import string
8import getopt
9import re
Chui Tey5d2af632002-05-26 13:36:41 +000010import socket
11import time
Kurt B. Kaiser003091c2003-02-17 18:57:16 +000012import threading
Chui Tey5d2af632002-05-26 13:36:41 +000013import traceback
Kurt B. Kaiser62833982002-09-18 17:07:05 +000014import types
Martin v. Löwise2b56242012-07-25 10:56:22 +020015import io
David Scherer7aced172000-08-15 01:13:23 +000016
17import linecache
18from code import InteractiveInterpreter
Terry Jan Reedy4ade2d22014-02-08 09:39:51 -050019from platform import python_version, system
David Scherer7aced172000-08-15 01:13:23 +000020
Kurt B. Kaiser2303b1c2003-11-24 05:26:16 +000021try:
Georg Brandl6634bf22008-05-20 07:13:37 +000022 from Tkinter import *
Kurt B. Kaiser2303b1c2003-11-24 05:26:16 +000023except ImportError:
Terry Jan Reedybee003c2014-09-19 22:37:24 -040024 print("** IDLE can't import Tkinter.\n"
25 "Your Python may not be configured for Tk. **", file=sys.__stderr__)
Kurt B. Kaiser2303b1c2003-11-24 05:26:16 +000026 sys.exit(1)
Georg Brandl6634bf22008-05-20 07:13:37 +000027import tkMessageBox
David Scherer7aced172000-08-15 01:13:23 +000028
Florent Xiclunad630c042010-04-02 07:24:52 +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. Kaiserb9764192002-09-23 04:10:37 +000041IDENTCHARS = string.ascii_letters + string.digits + "_"
Kurt B. Kaiser013d6cc2009-04-04 07:03:48 +000042HOST = '127.0.0.1' # python execution server on localhost loopback
43PORT = 0 # someday pass in host, port for remote debug capability
Kurt B. Kaiserb9764192002-09-23 04:10:37 +000044
Kurt B. Kaisera00050f2003-05-08 20:26:55 +000045try:
46 from signal import SIGTERM
47except ImportError:
48 SIGTERM = 15
49
Kurt B. Kaiser49a5fe12004-07-04 01:25:56 +000050# Override warnings module to write to warning_stream. Initialize to send IDLE
51# internal warnings to the console. ScriptBinding.check_syntax() will
52# temporarily redirect the stream to the shell window to display warnings when
53# checking user's code.
Terry Jan Reedy8eab0082013-06-28 23:51:34 -040054warning_stream = sys.__stderr__ # None, at least on Windows, if no console.
55import warnings
56
57def idle_formatwarning(message, category, filename, lineno, line=None):
58 """Format warnings the IDLE way."""
59
60 s = "\nWarning (from warnings module):\n"
61 s += ' File \"%s\", line %s\n' % (filename, lineno)
62 if line is None:
63 line = linecache.getline(filename, lineno)
64 line = line.strip()
65 if line:
66 s += " %s\n" % line
67 s += "%s: %s\n" % (category.__name__, message)
68 return s
69
70def idle_showwarning(
71 message, category, filename, lineno, file=None, line=None):
72 """Show Idle-format warning (after replacing warnings.showwarning).
73
74 The differences are the formatter called, the file=None replacement,
75 which can be None, the capture of the consequence AttributeError,
76 and the output of a hard-coded prompt.
77 """
78 if file is None:
79 file = warning_stream
80 try:
81 file.write(idle_formatwarning(
82 message, category, filename, lineno, line=line))
83 file.write(">>> ")
84 except (AttributeError, IOError):
85 pass # if file (probably __stderr__) is invalid, skip warning.
86
87_warnings_showwarning = None
88
89def capture_warnings(capture):
90 "Replace warning.showwarning with idle_showwarning, or reverse."
91
92 global _warnings_showwarning
93 if capture:
94 if _warnings_showwarning is None:
95 _warnings_showwarning = warnings.showwarning
96 warnings.showwarning = idle_showwarning
97 else:
98 if _warnings_showwarning is not None:
99 warnings.showwarning = _warnings_showwarning
100 _warnings_showwarning = None
101
102capture_warnings(True)
Chui Tey5d2af632002-05-26 13:36:41 +0000103
Kurt B. Kaiserf7a88992004-11-13 21:05:58 +0000104def extended_linecache_checkcache(filename=None,
105 orig_checkcache=linecache.checkcache):
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000106 """Extend linecache.checkcache to preserve the <pyshell#...> entries
107
Kurt B. Kaiserf7a88992004-11-13 21:05:58 +0000108 Rather than repeating the linecache code, patch it to save the
109 <pyshell#...> entries, call the original linecache.checkcache()
Guilherme Polof198ac22009-08-14 14:03:07 +0000110 (skipping them), and then restore the saved entries.
Kurt B. Kaiserf7a88992004-11-13 21:05:58 +0000111
112 orig_checkcache is bound at definition time to the original
113 method, allowing it to be patched.
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000114 """
David Scherer7aced172000-08-15 01:13:23 +0000115 cache = linecache.cache
116 save = {}
Guilherme Polof198ac22009-08-14 14:03:07 +0000117 for key in list(cache):
118 if key[:1] + key[-1:] == '<>':
119 save[key] = cache.pop(key)
120 orig_checkcache(filename)
David Scherer7aced172000-08-15 01:13:23 +0000121 cache.update(save)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000122
Kurt B. Kaiser81885592002-11-29 22:10:53 +0000123# Patch linecache.checkcache():
124linecache.checkcache = extended_linecache_checkcache
David Scherer7aced172000-08-15 01:13:23 +0000125
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000126
David Scherer7aced172000-08-15 01:13:23 +0000127class PyShellEditorWindow(EditorWindow):
Kurt B. Kaiser183403a2004-08-22 05:14:32 +0000128 "Regular text edit window in IDLE, supports breakpoints"
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000129
David Scherer7aced172000-08-15 01:13:23 +0000130 def __init__(self, *args):
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000131 self.breakpoints = []
Raymond Hettinger931237e2003-07-09 18:48:24 +0000132 EditorWindow.__init__(self, *args)
David Scherer7aced172000-08-15 01:13:23 +0000133 self.text.bind("<<set-breakpoint-here>>", self.set_breakpoint_here)
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000134 self.text.bind("<<clear-breakpoint-here>>", self.clear_breakpoint_here)
David Scherer7aced172000-08-15 01:13:23 +0000135 self.text.bind("<<open-python-shell>>", self.flist.open_shell)
136
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000137 self.breakpointPath = os.path.join(idleConf.GetUserCfgDir(),
138 'breakpoints.lst')
Chui Teya2adb0f2002-11-04 22:14:54 +0000139 # whenever a file is changed, restore breakpoints
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000140 def filename_changed_hook(old_hook=self.io.filename_change_hook,
141 self=self):
Chui Teya2adb0f2002-11-04 22:14:54 +0000142 self.restore_file_breaks()
143 old_hook()
144 self.io.set_filename_change_hook(filename_changed_hook)
Roger Serwyd7c9d9c2013-04-02 22:37:12 -0500145 if self.io.filename:
146 self.restore_file_breaks()
Terry Jan Reedy25327d42014-08-08 23:33:11 -0400147 self.color_breakpoint_text()
Chui Teya2adb0f2002-11-04 22:14:54 +0000148
Andrew Svetlov5018db72012-11-01 22:39:14 +0200149 rmenu_specs = [
150 ("Cut", "<<cut>>", "rmenu_check_cut"),
151 ("Copy", "<<copy>>", "rmenu_check_copy"),
152 ("Paste", "<<paste>>", "rmenu_check_paste"),
153 ("Set Breakpoint", "<<set-breakpoint-here>>", None),
154 ("Clear Breakpoint", "<<clear-breakpoint-here>>", None)
155 ]
David Scherer7aced172000-08-15 01:13:23 +0000156
Terry Jan Reedy25327d42014-08-08 23:33:11 -0400157 def color_breakpoint_text(self, color=True):
158 "Turn colorizing of breakpoint text on or off"
159 if color:
160 theme = idleConf.GetOption('main','Theme','name')
161 cfg = idleConf.GetHighlight(theme, "break")
162 else:
163 cfg = {'foreground': '', 'background': ''}
164 self.text.tag_config('BREAK', cfg)
165
Chui Teya2adb0f2002-11-04 22:14:54 +0000166 def set_breakpoint(self, lineno):
167 text = self.text
168 filename = self.io.filename
169 text.tag_add("BREAK", "%d.0" % lineno, "%d.0" % (lineno+1))
170 try:
171 i = self.breakpoints.index(lineno)
172 except ValueError: # only add if missing, i.e. do once
173 self.breakpoints.append(lineno)
174 try: # update the subprocess debugger
175 debug = self.flist.pyshell.interp.debugger
176 debug.set_breakpoint_here(filename, lineno)
177 except: # but debugger may not be active right now....
178 pass
179
David Scherer7aced172000-08-15 01:13:23 +0000180 def set_breakpoint_here(self, event=None):
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000181 text = self.text
182 filename = self.io.filename
183 if not filename:
184 text.bell()
David Scherer7aced172000-08-15 01:13:23 +0000185 return
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000186 lineno = int(float(text.index("insert")))
Chui Teya2adb0f2002-11-04 22:14:54 +0000187 self.set_breakpoint(lineno)
David Scherer7aced172000-08-15 01:13:23 +0000188
Kurt B. Kaiser669f4c32002-06-20 04:01:47 +0000189 def clear_breakpoint_here(self, event=None):
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000190 text = self.text
191 filename = self.io.filename
192 if not filename:
193 text.bell()
Kurt B. Kaiser669f4c32002-06-20 04:01:47 +0000194 return
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000195 lineno = int(float(text.index("insert")))
196 try:
197 self.breakpoints.remove(lineno)
198 except:
199 pass
200 text.tag_remove("BREAK", "insert linestart",\
201 "insert lineend +1char")
202 try:
203 debug = self.flist.pyshell.interp.debugger
204 debug.clear_breakpoint_here(filename, lineno)
205 except:
206 pass
207
208 def clear_file_breaks(self):
209 if self.breakpoints:
210 text = self.text
211 filename = self.io.filename
212 if not filename:
213 text.bell()
214 return
215 self.breakpoints = []
216 text.tag_remove("BREAK", "1.0", END)
217 try:
218 debug = self.flist.pyshell.interp.debugger
219 debug.clear_file_breaks(filename)
220 except:
221 pass
222
Chui Teya2adb0f2002-11-04 22:14:54 +0000223 def store_file_breaks(self):
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000224 "Save breakpoints when file is saved"
225 # XXX 13 Dec 2002 KBK Currently the file must be saved before it can
226 # be run. The breaks are saved at that time. If we introduce
227 # a temporary file save feature the save breaks functionality
228 # needs to be re-verified, since the breaks at the time the
229 # temp file is created may differ from the breaks at the last
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000230 # permanent save of the file. Currently, a break introduced
231 # after a save will be effective, but not persistent.
232 # This is necessary to keep the saved breaks synched with the
233 # saved file.
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000234 #
Terry Jan Reedy987a02b2014-10-12 01:10:58 -0400235 # Breakpoints are set as tagged ranges in the text.
236 # Since a modified file has to be saved before it is
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000237 # run, and since self.breakpoints (from which the subprocess
238 # debugger is loaded) is updated during the save, the visible
239 # breaks stay synched with the subprocess even if one of these
240 # unexpected breakpoint deletions occurs.
241 breaks = self.breakpoints
242 filename = self.io.filename
Chui Teya2adb0f2002-11-04 22:14:54 +0000243 try:
Ned Deily40ad0412011-12-14 14:57:43 -0800244 with open(self.breakpointPath,"r") as old_file:
245 lines = old_file.readlines()
Chui Teya2adb0f2002-11-04 22:14:54 +0000246 except IOError:
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000247 lines = []
Ned Deily40ad0412011-12-14 14:57:43 -0800248 try:
249 with open(self.breakpointPath,"w") as new_file:
250 for line in lines:
251 if not line.startswith(filename + '='):
252 new_file.write(line)
253 self.update_breakpoints()
254 breaks = self.breakpoints
255 if breaks:
256 new_file.write(filename + '=' + str(breaks) + '\n')
257 except IOError as err:
258 if not getattr(self.root, "breakpoint_error_displayed", False):
259 self.root.breakpoint_error_displayed = True
260 tkMessageBox.showerror(title='IDLE Error',
261 message='Unable to update breakpoint list:\n%s'
262 % str(err),
263 parent=self.text)
Chui Teya2adb0f2002-11-04 22:14:54 +0000264
265 def restore_file_breaks(self):
266 self.text.update() # this enables setting "BREAK" tags to be visible
Roger Serwyd7c9d9c2013-04-02 22:37:12 -0500267 if self.io is None:
268 # can happen if IDLE closes due to the .update() call
269 return
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000270 filename = self.io.filename
271 if filename is None:
272 return
Chui Tey69371d62002-11-04 23:39:45 +0000273 if os.path.isfile(self.breakpointPath):
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000274 lines = open(self.breakpointPath,"r").readlines()
Chui Tey69371d62002-11-04 23:39:45 +0000275 for line in lines:
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000276 if line.startswith(filename + '='):
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000277 breakpoint_linenumbers = eval(line[len(filename)+1:])
Chui Tey69371d62002-11-04 23:39:45 +0000278 for breakpoint_linenumber in breakpoint_linenumbers:
279 self.set_breakpoint(breakpoint_linenumber)
Chui Teya2adb0f2002-11-04 22:14:54 +0000280
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000281 def update_breakpoints(self):
282 "Retrieves all the breakpoints in the current window"
Chui Teya2adb0f2002-11-04 22:14:54 +0000283 text = self.text
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000284 ranges = text.tag_ranges("BREAK")
285 linenumber_list = self.ranges_to_linenumbers(ranges)
286 self.breakpoints = linenumber_list
287
288 def ranges_to_linenumbers(self, ranges):
289 lines = []
290 for index in range(0, len(ranges), 2):
Andrew Svetlov8a15c372012-07-31 19:51:27 +0300291 lineno = int(float(ranges[index].string))
292 end = int(float(ranges[index+1].string))
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000293 while lineno < end:
294 lines.append(lineno)
295 lineno += 1
296 return lines
297
Kurt B. Kaiser11220fa2002-12-24 00:57:22 +0000298# XXX 13 Dec 2002 KBK Not used currently
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000299# def saved_change_hook(self):
300# "Extend base method - clear breaks if module is modified"
301# if not self.get_saved():
302# self.clear_file_breaks()
303# EditorWindow.saved_change_hook(self)
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000304
305 def _close(self):
306 "Extend base method - clear breaks when module is closed"
307 self.clear_file_breaks()
308 EditorWindow._close(self)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000309
David Scherer7aced172000-08-15 01:13:23 +0000310
311class PyShellFileList(FileList):
Kurt B. Kaiser183403a2004-08-22 05:14:32 +0000312 "Extend base class: IDLE supports a shell and breakpoints"
David Scherer7aced172000-08-15 01:13:23 +0000313
Kurt B. Kaiser183403a2004-08-22 05:14:32 +0000314 # override FileList's class variable, instances return PyShellEditorWindow
315 # instead of EditorWindow when new edit windows are created.
David Scherer7aced172000-08-15 01:13:23 +0000316 EditorWindow = PyShellEditorWindow
317
318 pyshell = None
319
320 def open_shell(self, event=None):
321 if self.pyshell:
Kurt B. Kaiser183403a2004-08-22 05:14:32 +0000322 self.pyshell.top.wakeup()
David Scherer7aced172000-08-15 01:13:23 +0000323 else:
324 self.pyshell = PyShell(self)
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000325 if self.pyshell:
326 if not self.pyshell.begin():
327 return None
David Scherer7aced172000-08-15 01:13:23 +0000328 return self.pyshell
329
330
331class ModifiedColorDelegator(ColorDelegator):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000332 "Extend base class: colorizer for the shell window itself"
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000333
Steven M. Gavab77d3432002-03-02 07:16:21 +0000334 def __init__(self):
335 ColorDelegator.__init__(self)
336 self.LoadTagDefs()
David Scherer7aced172000-08-15 01:13:23 +0000337
338 def recolorize_main(self):
339 self.tag_remove("TODO", "1.0", "iomark")
340 self.tag_add("SYNC", "1.0", "iomark")
341 ColorDelegator.recolorize_main(self)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000342
Steven M. Gavab77d3432002-03-02 07:16:21 +0000343 def LoadTagDefs(self):
344 ColorDelegator.LoadTagDefs(self)
345 theme = idleConf.GetOption('main','Theme','name')
346 self.tagdefs.update({
347 "stdin": {'background':None,'foreground':None},
348 "stdout": idleConf.GetHighlight(theme, "stdout"),
349 "stderr": idleConf.GetHighlight(theme, "stderr"),
350 "console": idleConf.GetHighlight(theme, "console"),
Steven M. Gavab77d3432002-03-02 07:16:21 +0000351 })
David Scherer7aced172000-08-15 01:13:23 +0000352
Ned Deily5e247b72012-05-31 09:17:29 -0700353 def removecolors(self):
354 # Don't remove shell color tags before "iomark"
355 for tag in self.tagdefs:
356 self.tag_remove(tag, "iomark", "end")
357
David Scherer7aced172000-08-15 01:13:23 +0000358class ModifiedUndoDelegator(UndoDelegator):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000359 "Extend base class: forbid insert/delete before the I/O mark"
David Scherer7aced172000-08-15 01:13:23 +0000360
361 def insert(self, index, chars, tags=None):
362 try:
363 if self.delegate.compare(index, "<", "iomark"):
364 self.delegate.bell()
365 return
366 except TclError:
367 pass
368 UndoDelegator.insert(self, index, chars, tags)
369
370 def delete(self, index1, index2=None):
371 try:
372 if self.delegate.compare(index1, "<", "iomark"):
373 self.delegate.bell()
374 return
375 except TclError:
376 pass
377 UndoDelegator.delete(self, index1, index2)
378
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000379
380class MyRPCClient(rpc.RPCClient):
381
382 def handle_EOF(self):
383 "Override the base class - just re-raise EOFError"
384 raise EOFError
385
Kurt B. Kaiser8d1f11b2003-05-26 22:20:34 +0000386
David Scherer7aced172000-08-15 01:13:23 +0000387class ModifiedInterpreter(InteractiveInterpreter):
388
389 def __init__(self, tkconsole):
390 self.tkconsole = tkconsole
391 locals = sys.modules['__main__'].__dict__
392 InteractiveInterpreter.__init__(self, locals=locals)
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000393 self.save_warnings_filters = None
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000394 self.restarting = False
Kurt B. Kaiser013d6cc2009-04-04 07:03:48 +0000395 self.subprocess_arglist = None
396 self.port = PORT
Ned Deily86d669b2011-10-30 19:58:04 -0700397 self.original_compiler_flags = self.compile.compiler.flags
David Scherer7aced172000-08-15 01:13:23 +0000398
Roger Serwy16ce43a2013-06-11 22:13:17 -0500399 _afterid = None
Chui Tey5d2af632002-05-26 13:36:41 +0000400 rpcclt = None
401 rpcpid = None
402
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000403 def spawn_subprocess(self):
Florent Xiclunac8a730b2010-03-25 20:32:07 +0000404 if self.subprocess_arglist is None:
Kurt B. Kaiser013d6cc2009-04-04 07:03:48 +0000405 self.subprocess_arglist = self.build_subprocess_arglist()
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000406 args = self.subprocess_arglist
Kurt B. Kaiserb7855182003-08-14 14:54:28 +0000407 self.rpcpid = os.spawnv(os.P_NOWAIT, sys.executable, args)
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000408
Tony Lowndsf53dec22002-12-20 04:24:43 +0000409 def build_subprocess_arglist(self):
Kurt B. Kaiser013d6cc2009-04-04 07:03:48 +0000410 assert (self.port!=0), (
411 "Socket should have been assigned a port number.")
Tony Lownds2398d572003-05-13 15:28:21 +0000412 w = ['-W' + s for s in sys.warnoptions]
Georg Brandld0761532006-10-12 07:57:21 +0000413 if 1/2 > 0: # account for new division
414 w.append('-Qnew')
Tony Lownds2398d572003-05-13 15:28:21 +0000415 # Maybe IDLE is installed and is being accessed via sys.path,
416 # or maybe it's not installed and the idle.py script is being
417 # run from the IDLE source directory.
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000418 del_exitf = idleConf.GetOption('main', 'General', 'delete-exitfunc',
419 default=False, type='bool')
Tony Lownds2398d572003-05-13 15:28:21 +0000420 if __name__ == 'idlelib.PyShell':
Walter Dörwald70a6b492004-02-12 17:35:32 +0000421 command = "__import__('idlelib.run').run.main(%r)" % (del_exitf,)
Tony Lowndsf2324b92002-09-29 00:34:10 +0000422 else:
Walter Dörwald70a6b492004-02-12 17:35:32 +0000423 command = "__import__('run').main(%r)" % (del_exitf,)
Kurt B. Kaiserb7855182003-08-14 14:54:28 +0000424 if sys.platform[:3] == 'win' and ' ' in sys.executable:
425 # handle embedded space in path by quoting the argument
426 decorated_exec = '"%s"' % sys.executable
427 else:
428 decorated_exec = sys.executable
429 return [decorated_exec] + w + ["-c", command, str(self.port)]
Tony Lowndsf2324b92002-09-29 00:34:10 +0000430
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000431 def start_subprocess(self):
Kurt B. Kaiser013d6cc2009-04-04 07:03:48 +0000432 addr = (HOST, self.port)
433 # GUI makes several attempts to acquire socket, listens for connection
Kurt B. Kaiser5db48432003-05-15 03:40:51 +0000434 for i in range(3):
Chui Tey5d2af632002-05-26 13:36:41 +0000435 time.sleep(i)
436 try:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000437 self.rpcclt = MyRPCClient(addr)
Chui Tey5d2af632002-05-26 13:36:41 +0000438 break
Terry Jan Reedy2b149862013-06-29 00:59:34 -0400439 except socket.error as err:
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000440 pass
Chui Tey5d2af632002-05-26 13:36:41 +0000441 else:
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000442 self.display_port_binding_error()
443 return None
Kurt B. Kaiser013d6cc2009-04-04 07:03:48 +0000444 # if PORT was 0, system will assign an 'ephemeral' port. Find it out:
445 self.port = self.rpcclt.listening_sock.getsockname()[1]
446 # if PORT was not 0, probably working with a remote execution server
447 if PORT != 0:
448 # To allow reconnection within the 2MSL wait (cf. Stevens TCP
449 # V1, 18.6), set SO_REUSEADDR. Note that this can be problematic
450 # on Windows since the implementation allows two active sockets on
451 # the same address!
452 self.rpcclt.listening_sock.setsockopt(socket.SOL_SOCKET,
453 socket.SO_REUSEADDR, 1)
454 self.spawn_subprocess()
455 #time.sleep(20) # test to simulate GUI not accepting connection
Kurt B. Kaiserb4179362002-07-26 00:06:42 +0000456 # Accept the connection from the Python execution server
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000457 self.rpcclt.listening_sock.settimeout(10)
458 try:
459 self.rpcclt.accept()
Terry Jan Reedy2b149862013-06-29 00:59:34 -0400460 except socket.timeout as err:
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000461 self.display_no_subprocess_error()
462 return None
Serhiy Storchaka9abc8302013-01-25 15:30:35 +0200463 self.rpcclt.register("console", self.tkconsole)
464 self.rpcclt.register("stdin", self.tkconsole.stdin)
Kurt B. Kaiser969de452002-06-12 03:28:57 +0000465 self.rpcclt.register("stdout", self.tkconsole.stdout)
466 self.rpcclt.register("stderr", self.tkconsole.stderr)
Chui Tey5d2af632002-05-26 13:36:41 +0000467 self.rpcclt.register("flist", self.tkconsole.flist)
Kurt B. Kaiser8cd0def2003-01-31 05:06:43 +0000468 self.rpcclt.register("linecache", linecache)
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000469 self.rpcclt.register("interp", self)
Terry Jan Reedyb98000a2012-01-31 02:09:25 -0500470 self.transfer_path(with_cwd=True)
Chui Tey5d2af632002-05-26 13:36:41 +0000471 self.poll_subprocess()
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000472 return self.rpcclt
Chui Tey5d2af632002-05-26 13:36:41 +0000473
Terry Jan Reedyb98000a2012-01-31 02:09:25 -0500474 def restart_subprocess(self, with_cwd=False):
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000475 if self.restarting:
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000476 return self.rpcclt
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000477 self.restarting = True
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000478 # close only the subprocess debugger
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000479 debug = self.getdebugger()
480 if debug:
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000481 try:
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000482 # Only close subprocess debugger, don't unregister gui_adap!
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000483 RemoteDebugger.close_subprocess_debugger(self.rpcclt)
484 except:
485 pass
486 # Kill subprocess, spawn a new one, accept connection.
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000487 self.rpcclt.close()
488 self.unix_terminate()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000489 console = self.tkconsole
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000490 was_executing = console.executing
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000491 console.executing = False
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000492 self.spawn_subprocess()
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000493 try:
494 self.rpcclt.accept()
Terry Jan Reedy2b149862013-06-29 00:59:34 -0400495 except socket.timeout as err:
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000496 self.display_no_subprocess_error()
497 return None
Terry Jan Reedyb98000a2012-01-31 02:09:25 -0500498 self.transfer_path(with_cwd=with_cwd)
Roger Serwyad8cad32013-04-03 00:42:24 -0500499 console.stop_readline()
Kurt B. Kaiser1061e722003-01-04 01:43:53 +0000500 # annotate restart in shell window and mark it
Kurt B. Kaiser4cc5ef52003-01-22 00:23:23 +0000501 console.text.delete("iomark", "end-1c")
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000502 if was_executing:
503 console.write('\n')
504 console.showprompt()
Kurt B. Kaiser1061e722003-01-04 01:43:53 +0000505 halfbar = ((int(console.width) - 16) // 2) * '='
506 console.write(halfbar + ' RESTART ' + halfbar)
507 console.text.mark_set("restart", "end-1c")
508 console.text.mark_gravity("restart", "left")
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000509 console.showprompt()
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000510 # restart subprocess debugger
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000511 if debug:
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000512 # Restarted debugger connects to current instance of debug GUI
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000513 gui = RemoteDebugger.restart_subprocess_debugger(self.rpcclt)
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000514 # reload remote debugger breakpoints for all PyShellEditWindows
515 debug.load_breakpoints()
Ned Deily86d669b2011-10-30 19:58:04 -0700516 self.compile.compiler.flags = self.original_compiler_flags
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000517 self.restarting = False
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000518 return self.rpcclt
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000519
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000520 def __request_interrupt(self):
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000521 self.rpcclt.remotecall("exec", "interrupt_the_server", (), {})
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000522
523 def interrupt_subprocess(self):
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000524 threading.Thread(target=self.__request_interrupt).start()
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000525
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000526 def kill_subprocess(self):
Roger Serwy16ce43a2013-06-11 22:13:17 -0500527 if self._afterid is not None:
528 self.tkconsole.text.after_cancel(self._afterid)
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000529 try:
530 self.rpcclt.close()
531 except AttributeError: # no socket
532 pass
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000533 self.unix_terminate()
534 self.tkconsole.executing = False
535 self.rpcclt = None
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000536
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000537 def unix_terminate(self):
538 "UNIX: make sure subprocess is terminated and collect status"
539 if hasattr(os, 'kill'):
540 try:
541 os.kill(self.rpcpid, SIGTERM)
542 except OSError:
543 # process already terminated:
544 return
545 else:
546 try:
547 os.waitpid(self.rpcpid, 0)
548 except OSError:
549 return
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000550
Terry Jan Reedyb98000a2012-01-31 02:09:25 -0500551 def transfer_path(self, with_cwd=False):
552 if with_cwd: # Issue 13506
553 path = [''] # include Current Working Directory
554 path.extend(sys.path)
555 else:
556 path = sys.path
Terry Jan Reedy1d4ae482012-01-31 02:55:32 -0500557
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000558 self.runcommand("""if 1:
559 import sys as _sys
Walter Dörwald70a6b492004-02-12 17:35:32 +0000560 _sys.path = %r
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000561 del _sys
Terry Jan Reedyb98000a2012-01-31 02:09:25 -0500562 \n""" % (path,))
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000563
Chui Tey5d2af632002-05-26 13:36:41 +0000564 active_seq = None
565
566 def poll_subprocess(self):
567 clt = self.rpcclt
568 if clt is None:
569 return
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000570 try:
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000571 response = clt.pollresponse(self.active_seq, wait=0.05)
572 except (EOFError, IOError, KeyboardInterrupt):
573 # lost connection or subprocess terminated itself, restart
574 # [the KBI is from rpc.SocketIO.handle_EOF()]
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000575 if self.tkconsole.closing:
576 return
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000577 response = None
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000578 self.restart_subprocess()
Chui Tey5d2af632002-05-26 13:36:41 +0000579 if response:
580 self.tkconsole.resetoutput()
581 self.active_seq = None
582 how, what = response
Kurt B. Kaiserbc286132003-01-25 21:33:40 +0000583 console = self.tkconsole.console
Chui Tey5d2af632002-05-26 13:36:41 +0000584 if how == "OK":
585 if what is not None:
Terry Jan Reedybee003c2014-09-19 22:37:24 -0400586 print(repr(what), file=console)
Chui Tey5d2af632002-05-26 13:36:41 +0000587 elif how == "EXCEPTION":
Chui Tey5d2af632002-05-26 13:36:41 +0000588 if self.tkconsole.getvar("<<toggle-jit-stack-viewer>>"):
589 self.remote_stack_viewer()
590 elif how == "ERROR":
Kurt B. Kaiser0930c432002-12-06 21:45:24 +0000591 errmsg = "PyShell.ModifiedInterpreter: Subprocess ERROR:\n"
Terry Jan Reedybee003c2014-09-19 22:37:24 -0400592 print(errmsg, what, file=sys.__stderr__)
593 print(errmsg, what, file=console)
Kurt B. Kaiserbc286132003-01-25 21:33:40 +0000594 # we received a response to the currently active seq number:
Kurt B. Kaiserd112bc72006-08-16 05:01:42 +0000595 try:
596 self.tkconsole.endexecuting()
597 except AttributeError: # shell may have closed
598 pass
Kurt B. Kaiser88957d82003-05-19 23:11:51 +0000599 # Reschedule myself
600 if not self.tkconsole.closing:
Roger Serwy16ce43a2013-06-11 22:13:17 -0500601 self._afterid = self.tkconsole.text.after(
602 self.tkconsole.pollinterval, self.poll_subprocess)
Chui Tey5d2af632002-05-26 13:36:41 +0000603
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000604 debugger = None
605
606 def setdebugger(self, debugger):
607 self.debugger = debugger
608
609 def getdebugger(self):
610 return self.debugger
611
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000612 def open_remote_stack_viewer(self):
613 """Initiate the remote stack viewer from a separate thread.
614
615 This method is called from the subprocess, and by returning from this
616 method we allow the subprocess to unblock. After a bit the shell
617 requests the subprocess to open the remote stack viewer which returns a
Ezio Melottic569cfe2010-07-23 16:55:21 +0000618 static object looking at the last exception. It is queried through
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000619 the RPC mechanism.
620
621 """
622 self.tkconsole.text.after(300, self.remote_stack_viewer)
623 return
624
Chui Tey5d2af632002-05-26 13:36:41 +0000625 def remote_stack_viewer(self):
Florent Xiclunad630c042010-04-02 07:24:52 +0000626 from idlelib import RemoteObjectBrowser
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000627 oid = self.rpcclt.remotequeue("exec", "stackviewer", ("flist",), {})
Chui Tey5d2af632002-05-26 13:36:41 +0000628 if oid is None:
629 self.tkconsole.root.bell()
630 return
631 item = RemoteObjectBrowser.StubObjectTreeItem(self.rpcclt, oid)
Florent Xiclunad630c042010-04-02 07:24:52 +0000632 from idlelib.TreeWidget import ScrolledCanvas, TreeNode
Chui Tey5d2af632002-05-26 13:36:41 +0000633 top = Toplevel(self.tkconsole.root)
Kurt B. Kaiser73360a32004-03-08 18:15:31 +0000634 theme = idleConf.GetOption('main','Theme','name')
635 background = idleConf.GetHighlight(theme, 'normal')['background']
636 sc = ScrolledCanvas(top, bg=background, highlightthickness=0)
Chui Tey5d2af632002-05-26 13:36:41 +0000637 sc.frame.pack(expand=1, fill="both")
638 node = TreeNode(sc.canvas, None, item)
639 node.expand()
640 # XXX Should GC the remote tree when closing the window
641
David Scherer7aced172000-08-15 01:13:23 +0000642 gid = 0
643
644 def execsource(self, source):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000645 "Like runsource() but assumes complete exec source"
David Scherer7aced172000-08-15 01:13:23 +0000646 filename = self.stuffsource(source)
647 self.execfile(filename, source)
648
649 def execfile(self, filename, source=None):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000650 "Execute an existing file"
David Scherer7aced172000-08-15 01:13:23 +0000651 if source is None:
652 source = open(filename, "r").read()
653 try:
654 code = compile(source, filename, "exec")
655 except (OverflowError, SyntaxError):
656 self.tkconsole.resetoutput()
Terry Jan Reedybee003c2014-09-19 22:37:24 -0400657 print('*** Error in script or command!\n'
658 'Traceback (most recent call last):',
659 file=self.tkconsole.stderr)
David Scherer7aced172000-08-15 01:13:23 +0000660 InteractiveInterpreter.showsyntaxerror(self, filename)
Kurt B. Kaiser6e44cc22002-11-30 06:18:00 +0000661 self.tkconsole.showprompt()
David Scherer7aced172000-08-15 01:13:23 +0000662 else:
663 self.runcode(code)
664
665 def runsource(self, source):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000666 "Extend base class method: Stuff the source in the line cache first"
David Scherer7aced172000-08-15 01:13:23 +0000667 filename = self.stuffsource(source)
668 self.more = 0
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000669 self.save_warnings_filters = warnings.filters[:]
670 warnings.filterwarnings(action="error", category=SyntaxWarning)
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +0000671 if isinstance(source, types.UnicodeType):
Florent Xiclunad630c042010-04-02 07:24:52 +0000672 from idlelib import IOBinding
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +0000673 try:
674 source = source.encode(IOBinding.encoding)
675 except UnicodeError:
676 self.tkconsole.resetoutput()
Kurt B. Kaisercd3d8be2006-08-10 17:11:09 +0000677 self.write("Unsupported characters in input\n")
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +0000678 return
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000679 try:
Kurt B. Kaiser935ea9a2005-05-10 03:44:24 +0000680 # InteractiveInterpreter.runsource() calls its runcode() method,
681 # which is overridden (see below)
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000682 return InteractiveInterpreter.runsource(self, source, filename)
683 finally:
684 if self.save_warnings_filters is not None:
685 warnings.filters[:] = self.save_warnings_filters
686 self.save_warnings_filters = None
David Scherer7aced172000-08-15 01:13:23 +0000687
688 def stuffsource(self, source):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000689 "Stuff source in the filename cache"
David Scherer7aced172000-08-15 01:13:23 +0000690 filename = "<pyshell#%d>" % self.gid
691 self.gid = self.gid + 1
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +0000692 lines = source.split("\n")
David Scherer7aced172000-08-15 01:13:23 +0000693 linecache.cache[filename] = len(source)+1, 0, lines, filename
694 return filename
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000695
Kurt B. Kaiser11659ad2003-05-15 23:23:21 +0000696 def prepend_syspath(self, filename):
697 "Prepend sys.path with file's directory if not already included"
698 self.runcommand("""if 1:
Walter Dörwald70a6b492004-02-12 17:35:32 +0000699 _filename = %r
Kurt B. Kaiser11659ad2003-05-15 23:23:21 +0000700 import sys as _sys
701 from os.path import dirname as _dirname
702 _dir = _dirname(_filename)
703 if not _dir in _sys.path:
704 _sys.path.insert(0, _dir)
705 del _filename, _sys, _dirname, _dir
Walter Dörwald70a6b492004-02-12 17:35:32 +0000706 \n""" % (filename,))
Kurt B. Kaiser11659ad2003-05-15 23:23:21 +0000707
David Scherer7aced172000-08-15 01:13:23 +0000708 def showsyntaxerror(self, filename=None):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000709 """Extend base class method: Add Colorizing
710
711 Color the offending position instead of printing it and pointing at it
712 with a caret.
713
714 """
David Scherer7aced172000-08-15 01:13:23 +0000715 text = self.tkconsole.text
716 stuff = self.unpackerror()
Kurt B. Kaiser6e44cc22002-11-30 06:18:00 +0000717 if stuff:
718 msg, lineno, offset, line = stuff
719 if lineno == 1:
720 pos = "iomark + %d chars" % (offset-1)
721 else:
722 pos = "iomark linestart + %d lines + %d chars" % \
723 (lineno-1, offset-1)
724 text.tag_add("ERROR", pos)
725 text.see(pos)
726 char = text.get(pos)
727 if char and char in IDENTCHARS:
728 text.tag_add("ERROR", pos + " wordstart", pos)
729 self.tkconsole.resetoutput()
730 self.write("SyntaxError: %s\n" % str(msg))
731 else:
David Scherer7aced172000-08-15 01:13:23 +0000732 self.tkconsole.resetoutput()
733 InteractiveInterpreter.showsyntaxerror(self, filename)
Kurt B. Kaiser6e44cc22002-11-30 06:18:00 +0000734 self.tkconsole.showprompt()
David Scherer7aced172000-08-15 01:13:23 +0000735
736 def unpackerror(self):
737 type, value, tb = sys.exc_info()
738 ok = type is SyntaxError
739 if ok:
740 try:
741 msg, (dummy_filename, lineno, offset, line) = value
Kurt B. Kaiserbea57c62003-07-09 04:27:24 +0000742 if not offset:
743 offset = 0
David Scherer7aced172000-08-15 01:13:23 +0000744 except:
745 ok = 0
746 if ok:
747 return msg, lineno, offset, line
748 else:
749 return None
750
751 def showtraceback(self):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000752 "Extend base class method to reset output properly"
David Scherer7aced172000-08-15 01:13:23 +0000753 self.tkconsole.resetoutput()
754 self.checklinecache()
755 InteractiveInterpreter.showtraceback(self)
Chui Tey5d2af632002-05-26 13:36:41 +0000756 if self.tkconsole.getvar("<<toggle-jit-stack-viewer>>"):
757 self.tkconsole.open_stack_viewer()
David Scherer7aced172000-08-15 01:13:23 +0000758
759 def checklinecache(self):
760 c = linecache.cache
761 for key in c.keys():
762 if key[:1] + key[-1:] != "<>":
763 del c[key]
764
Chui Tey5d2af632002-05-26 13:36:41 +0000765 def runcommand(self, code):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000766 "Run the code without invoking the debugger"
Chui Tey5d2af632002-05-26 13:36:41 +0000767 # The code better not raise an exception!
768 if self.tkconsole.executing:
Neal Norwitzf4c4f112002-11-30 18:49:10 +0000769 self.display_executing_dialog()
Chui Tey5d2af632002-05-26 13:36:41 +0000770 return 0
771 if self.rpcclt:
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000772 self.rpcclt.remotequeue("exec", "runcode", (code,), {})
Chui Tey5d2af632002-05-26 13:36:41 +0000773 else:
774 exec code in self.locals
775 return 1
776
David Scherer7aced172000-08-15 01:13:23 +0000777 def runcode(self, code):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000778 "Override base class method"
Chui Tey5d2af632002-05-26 13:36:41 +0000779 if self.tkconsole.executing:
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000780 self.interp.restart_subprocess()
Chui Tey5d2af632002-05-26 13:36:41 +0000781 self.checklinecache()
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000782 if self.save_warnings_filters is not None:
783 warnings.filters[:] = self.save_warnings_filters
784 self.save_warnings_filters = None
David Scherer7aced172000-08-15 01:13:23 +0000785 debugger = self.debugger
786 try:
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000787 self.tkconsole.beginexecuting()
Kurt B. Kaiserdddeb0e2007-02-06 03:21:40 +0000788 if not debugger and self.rpcclt is not None:
789 self.active_seq = self.rpcclt.asyncqueue("exec", "runcode",
790 (code,), {})
791 elif debugger:
792 debugger.run(code, self.locals)
793 else:
794 exec code in self.locals
795 except SystemExit:
796 if not self.tkconsole.closing:
797 if tkMessageBox.askyesno(
798 "Exit?",
799 "Do you want to exit altogether?",
800 default="yes",
801 master=self.tkconsole.text):
Kurt B. Kaiserf137e1d2006-08-16 07:04:17 +0000802 raise
Kurt B. Kaiserdddeb0e2007-02-06 03:21:40 +0000803 else:
804 self.showtraceback()
805 else:
806 raise
807 except:
808 if use_subprocess:
Terry Jan Reedybee003c2014-09-19 22:37:24 -0400809 print("IDLE internal error in runcode()",
810 file=self.tkconsole.stderr)
David Scherer7aced172000-08-15 01:13:23 +0000811 self.showtraceback()
Kurt B. Kaiserdddeb0e2007-02-06 03:21:40 +0000812 self.tkconsole.endexecuting()
813 else:
814 if self.tkconsole.canceled:
815 self.tkconsole.canceled = False
Terry Jan Reedybee003c2014-09-19 22:37:24 -0400816 print("KeyboardInterrupt", file=self.tkconsole.stderr)
Kurt B. Kaiserdddeb0e2007-02-06 03:21:40 +0000817 else:
818 self.showtraceback()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000819 finally:
820 if not use_subprocess:
Kurt B. Kaiserd112bc72006-08-16 05:01:42 +0000821 try:
822 self.tkconsole.endexecuting()
823 except AttributeError: # shell may have closed
824 pass
David Scherer7aced172000-08-15 01:13:23 +0000825
826 def write(self, s):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000827 "Override base class method"
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000828 self.tkconsole.stderr.write(s)
David Scherer7aced172000-08-15 01:13:23 +0000829
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000830 def display_port_binding_error(self):
831 tkMessageBox.showerror(
832 "Port Binding Error",
Kurt B. Kaiser013d6cc2009-04-04 07:03:48 +0000833 "IDLE can't bind to a TCP/IP port, which is necessary to "
834 "communicate with its Python execution server. This might be "
835 "because no networking is installed on this computer. "
836 "Run IDLE with the -n command line switch to start without a "
837 "subprocess and refer to Help/IDLE Help 'Running without a "
838 "subprocess' for further details.",
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000839 master=self.tkconsole.text)
840
841 def display_no_subprocess_error(self):
842 tkMessageBox.showerror(
843 "Subprocess Startup Error",
844 "IDLE's subprocess didn't make connection. Either IDLE can't "
845 "start a subprocess or personal firewall software is blocking "
846 "the connection.",
847 master=self.tkconsole.text)
848
849 def display_executing_dialog(self):
850 tkMessageBox.showerror(
851 "Already executing",
852 "The Python Shell window is already executing a command; "
853 "please wait until it is finished.",
854 master=self.tkconsole.text)
855
856
David Scherer7aced172000-08-15 01:13:23 +0000857class PyShell(OutputWindow):
858
Terry Jan Reedyd676a3a2013-03-30 18:50:43 -0400859 shell_title = "Python " + python_version() + " Shell"
David Scherer7aced172000-08-15 01:13:23 +0000860
861 # Override classes
862 ColorDelegator = ModifiedColorDelegator
863 UndoDelegator = ModifiedUndoDelegator
864
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000865 # Override menus
Kurt B. Kaiserdc1e7092002-07-11 04:33:41 +0000866 menu_specs = [
867 ("file", "_File"),
868 ("edit", "_Edit"),
Kurt B. Kaiser4cc5ef52003-01-22 00:23:23 +0000869 ("debug", "_Debug"),
Kurt B. Kaiser1061e722003-01-04 01:43:53 +0000870 ("options", "_Options"),
Kurt B. Kaiserdc1e7092002-07-11 04:33:41 +0000871 ("windows", "_Windows"),
872 ("help", "_Help"),
873 ]
David Scherer7aced172000-08-15 01:13:23 +0000874
Ned Deily57847df2014-03-27 20:47:04 -0700875 if sys.platform == "darwin":
Ronald Oussoren19302d92006-06-11 14:33:36 +0000876 menu_specs[-2] = ("windows", "_Window")
877
878
David Scherer7aced172000-08-15 01:13:23 +0000879 # New classes
Florent Xiclunad630c042010-04-02 07:24:52 +0000880 from idlelib.IdleHistory import History
David Scherer7aced172000-08-15 01:13:23 +0000881
882 def __init__(self, flist=None):
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +0000883 if use_subprocess:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000884 ms = self.menu_specs
885 if ms[2][0] != "shell":
Kurt B. Kaiser7ae35482006-08-16 21:45:59 +0000886 ms.insert(2, ("shell", "She_ll"))
David Scherer7aced172000-08-15 01:13:23 +0000887 self.interp = ModifiedInterpreter(self)
888 if flist is None:
889 root = Tk()
890 fixwordbreaks(root)
891 root.withdraw()
892 flist = PyShellFileList(root)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000893 #
David Scherer7aced172000-08-15 01:13:23 +0000894 OutputWindow.__init__(self, flist, None, None)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000895 #
Kurt B. Kaiser6af44982005-01-19 00:22:59 +0000896## self.config(usetabs=1, indentwidth=8, context_use_ps1=1)
897 self.usetabs = True
898 # indentwidth must be 8 when using tabs. See note in EditorWindow:
899 self.indentwidth = 8
900 self.context_use_ps1 = True
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000901 #
David Scherer7aced172000-08-15 01:13:23 +0000902 text = self.text
903 text.configure(wrap="char")
904 text.bind("<<newline-and-indent>>", self.enter_callback)
905 text.bind("<<plain-newline-and-indent>>", self.linefeed_callback)
906 text.bind("<<interrupt-execution>>", self.cancel_callback)
David Scherer7aced172000-08-15 01:13:23 +0000907 text.bind("<<end-of-file>>", self.eof_callback)
908 text.bind("<<open-stack-viewer>>", self.open_stack_viewer)
Kurt B. Kaiser57bfe5d2003-05-10 00:09:52 +0000909 text.bind("<<toggle-debugger>>", self.toggle_debugger)
David Scherer7aced172000-08-15 01:13:23 +0000910 text.bind("<<toggle-jit-stack-viewer>>", self.toggle_jit_stack_viewer)
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +0000911 if use_subprocess:
912 text.bind("<<view-restart>>", self.view_restart_mark)
913 text.bind("<<restart-shell>>", self.restart_shell)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000914 #
David Scherer7aced172000-08-15 01:13:23 +0000915 self.save_stdout = sys.stdout
916 self.save_stderr = sys.stderr
917 self.save_stdin = sys.stdin
Florent Xiclunad630c042010-04-02 07:24:52 +0000918 from idlelib import IOBinding
Serhiy Storchaka9abc8302013-01-25 15:30:35 +0200919 self.stdin = PseudoInputFile(self, "stdin", IOBinding.encoding)
920 self.stdout = PseudoOutputFile(self, "stdout", IOBinding.encoding)
921 self.stderr = PseudoOutputFile(self, "stderr", IOBinding.encoding)
922 self.console = PseudoOutputFile(self, "console", IOBinding.encoding)
Chui Tey5d2af632002-05-26 13:36:41 +0000923 if not use_subprocess:
924 sys.stdout = self.stdout
925 sys.stderr = self.stderr
Martin v. Löwise2b56242012-07-25 10:56:22 +0200926 sys.stdin = self.stdin
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000927 #
David Scherer7aced172000-08-15 01:13:23 +0000928 self.history = self.History(self.text)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000929 #
Kurt B. Kaiser88957d82003-05-19 23:11:51 +0000930 self.pollinterval = 50 # millisec
Chui Tey5d2af632002-05-26 13:36:41 +0000931
Kurt B. Kaiser4d5bc602004-06-06 01:29:22 +0000932 def get_standard_extension_names(self):
933 return idleConf.GetExtensions(shell_only=True)
934
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000935 reading = False
936 executing = False
937 canceled = False
938 endoffile = False
939 closing = False
Roger Serwyad8cad32013-04-03 00:42:24 -0500940 _stop_readline_flag = False
David Scherer7aced172000-08-15 01:13:23 +0000941
Kurt B. Kaiser49a5fe12004-07-04 01:25:56 +0000942 def set_warning_stream(self, stream):
Skip Montanarod9161422004-07-06 21:53:27 +0000943 global warning_stream
944 warning_stream = stream
Kurt B. Kaiser49a5fe12004-07-04 01:25:56 +0000945
946 def get_warning_stream(self):
947 return warning_stream
948
David Scherer7aced172000-08-15 01:13:23 +0000949 def toggle_debugger(self, event=None):
950 if self.executing:
951 tkMessageBox.showerror("Don't debug now",
952 "You can only toggle the debugger when idle",
953 master=self.text)
954 self.set_debugger_indicator()
955 return "break"
956 else:
957 db = self.interp.getdebugger()
958 if db:
959 self.close_debugger()
960 else:
961 self.open_debugger()
962
963 def set_debugger_indicator(self):
964 db = self.interp.getdebugger()
965 self.setvar("<<toggle-debugger>>", not not db)
966
Kurt B. Kaiser1061e722003-01-04 01:43:53 +0000967 def toggle_jit_stack_viewer(self, event=None):
David Scherer7aced172000-08-15 01:13:23 +0000968 pass # All we need is the variable
969
970 def close_debugger(self):
971 db = self.interp.getdebugger()
972 if db:
973 self.interp.setdebugger(None)
974 db.close()
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000975 if self.interp.rpcclt:
976 RemoteDebugger.close_remote_debugger(self.interp.rpcclt)
David Scherer7aced172000-08-15 01:13:23 +0000977 self.resetoutput()
978 self.console.write("[DEBUG OFF]\n")
979 sys.ps1 = ">>> "
980 self.showprompt()
981 self.set_debugger_indicator()
982
983 def open_debugger(self):
Chui Tey5d2af632002-05-26 13:36:41 +0000984 if self.interp.rpcclt:
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000985 dbg_gui = RemoteDebugger.start_remote_debugger(self.interp.rpcclt,
986 self)
987 else:
988 dbg_gui = Debugger.Debugger(self)
989 self.interp.setdebugger(dbg_gui)
990 dbg_gui.load_breakpoints()
Chui Tey5d2af632002-05-26 13:36:41 +0000991 sys.ps1 = "[DEBUG ON]\n>>> "
992 self.showprompt()
993 self.set_debugger_indicator()
994
David Scherer7aced172000-08-15 01:13:23 +0000995 def beginexecuting(self):
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000996 "Helper for ModifiedInterpreter"
David Scherer7aced172000-08-15 01:13:23 +0000997 self.resetoutput()
998 self.executing = 1
David Scherer7aced172000-08-15 01:13:23 +0000999
1000 def endexecuting(self):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +00001001 "Helper for ModifiedInterpreter"
David Scherer7aced172000-08-15 01:13:23 +00001002 self.executing = 0
1003 self.canceled = 0
Chui Tey5d2af632002-05-26 13:36:41 +00001004 self.showprompt()
David Scherer7aced172000-08-15 01:13:23 +00001005
1006 def close(self):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +00001007 "Extend EditorWindow.close()"
David Scherer7aced172000-08-15 01:13:23 +00001008 if self.executing:
Kurt B. Kaiser003091c2003-02-17 18:57:16 +00001009 response = tkMessageBox.askokcancel(
David Scherer7aced172000-08-15 01:13:23 +00001010 "Kill?",
Kurt B. Kaiser003091c2003-02-17 18:57:16 +00001011 "The program is still running!\n Do you want to kill it?",
David Scherer7aced172000-08-15 01:13:23 +00001012 default="ok",
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +00001013 parent=self.text)
Benjamin Peterson5b63acd2008-03-29 15:24:25 +00001014 if response is False:
David Scherer7aced172000-08-15 01:13:23 +00001015 return "cancel"
Roger Serwyad8cad32013-04-03 00:42:24 -05001016 self.stop_readline()
Kurt B. Kaiser5c3df352004-12-23 04:20:59 +00001017 self.canceled = True
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +00001018 self.closing = True
Kurt B. Kaiser88957d82003-05-19 23:11:51 +00001019 return EditorWindow.close(self)
David Scherer7aced172000-08-15 01:13:23 +00001020
1021 def _close(self):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +00001022 "Extend EditorWindow._close(), shut down debugger and execution server"
David Scherer7aced172000-08-15 01:13:23 +00001023 self.close_debugger()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +00001024 if use_subprocess:
1025 self.interp.kill_subprocess()
David Scherer7aced172000-08-15 01:13:23 +00001026 # Restore std streams
1027 sys.stdout = self.save_stdout
1028 sys.stderr = self.save_stderr
1029 sys.stdin = self.save_stdin
1030 # Break cycles
1031 self.interp = None
1032 self.console = None
David Scherer7aced172000-08-15 01:13:23 +00001033 self.flist.pyshell = None
1034 self.history = None
Kurt B. Kaiser83118c62002-06-24 17:03:37 +00001035 EditorWindow._close(self)
David Scherer7aced172000-08-15 01:13:23 +00001036
1037 def ispythonsource(self, filename):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +00001038 "Override EditorWindow method: never remove the colorizer"
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +00001039 return True
David Scherer7aced172000-08-15 01:13:23 +00001040
1041 def short_title(self):
1042 return self.shell_title
1043
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +00001044 COPYRIGHT = \
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001045 'Type "copyright", "credits" or "license()" for more information.'
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +00001046
David Scherer7aced172000-08-15 01:13:23 +00001047 def begin(self):
1048 self.resetoutput()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +00001049 if use_subprocess:
1050 nosub = ''
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +00001051 client = self.interp.start_subprocess()
1052 if not client:
1053 self.close()
Kurt B. Kaiser76637292004-01-21 22:10:01 +00001054 return False
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +00001055 else:
1056 nosub = "==== No Subprocess ===="
Raymond Hettingerbf3f69e2009-01-26 23:29:09 +00001057 self.write("Python %s on %s\n%s\n%s" %
1058 (sys.version, sys.platform, self.COPYRIGHT, nosub))
David Scherer7aced172000-08-15 01:13:23 +00001059 self.showprompt()
Georg Brandl6634bf22008-05-20 07:13:37 +00001060 import Tkinter
1061 Tkinter._default_root = None # 03Jan04 KBK What's this?
Kurt B. Kaiser76637292004-01-21 22:10:01 +00001062 return True
David Scherer7aced172000-08-15 01:13:23 +00001063
Roger Serwyad8cad32013-04-03 00:42:24 -05001064 def stop_readline(self):
1065 if not self.reading: # no nested mainloop to exit.
1066 return
1067 self._stop_readline_flag = True
1068 self.top.quit()
1069
David Scherer7aced172000-08-15 01:13:23 +00001070 def readline(self):
1071 save = self.reading
1072 try:
1073 self.reading = 1
Kurt B. Kaiser5c3df352004-12-23 04:20:59 +00001074 self.top.mainloop() # nested mainloop()
David Scherer7aced172000-08-15 01:13:23 +00001075 finally:
1076 self.reading = save
Roger Serwyad8cad32013-04-03 00:42:24 -05001077 if self._stop_readline_flag:
1078 self._stop_readline_flag = False
1079 return ""
David Scherer7aced172000-08-15 01:13:23 +00001080 line = self.text.get("iomark", "end-1c")
Kurt B. Kaiser5c3df352004-12-23 04:20:59 +00001081 if len(line) == 0: # may be EOF if we quit our mainloop with Ctrl-C
1082 line = "\n"
Martin v. Löwisbcc651a2003-06-22 07:52:56 +00001083 if isinstance(line, unicode):
Florent Xiclunad630c042010-04-02 07:24:52 +00001084 from idlelib import IOBinding
Martin v. Löwisbcc651a2003-06-22 07:52:56 +00001085 try:
1086 line = line.encode(IOBinding.encoding)
1087 except UnicodeError:
1088 pass
David Scherer7aced172000-08-15 01:13:23 +00001089 self.resetoutput()
1090 if self.canceled:
1091 self.canceled = 0
Kurt B. Kaiser5c3df352004-12-23 04:20:59 +00001092 if not use_subprocess:
1093 raise KeyboardInterrupt
David Scherer7aced172000-08-15 01:13:23 +00001094 if self.endoffile:
1095 self.endoffile = 0
Kurt B. Kaiser5c3df352004-12-23 04:20:59 +00001096 line = ""
David Scherer7aced172000-08-15 01:13:23 +00001097 return line
1098
1099 def isatty(self):
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +00001100 return True
David Scherer7aced172000-08-15 01:13:23 +00001101
Kurt B. Kaiser003091c2003-02-17 18:57:16 +00001102 def cancel_callback(self, event=None):
David Scherer7aced172000-08-15 01:13:23 +00001103 try:
1104 if self.text.compare("sel.first", "!=", "sel.last"):
1105 return # Active selection -- always use default binding
1106 except:
1107 pass
1108 if not (self.executing or self.reading):
1109 self.resetoutput()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +00001110 self.interp.write("KeyboardInterrupt\n")
David Scherer7aced172000-08-15 01:13:23 +00001111 self.showprompt()
1112 return "break"
1113 self.endoffile = 0
Kurt B. Kaiser003091c2003-02-17 18:57:16 +00001114 self.canceled = 1
Kurt B. Kaiser5c3df352004-12-23 04:20:59 +00001115 if (self.executing and self.interp.rpcclt):
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +00001116 if self.interp.getdebugger():
1117 self.interp.restart_subprocess()
1118 else:
1119 self.interp.interrupt_subprocess()
Kurt B. Kaiser5c3df352004-12-23 04:20:59 +00001120 if self.reading:
1121 self.top.quit() # exit the nested mainloop() in readline()
David Scherer7aced172000-08-15 01:13:23 +00001122 return "break"
1123
1124 def eof_callback(self, event):
1125 if self.executing and not self.reading:
1126 return # Let the default binding (delete next char) take over
1127 if not (self.text.compare("iomark", "==", "insert") and
1128 self.text.compare("insert", "==", "end-1c")):
1129 return # Let the default binding (delete next char) take over
1130 if not self.executing:
David Scherer7aced172000-08-15 01:13:23 +00001131 self.resetoutput()
1132 self.close()
1133 else:
1134 self.canceled = 0
1135 self.endoffile = 1
1136 self.top.quit()
1137 return "break"
1138
David Scherer7aced172000-08-15 01:13:23 +00001139 def linefeed_callback(self, event):
1140 # Insert a linefeed without entering anything (still autoindented)
1141 if self.reading:
1142 self.text.insert("insert", "\n")
1143 self.text.see("insert")
1144 else:
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +00001145 self.newline_and_indent_event(event)
David Scherer7aced172000-08-15 01:13:23 +00001146 return "break"
1147
1148 def enter_callback(self, event):
1149 if self.executing and not self.reading:
1150 return # Let the default binding (insert '\n') take over
1151 # If some text is selected, recall the selection
1152 # (but only if this before the I/O mark)
1153 try:
1154 sel = self.text.get("sel.first", "sel.last")
1155 if sel:
1156 if self.text.compare("sel.last", "<=", "iomark"):
Kurt B. Kaisera7daba62005-06-19 18:56:15 +00001157 self.recall(sel, event)
David Scherer7aced172000-08-15 01:13:23 +00001158 return "break"
1159 except:
1160 pass
1161 # If we're strictly before the line containing iomark, recall
1162 # the current line, less a leading prompt, less leading or
1163 # trailing whitespace
1164 if self.text.compare("insert", "<", "iomark linestart"):
1165 # Check if there's a relevant stdin range -- if so, use it
1166 prev = self.text.tag_prevrange("stdin", "insert")
1167 if prev and self.text.compare("insert", "<", prev[1]):
Kurt B. Kaisera7daba62005-06-19 18:56:15 +00001168 self.recall(self.text.get(prev[0], prev[1]), event)
David Scherer7aced172000-08-15 01:13:23 +00001169 return "break"
1170 next = self.text.tag_nextrange("stdin", "insert")
1171 if next and self.text.compare("insert lineend", ">=", next[0]):
Kurt B. Kaisera7daba62005-06-19 18:56:15 +00001172 self.recall(self.text.get(next[0], next[1]), event)
David Scherer7aced172000-08-15 01:13:23 +00001173 return "break"
Kurt B. Kaiser4ada7ad2002-12-29 22:03:38 +00001174 # No stdin mark -- just get the current line, less any prompt
Kurt B. Kaiserb1754452005-11-18 22:05:48 +00001175 indices = self.text.tag_nextrange("console", "insert linestart")
1176 if indices and \
1177 self.text.compare(indices[0], "<=", "insert linestart"):
1178 self.recall(self.text.get(indices[1], "insert lineend"), event)
1179 else:
1180 self.recall(self.text.get("insert linestart", "insert lineend"), event)
David Scherer7aced172000-08-15 01:13:23 +00001181 return "break"
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +00001182 # If we're between the beginning of the line and the iomark, i.e.
Kurt B. Kaiser4ada7ad2002-12-29 22:03:38 +00001183 # in the prompt area, move to the end of the prompt
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +00001184 if self.text.compare("insert", "<", "iomark"):
Kurt B. Kaiser4ada7ad2002-12-29 22:03:38 +00001185 self.text.mark_set("insert", "iomark")
David Scherer7aced172000-08-15 01:13:23 +00001186 # If we're in the current input and there's only whitespace
1187 # beyond the cursor, erase that whitespace first
1188 s = self.text.get("insert", "end-1c")
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +00001189 if s and not s.strip():
David Scherer7aced172000-08-15 01:13:23 +00001190 self.text.delete("insert", "end-1c")
1191 # If we're in the current input before its last line,
1192 # insert a newline right at the insert point
1193 if self.text.compare("insert", "<", "end-1c linestart"):
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +00001194 self.newline_and_indent_event(event)
David Scherer7aced172000-08-15 01:13:23 +00001195 return "break"
1196 # We're in the last line; append a newline and submit it
1197 self.text.mark_set("insert", "end-1c")
1198 if self.reading:
1199 self.text.insert("insert", "\n")
1200 self.text.see("insert")
1201 else:
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +00001202 self.newline_and_indent_event(event)
David Scherer7aced172000-08-15 01:13:23 +00001203 self.text.tag_add("stdin", "iomark", "end-1c")
1204 self.text.update_idletasks()
1205 if self.reading:
1206 self.top.quit() # Break out of recursive mainloop() in raw_input()
1207 else:
1208 self.runit()
1209 return "break"
1210
Kurt B. Kaisera7daba62005-06-19 18:56:15 +00001211 def recall(self, s, event):
Kurt B. Kaisercd3d8be2006-08-10 17:11:09 +00001212 # remove leading and trailing empty or whitespace lines
1213 s = re.sub(r'^\s*\n', '' , s)
1214 s = re.sub(r'\n\s*$', '', s)
1215 lines = s.split('\n')
Kurt B. Kaisera7daba62005-06-19 18:56:15 +00001216 self.text.undo_block_start()
1217 try:
1218 self.text.tag_remove("sel", "1.0", "end")
1219 self.text.mark_set("insert", "end-1c")
Kurt B. Kaisercd3d8be2006-08-10 17:11:09 +00001220 prefix = self.text.get("insert linestart", "insert")
1221 if prefix.rstrip().endswith(':'):
Kurt B. Kaiser8fa7eb52005-06-21 02:42:17 +00001222 self.newline_and_indent_event(event)
Kurt B. Kaisercd3d8be2006-08-10 17:11:09 +00001223 prefix = self.text.get("insert linestart", "insert")
1224 self.text.insert("insert", lines[0].strip())
Kurt B. Kaiser8fa7eb52005-06-21 02:42:17 +00001225 if len(lines) > 1:
Kurt B. Kaisercd3d8be2006-08-10 17:11:09 +00001226 orig_base_indent = re.search(r'^([ \t]*)', lines[0]).group(0)
1227 new_base_indent = re.search(r'^([ \t]*)', prefix).group(0)
Kurt B. Kaiser8fa7eb52005-06-21 02:42:17 +00001228 for line in lines[1:]:
Kurt B. Kaisercd3d8be2006-08-10 17:11:09 +00001229 if line.startswith(orig_base_indent):
1230 # replace orig base indentation with new indentation
1231 line = new_base_indent + line[len(orig_base_indent):]
1232 self.text.insert('insert', '\n'+line.rstrip())
Kurt B. Kaisera7daba62005-06-19 18:56:15 +00001233 finally:
1234 self.text.see("insert")
1235 self.text.undo_block_stop()
David Scherer7aced172000-08-15 01:13:23 +00001236
1237 def runit(self):
1238 line = self.text.get("iomark", "end-1c")
1239 # Strip off last newline and surrounding whitespace.
1240 # (To allow you to hit return twice to end a statement.)
1241 i = len(line)
1242 while i > 0 and line[i-1] in " \t":
1243 i = i-1
1244 if i > 0 and line[i-1] == "\n":
1245 i = i-1
1246 while i > 0 and line[i-1] in " \t":
1247 i = i-1
1248 line = line[:i]
1249 more = self.interp.runsource(line)
David Scherer7aced172000-08-15 01:13:23 +00001250
David Scherer7aced172000-08-15 01:13:23 +00001251 def open_stack_viewer(self, event=None):
Chui Tey5d2af632002-05-26 13:36:41 +00001252 if self.interp.rpcclt:
1253 return self.interp.remote_stack_viewer()
David Scherer7aced172000-08-15 01:13:23 +00001254 try:
1255 sys.last_traceback
1256 except:
1257 tkMessageBox.showerror("No stack trace",
1258 "There is no stack trace yet.\n"
1259 "(sys.last_traceback is not defined)",
1260 master=self.text)
1261 return
Florent Xiclunad630c042010-04-02 07:24:52 +00001262 from idlelib.StackViewer import StackBrowser
David Scherer7aced172000-08-15 01:13:23 +00001263 sv = StackBrowser(self.root, self.flist)
1264
Kurt B. Kaiser1061e722003-01-04 01:43:53 +00001265 def view_restart_mark(self, event=None):
1266 self.text.see("iomark")
1267 self.text.see("restart")
1268
1269 def restart_shell(self, event=None):
Terry Jan Reedyb98000a2012-01-31 02:09:25 -05001270 "Callback for Run/Restart Shell Cntl-F6"
1271 self.interp.restart_subprocess(with_cwd=True)
Kurt B. Kaiser1061e722003-01-04 01:43:53 +00001272
David Scherer7aced172000-08-15 01:13:23 +00001273 def showprompt(self):
1274 self.resetoutput()
1275 try:
1276 s = str(sys.ps1)
1277 except:
1278 s = ""
1279 self.console.write(s)
1280 self.text.mark_set("insert", "end-1c")
Chui Tey5d2af632002-05-26 13:36:41 +00001281 self.set_line_and_column()
Kurt B. Kaiserdc1e7092002-07-11 04:33:41 +00001282 self.io.reset_undo()
David Scherer7aced172000-08-15 01:13:23 +00001283
1284 def resetoutput(self):
1285 source = self.text.get("iomark", "end-1c")
1286 if self.history:
Terry Jan Reedyb638a382013-08-13 19:51:04 -04001287 self.history.store(source)
David Scherer7aced172000-08-15 01:13:23 +00001288 if self.text.get("end-2c") != "\n":
1289 self.text.insert("end-1c", "\n")
1290 self.text.mark_set("iomark", "end-1c")
Chui Tey5d2af632002-05-26 13:36:41 +00001291 self.set_line_and_column()
David Scherer7aced172000-08-15 01:13:23 +00001292 sys.stdout.softspace = 0
1293
1294 def write(self, s, tags=()):
Kurt B. Kaiser003091c2003-02-17 18:57:16 +00001295 try:
1296 self.text.mark_gravity("iomark", "right")
1297 OutputWindow.write(self, s, tags, "iomark")
1298 self.text.mark_gravity("iomark", "left")
1299 except:
1300 pass
David Scherer7aced172000-08-15 01:13:23 +00001301 if self.canceled:
1302 self.canceled = 0
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +00001303 if not use_subprocess:
1304 raise KeyboardInterrupt
David Scherer7aced172000-08-15 01:13:23 +00001305
Andrew Svetlov5018db72012-11-01 22:39:14 +02001306 def rmenu_check_cut(self):
1307 try:
1308 if self.text.compare('sel.first', '<', 'iomark'):
1309 return 'disabled'
1310 except TclError: # no selection, so the index 'sel.first' doesn't exist
1311 return 'disabled'
1312 return super(PyShell, self).rmenu_check_cut()
1313
1314 def rmenu_check_paste(self):
1315 if self.text.compare('insert', '<', 'iomark'):
1316 return 'disabled'
1317 return super(PyShell, self).rmenu_check_paste()
1318
Serhiy Storchaka9abc8302013-01-25 15:30:35 +02001319class PseudoFile(io.TextIOBase):
David Scherer7aced172000-08-15 01:13:23 +00001320
Martin v. Löwisbcc651a2003-06-22 07:52:56 +00001321 def __init__(self, shell, tags, encoding=None):
David Scherer7aced172000-08-15 01:13:23 +00001322 self.shell = shell
1323 self.tags = tags
Chui Tey5d2af632002-05-26 13:36:41 +00001324 self.softspace = 0
Serhiy Storchaka9abc8302013-01-25 15:30:35 +02001325 self._encoding = encoding
David Scherer7aced172000-08-15 01:13:23 +00001326
Serhiy Storchaka9abc8302013-01-25 15:30:35 +02001327 @property
1328 def encoding(self):
1329 return self._encoding
David Scherer7aced172000-08-15 01:13:23 +00001330
Serhiy Storchaka9abc8302013-01-25 15:30:35 +02001331 @property
1332 def name(self):
1333 return '<%s>' % self.tags
David Scherer7aced172000-08-15 01:13:23 +00001334
1335 def isatty(self):
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +00001336 return True
David Scherer7aced172000-08-15 01:13:23 +00001337
Serhiy Storchaka9abc8302013-01-25 15:30:35 +02001338
1339class PseudoOutputFile(PseudoFile):
1340
1341 def writable(self):
1342 return True
Martin v. Löwise2b56242012-07-25 10:56:22 +02001343
1344 def write(self, s):
Serhiy Storchaka9abc8302013-01-25 15:30:35 +02001345 if self.closed:
1346 raise ValueError("write to closed file")
Serhiy Storchaka7057f3f2013-12-10 10:04:41 +02001347 if type(s) not in (unicode, str, bytearray):
1348 # See issue #19481
1349 if isinstance(s, unicode):
1350 s = unicode.__getslice__(s, None, None)
1351 elif isinstance(s, str):
1352 s = str.__str__(s)
1353 elif isinstance(s, bytearray):
1354 s = bytearray.__str__(s)
1355 else:
1356 raise TypeError('must be string, not ' + type(s).__name__)
Serhiy Storchaka9abc8302013-01-25 15:30:35 +02001357 return self.shell.write(s, self.tags)
1358
1359
1360class PseudoInputFile(PseudoFile):
1361
1362 def __init__(self, shell, tags, encoding=None):
1363 PseudoFile.__init__(self, shell, tags, encoding)
1364 self._line_buffer = ''
1365
1366 def readable(self):
1367 return True
1368
1369 def read(self, size=-1):
1370 if self.closed:
1371 raise ValueError("read from closed file")
1372 if size is None:
1373 size = -1
1374 elif not isinstance(size, int):
1375 raise TypeError('must be int, not ' + type(size).__name__)
1376 result = self._line_buffer
1377 self._line_buffer = ''
1378 if size < 0:
1379 while True:
1380 line = self.shell.readline()
1381 if not line: break
1382 result += line
1383 else:
1384 while len(result) < size:
1385 line = self.shell.readline()
1386 if not line: break
1387 result += line
1388 self._line_buffer = result[size:]
1389 result = result[:size]
1390 return result
1391
1392 def readline(self, size=-1):
1393 if self.closed:
1394 raise ValueError("read from closed file")
1395 if size is None:
1396 size = -1
1397 elif not isinstance(size, int):
1398 raise TypeError('must be int, not ' + type(size).__name__)
1399 line = self._line_buffer or self.shell.readline()
1400 if size < 0:
1401 size = len(line)
Serhiy Storchaka0b6b3352013-12-25 14:24:17 +02001402 eol = line.find('\n', 0, size)
1403 if eol >= 0:
1404 size = eol + 1
Serhiy Storchaka9abc8302013-01-25 15:30:35 +02001405 self._line_buffer = line[size:]
1406 return line[:size]
Martin v. Löwise2b56242012-07-25 10:56:22 +02001407
Roger Serwy53dc4f02013-04-11 19:13:21 -05001408 def close(self):
1409 self.shell.close()
1410
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001411
David Scherer7aced172000-08-15 01:13:23 +00001412usage_msg = """\
David Scherer7aced172000-08-15 01:13:23 +00001413
Kurt B. Kaiser11659ad2003-05-15 23:23:21 +00001414USAGE: idle [-deins] [-t title] [file]*
1415 idle [-dns] [-t title] (-c cmd | -r file) [arg]*
1416 idle [-dns] [-t title] - [arg]*
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001417
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001418 -h print this help message and exit
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001419 -n run IDLE without a subprocess (see Help/IDLE Help for details)
David Scherer7aced172000-08-15 01:13:23 +00001420
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001421The following options will override the IDLE 'settings' configuration:
Kurt B. Kaiser96d88422001-07-17 04:59:01 +00001422
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001423 -e open an edit window
1424 -i open a shell window
1425
1426The following options imply -i and will open a shell:
1427
1428 -c cmd run the command in a shell, or
1429 -r file run script from file
1430
1431 -d enable the debugger
1432 -s run $IDLESTARTUP or $PYTHONSTARTUP before anything else
1433 -t title set title of shell window
1434
1435A default edit window will be bypassed when -c, -r, or - are used.
1436
1437[arg]* are passed to the command (-c) or script (-r) in sys.argv[1:].
1438
1439Examples:
1440
1441idle
1442 Open an edit window or shell depending on IDLE's configuration.
1443
1444idle foo.py foobar.py
1445 Edit the files, also open a shell if configured to start with shell.
1446
1447idle -est "Baz" foo.py
1448 Run $IDLESTARTUP or $PYTHONSTARTUP, edit foo.py, and open a shell
1449 window with the title "Baz".
1450
1451idle -c "import sys; print sys.argv" "foo"
1452 Open a shell window and run the command, passing "-c" in sys.argv[0]
1453 and "foo" in sys.argv[1].
1454
1455idle -d -s -r foo.py "Hello World"
1456 Open a shell window, run a startup script, enable the debugger, and
1457 run foo.py, passing "foo.py" in sys.argv[0] and "Hello World" in
1458 sys.argv[1].
1459
1460echo "import sys; print sys.argv" | idle - "foobar"
1461 Open a shell window, run the script piped in, passing '' in sys.argv[0]
1462 and "foobar" in sys.argv[1].
David Scherer7aced172000-08-15 01:13:23 +00001463"""
1464
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001465def main():
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001466 global flist, root, use_subprocess
David Scherer7aced172000-08-15 01:13:23 +00001467
Terry Jan Reedy8eab0082013-06-28 23:51:34 -04001468 capture_warnings(True)
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001469 use_subprocess = True
Roger Serwy34d0c662013-03-31 23:28:55 -05001470 enable_shell = False
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001471 enable_edit = False
1472 debug = False
1473 cmd = None
1474 script = None
1475 startup = False
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001476 try:
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001477 opts, args = getopt.getopt(sys.argv[1:], "c:deihnr:st:")
Terry Jan Reedy2b149862013-06-29 00:59:34 -04001478 except getopt.error as msg:
Terry Jan Reedybee003c2014-09-19 22:37:24 -04001479 print("Error: %s\n%s" % (msg, usage_msg), file=sys.stderr)
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001480 sys.exit(2)
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001481 for o, a in opts:
1482 if o == '-c':
1483 cmd = a
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001484 enable_shell = True
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001485 if o == '-d':
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001486 debug = True
1487 enable_shell = True
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001488 if o == '-e':
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001489 enable_edit = True
1490 if o == '-h':
1491 sys.stdout.write(usage_msg)
1492 sys.exit()
1493 if o == '-i':
1494 enable_shell = True
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001495 if o == '-n':
1496 use_subprocess = False
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001497 if o == '-r':
1498 script = a
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001499 if os.path.isfile(script):
1500 pass
1501 else:
Terry Jan Reedybee003c2014-09-19 22:37:24 -04001502 print("No script file: ", script, file=sys.stderr)
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001503 sys.exit()
1504 enable_shell = True
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001505 if o == '-s':
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001506 startup = True
1507 enable_shell = True
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001508 if o == '-t':
1509 PyShell.shell_title = a
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001510 enable_shell = True
1511 if args and args[0] == '-':
1512 cmd = sys.stdin.read()
1513 enable_shell = True
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001514 # process sys.argv and sys.path:
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001515 for i in range(len(sys.path)):
1516 sys.path[i] = os.path.abspath(sys.path[i])
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001517 if args and args[0] == '-':
1518 sys.argv = [''] + args[1:]
1519 elif cmd:
1520 sys.argv = ['-c'] + args
1521 elif script:
1522 sys.argv = [script] + args
1523 elif args:
1524 enable_edit = True
1525 pathx = []
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001526 for filename in args:
1527 pathx.append(os.path.dirname(filename))
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001528 for dir in pathx:
1529 dir = os.path.abspath(dir)
Florent Xiclunad630c042010-04-02 07:24:52 +00001530 if dir not in sys.path:
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001531 sys.path.insert(0, dir)
Kurt B. Kaiserff002b92002-12-21 21:39:11 +00001532 else:
1533 dir = os.getcwd()
1534 if not dir in sys.path:
1535 sys.path.insert(0, dir)
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001536 # check the IDLE settings configuration (but command line overrides)
1537 edit_start = idleConf.GetOption('main', 'General',
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001538 'editor-on-startup', type='bool')
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001539 enable_edit = enable_edit or edit_start
Roger Serwy34d0c662013-03-31 23:28:55 -05001540 enable_shell = enable_shell or not enable_edit
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001541 # start editor and/or shell windows:
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001542 root = Tk(className="Idle")
Ronald Oussoren19302d92006-06-11 14:33:36 +00001543
Terry Jan Reedy4ade2d22014-02-08 09:39:51 -05001544 # set application icon
1545 icondir = os.path.join(os.path.dirname(__file__), 'Icons')
1546 if system() == 'Windows':
1547 iconfile = os.path.join(icondir, 'idle.ico')
1548 root.wm_iconbitmap(default=iconfile)
1549 elif TkVersion >= 8.5:
1550 ext = '.png' if TkVersion >= 8.6 else '.gif'
1551 iconfiles = [os.path.join(icondir, 'idle_%d%s' % (size, ext))
1552 for size in (16, 32, 48)]
1553 icons = [PhotoImage(file=iconfile) for iconfile in iconfiles]
1554 root.tk.call('wm', 'iconphoto', str(root), "-default", *icons)
1555
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001556 fixwordbreaks(root)
1557 root.withdraw()
1558 flist = PyShellFileList(root)
Ronald Oussoren19302d92006-06-11 14:33:36 +00001559 macosxSupport.setupApp(root, flist)
1560
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001561 if enable_edit:
1562 if not (cmd or script):
Andrew Svetlov7c010ee2012-03-21 13:35:08 +02001563 for filename in args[:]:
1564 if flist.open(filename) is None:
1565 # filename is a directory actually, disconsider it
1566 args.remove(filename)
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001567 if not args:
1568 flist.new()
Ned Deily278543d2013-12-10 16:21:58 -08001569
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +00001570 if enable_shell:
Ronald Oussoren19302d92006-06-11 14:33:36 +00001571 shell = flist.open_shell()
1572 if not shell:
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +00001573 return # couldn't open shell
Ned Deily57847df2014-03-27 20:47:04 -07001574 if macosxSupport.isAquaTk() and flist.dict:
Ronald Oussoren19302d92006-06-11 14:33:36 +00001575 # On OSX: when the user has double-clicked on a file that causes
Tim Peters4f96f1f2006-06-11 19:42:51 +00001576 # IDLE to be launched the shell window will open just in front of
1577 # the file she wants to see. Lower the interpreter window when
Ronald Oussoren19302d92006-06-11 14:33:36 +00001578 # there are open files.
1579 shell.top.lower()
Ned Deily278543d2013-12-10 16:21:58 -08001580 else:
1581 shell = flist.pyshell
Ronald Oussoren19302d92006-06-11 14:33:36 +00001582
Ned Deily278543d2013-12-10 16:21:58 -08001583 # Handle remaining options. If any of these are set, enable_shell
1584 # was set also, so shell must be true to reach here.
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001585 if debug:
1586 shell.open_debugger()
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001587 if startup:
1588 filename = os.environ.get("IDLESTARTUP") or \
1589 os.environ.get("PYTHONSTARTUP")
1590 if filename and os.path.isfile(filename):
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001591 shell.interp.execfile(filename)
Ned Deily278543d2013-12-10 16:21:58 -08001592 if cmd or script:
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001593 shell.interp.runcommand("""if 1:
1594 import sys as _sys
Walter Dörwald70a6b492004-02-12 17:35:32 +00001595 _sys.argv = %r
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001596 del _sys
Walter Dörwald70a6b492004-02-12 17:35:32 +00001597 \n""" % (sys.argv,))
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001598 if cmd:
1599 shell.interp.execsource(cmd)
1600 elif script:
Kurt B. Kaiser11659ad2003-05-15 23:23:21 +00001601 shell.interp.prepend_syspath(script)
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001602 shell.interp.execfile(script)
Ned Deily278543d2013-12-10 16:21:58 -08001603 elif shell:
1604 # If there is a shell window and no cmd or script in progress,
1605 # check for problematic OS X Tk versions and print a warning
1606 # message in the IDLE shell window; this is less intrusive
1607 # than always opening a separate window.
1608 tkversionwarning = macosxSupport.tkVersionWarning(root)
1609 if tkversionwarning:
1610 shell.interp.runcommand("print('%s')" % tkversionwarning)
Ned Deily2a6f4b32011-01-30 00:18:47 +00001611
Terry Jan Reedyeaa7e782012-05-26 20:33:32 -04001612 while flist.inversedict: # keep IDLE running while files are open.
1613 root.mainloop()
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001614 root.destroy()
Terry Jan Reedy8eab0082013-06-28 23:51:34 -04001615 capture_warnings(False)
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001616
David Scherer7aced172000-08-15 01:13:23 +00001617if __name__ == "__main__":
Kurt B. Kaiser9e8b8282003-06-15 17:38:45 +00001618 sys.modules['PyShell'] = sys.modules['__main__']
David Scherer7aced172000-08-15 01:13:23 +00001619 main()
Terry Jan Reedy8eab0082013-06-28 23:51:34 -04001620
1621capture_warnings(False) # Make sure turned off; see issue 18081