blob: e20f70b60967b5e0a3fb5e344b9b0b2f3681529c [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 #
235 # Breakpoints are set as tagged ranges in the text. Certain
236 # kinds of edits cause these ranges to be deleted: Inserting
237 # or deleting a line just before a breakpoint, and certain
238 # deletions prior to a breakpoint. These issues need to be
239 # investigated and understood. It's not clear if they are
240 # Tk issues or IDLE issues, or whether they can actually
241 # be fixed. Since a modified file has to be saved before it is
242 # run, and since self.breakpoints (from which the subprocess
243 # debugger is loaded) is updated during the save, the visible
244 # breaks stay synched with the subprocess even if one of these
245 # unexpected breakpoint deletions occurs.
246 breaks = self.breakpoints
247 filename = self.io.filename
Chui Teya2adb0f2002-11-04 22:14:54 +0000248 try:
Ned Deily40ad0412011-12-14 14:57:43 -0800249 with open(self.breakpointPath,"r") as old_file:
250 lines = old_file.readlines()
Chui Teya2adb0f2002-11-04 22:14:54 +0000251 except IOError:
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000252 lines = []
Ned Deily40ad0412011-12-14 14:57:43 -0800253 try:
254 with open(self.breakpointPath,"w") as new_file:
255 for line in lines:
256 if not line.startswith(filename + '='):
257 new_file.write(line)
258 self.update_breakpoints()
259 breaks = self.breakpoints
260 if breaks:
261 new_file.write(filename + '=' + str(breaks) + '\n')
262 except IOError as err:
263 if not getattr(self.root, "breakpoint_error_displayed", False):
264 self.root.breakpoint_error_displayed = True
265 tkMessageBox.showerror(title='IDLE Error',
266 message='Unable to update breakpoint list:\n%s'
267 % str(err),
268 parent=self.text)
Chui Teya2adb0f2002-11-04 22:14:54 +0000269
270 def restore_file_breaks(self):
271 self.text.update() # this enables setting "BREAK" tags to be visible
Roger Serwyd7c9d9c2013-04-02 22:37:12 -0500272 if self.io is None:
273 # can happen if IDLE closes due to the .update() call
274 return
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000275 filename = self.io.filename
276 if filename is None:
277 return
Chui Tey69371d62002-11-04 23:39:45 +0000278 if os.path.isfile(self.breakpointPath):
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000279 lines = open(self.breakpointPath,"r").readlines()
Chui Tey69371d62002-11-04 23:39:45 +0000280 for line in lines:
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000281 if line.startswith(filename + '='):
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000282 breakpoint_linenumbers = eval(line[len(filename)+1:])
Chui Tey69371d62002-11-04 23:39:45 +0000283 for breakpoint_linenumber in breakpoint_linenumbers:
284 self.set_breakpoint(breakpoint_linenumber)
Chui Teya2adb0f2002-11-04 22:14:54 +0000285
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000286 def update_breakpoints(self):
287 "Retrieves all the breakpoints in the current window"
Chui Teya2adb0f2002-11-04 22:14:54 +0000288 text = self.text
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000289 ranges = text.tag_ranges("BREAK")
290 linenumber_list = self.ranges_to_linenumbers(ranges)
291 self.breakpoints = linenumber_list
292
293 def ranges_to_linenumbers(self, ranges):
294 lines = []
295 for index in range(0, len(ranges), 2):
Andrew Svetlov8a15c372012-07-31 19:51:27 +0300296 lineno = int(float(ranges[index].string))
297 end = int(float(ranges[index+1].string))
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000298 while lineno < end:
299 lines.append(lineno)
300 lineno += 1
301 return lines
302
Kurt B. Kaiser11220fa2002-12-24 00:57:22 +0000303# XXX 13 Dec 2002 KBK Not used currently
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000304# def saved_change_hook(self):
305# "Extend base method - clear breaks if module is modified"
306# if not self.get_saved():
307# self.clear_file_breaks()
308# EditorWindow.saved_change_hook(self)
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000309
310 def _close(self):
311 "Extend base method - clear breaks when module is closed"
312 self.clear_file_breaks()
313 EditorWindow._close(self)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000314
David Scherer7aced172000-08-15 01:13:23 +0000315
316class PyShellFileList(FileList):
Kurt B. Kaiser183403a2004-08-22 05:14:32 +0000317 "Extend base class: IDLE supports a shell and breakpoints"
David Scherer7aced172000-08-15 01:13:23 +0000318
Kurt B. Kaiser183403a2004-08-22 05:14:32 +0000319 # override FileList's class variable, instances return PyShellEditorWindow
320 # instead of EditorWindow when new edit windows are created.
David Scherer7aced172000-08-15 01:13:23 +0000321 EditorWindow = PyShellEditorWindow
322
323 pyshell = None
324
325 def open_shell(self, event=None):
326 if self.pyshell:
Kurt B. Kaiser183403a2004-08-22 05:14:32 +0000327 self.pyshell.top.wakeup()
David Scherer7aced172000-08-15 01:13:23 +0000328 else:
329 self.pyshell = PyShell(self)
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000330 if self.pyshell:
331 if not self.pyshell.begin():
332 return None
David Scherer7aced172000-08-15 01:13:23 +0000333 return self.pyshell
334
335
336class ModifiedColorDelegator(ColorDelegator):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000337 "Extend base class: colorizer for the shell window itself"
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000338
Steven M. Gavab77d3432002-03-02 07:16:21 +0000339 def __init__(self):
340 ColorDelegator.__init__(self)
341 self.LoadTagDefs()
David Scherer7aced172000-08-15 01:13:23 +0000342
343 def recolorize_main(self):
344 self.tag_remove("TODO", "1.0", "iomark")
345 self.tag_add("SYNC", "1.0", "iomark")
346 ColorDelegator.recolorize_main(self)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000347
Steven M. Gavab77d3432002-03-02 07:16:21 +0000348 def LoadTagDefs(self):
349 ColorDelegator.LoadTagDefs(self)
350 theme = idleConf.GetOption('main','Theme','name')
351 self.tagdefs.update({
352 "stdin": {'background':None,'foreground':None},
353 "stdout": idleConf.GetHighlight(theme, "stdout"),
354 "stderr": idleConf.GetHighlight(theme, "stderr"),
355 "console": idleConf.GetHighlight(theme, "console"),
Steven M. Gavab77d3432002-03-02 07:16:21 +0000356 })
David Scherer7aced172000-08-15 01:13:23 +0000357
Ned Deily5e247b72012-05-31 09:17:29 -0700358 def removecolors(self):
359 # Don't remove shell color tags before "iomark"
360 for tag in self.tagdefs:
361 self.tag_remove(tag, "iomark", "end")
362
David Scherer7aced172000-08-15 01:13:23 +0000363class ModifiedUndoDelegator(UndoDelegator):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000364 "Extend base class: forbid insert/delete before the I/O mark"
David Scherer7aced172000-08-15 01:13:23 +0000365
366 def insert(self, index, chars, tags=None):
367 try:
368 if self.delegate.compare(index, "<", "iomark"):
369 self.delegate.bell()
370 return
371 except TclError:
372 pass
373 UndoDelegator.insert(self, index, chars, tags)
374
375 def delete(self, index1, index2=None):
376 try:
377 if self.delegate.compare(index1, "<", "iomark"):
378 self.delegate.bell()
379 return
380 except TclError:
381 pass
382 UndoDelegator.delete(self, index1, index2)
383
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000384
385class MyRPCClient(rpc.RPCClient):
386
387 def handle_EOF(self):
388 "Override the base class - just re-raise EOFError"
389 raise EOFError
390
Kurt B. Kaiser8d1f11b2003-05-26 22:20:34 +0000391
David Scherer7aced172000-08-15 01:13:23 +0000392class ModifiedInterpreter(InteractiveInterpreter):
393
394 def __init__(self, tkconsole):
395 self.tkconsole = tkconsole
396 locals = sys.modules['__main__'].__dict__
397 InteractiveInterpreter.__init__(self, locals=locals)
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000398 self.save_warnings_filters = None
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000399 self.restarting = False
Kurt B. Kaiser013d6cc2009-04-04 07:03:48 +0000400 self.subprocess_arglist = None
401 self.port = PORT
Ned Deily86d669b2011-10-30 19:58:04 -0700402 self.original_compiler_flags = self.compile.compiler.flags
David Scherer7aced172000-08-15 01:13:23 +0000403
Roger Serwy16ce43a2013-06-11 22:13:17 -0500404 _afterid = None
Chui Tey5d2af632002-05-26 13:36:41 +0000405 rpcclt = None
406 rpcpid = None
407
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000408 def spawn_subprocess(self):
Florent Xiclunac8a730b2010-03-25 20:32:07 +0000409 if self.subprocess_arglist is None:
Kurt B. Kaiser013d6cc2009-04-04 07:03:48 +0000410 self.subprocess_arglist = self.build_subprocess_arglist()
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000411 args = self.subprocess_arglist
Kurt B. Kaiserb7855182003-08-14 14:54:28 +0000412 self.rpcpid = os.spawnv(os.P_NOWAIT, sys.executable, args)
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000413
Tony Lowndsf53dec22002-12-20 04:24:43 +0000414 def build_subprocess_arglist(self):
Kurt B. Kaiser013d6cc2009-04-04 07:03:48 +0000415 assert (self.port!=0), (
416 "Socket should have been assigned a port number.")
Tony Lownds2398d572003-05-13 15:28:21 +0000417 w = ['-W' + s for s in sys.warnoptions]
Georg Brandld0761532006-10-12 07:57:21 +0000418 if 1/2 > 0: # account for new division
419 w.append('-Qnew')
Tony Lownds2398d572003-05-13 15:28:21 +0000420 # Maybe IDLE is installed and is being accessed via sys.path,
421 # or maybe it's not installed and the idle.py script is being
422 # run from the IDLE source directory.
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000423 del_exitf = idleConf.GetOption('main', 'General', 'delete-exitfunc',
424 default=False, type='bool')
Tony Lownds2398d572003-05-13 15:28:21 +0000425 if __name__ == 'idlelib.PyShell':
Walter Dörwald70a6b492004-02-12 17:35:32 +0000426 command = "__import__('idlelib.run').run.main(%r)" % (del_exitf,)
Tony Lowndsf2324b92002-09-29 00:34:10 +0000427 else:
Walter Dörwald70a6b492004-02-12 17:35:32 +0000428 command = "__import__('run').main(%r)" % (del_exitf,)
Kurt B. Kaiserb7855182003-08-14 14:54:28 +0000429 if sys.platform[:3] == 'win' and ' ' in sys.executable:
430 # handle embedded space in path by quoting the argument
431 decorated_exec = '"%s"' % sys.executable
432 else:
433 decorated_exec = sys.executable
434 return [decorated_exec] + w + ["-c", command, str(self.port)]
Tony Lowndsf2324b92002-09-29 00:34:10 +0000435
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000436 def start_subprocess(self):
Kurt B. Kaiser013d6cc2009-04-04 07:03:48 +0000437 addr = (HOST, self.port)
438 # GUI makes several attempts to acquire socket, listens for connection
Kurt B. Kaiser5db48432003-05-15 03:40:51 +0000439 for i in range(3):
Chui Tey5d2af632002-05-26 13:36:41 +0000440 time.sleep(i)
441 try:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000442 self.rpcclt = MyRPCClient(addr)
Chui Tey5d2af632002-05-26 13:36:41 +0000443 break
Terry Jan Reedy2b149862013-06-29 00:59:34 -0400444 except socket.error as err:
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000445 pass
Chui Tey5d2af632002-05-26 13:36:41 +0000446 else:
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000447 self.display_port_binding_error()
448 return None
Kurt B. Kaiser013d6cc2009-04-04 07:03:48 +0000449 # if PORT was 0, system will assign an 'ephemeral' port. Find it out:
450 self.port = self.rpcclt.listening_sock.getsockname()[1]
451 # if PORT was not 0, probably working with a remote execution server
452 if PORT != 0:
453 # To allow reconnection within the 2MSL wait (cf. Stevens TCP
454 # V1, 18.6), set SO_REUSEADDR. Note that this can be problematic
455 # on Windows since the implementation allows two active sockets on
456 # the same address!
457 self.rpcclt.listening_sock.setsockopt(socket.SOL_SOCKET,
458 socket.SO_REUSEADDR, 1)
459 self.spawn_subprocess()
460 #time.sleep(20) # test to simulate GUI not accepting connection
Kurt B. Kaiserb4179362002-07-26 00:06:42 +0000461 # Accept the connection from the Python execution server
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000462 self.rpcclt.listening_sock.settimeout(10)
463 try:
464 self.rpcclt.accept()
Terry Jan Reedy2b149862013-06-29 00:59:34 -0400465 except socket.timeout as err:
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000466 self.display_no_subprocess_error()
467 return None
Serhiy Storchaka9abc8302013-01-25 15:30:35 +0200468 self.rpcclt.register("console", self.tkconsole)
469 self.rpcclt.register("stdin", self.tkconsole.stdin)
Kurt B. Kaiser969de452002-06-12 03:28:57 +0000470 self.rpcclt.register("stdout", self.tkconsole.stdout)
471 self.rpcclt.register("stderr", self.tkconsole.stderr)
Chui Tey5d2af632002-05-26 13:36:41 +0000472 self.rpcclt.register("flist", self.tkconsole.flist)
Kurt B. Kaiser8cd0def2003-01-31 05:06:43 +0000473 self.rpcclt.register("linecache", linecache)
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000474 self.rpcclt.register("interp", self)
Terry Jan Reedyb98000a2012-01-31 02:09:25 -0500475 self.transfer_path(with_cwd=True)
Chui Tey5d2af632002-05-26 13:36:41 +0000476 self.poll_subprocess()
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000477 return self.rpcclt
Chui Tey5d2af632002-05-26 13:36:41 +0000478
Terry Jan Reedyb98000a2012-01-31 02:09:25 -0500479 def restart_subprocess(self, with_cwd=False):
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000480 if self.restarting:
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000481 return self.rpcclt
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000482 self.restarting = True
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000483 # close only the subprocess debugger
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000484 debug = self.getdebugger()
485 if debug:
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000486 try:
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000487 # Only close subprocess debugger, don't unregister gui_adap!
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000488 RemoteDebugger.close_subprocess_debugger(self.rpcclt)
489 except:
490 pass
491 # Kill subprocess, spawn a new one, accept connection.
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000492 self.rpcclt.close()
493 self.unix_terminate()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000494 console = self.tkconsole
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000495 was_executing = console.executing
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000496 console.executing = False
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000497 self.spawn_subprocess()
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000498 try:
499 self.rpcclt.accept()
Terry Jan Reedy2b149862013-06-29 00:59:34 -0400500 except socket.timeout as err:
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000501 self.display_no_subprocess_error()
502 return None
Terry Jan Reedyb98000a2012-01-31 02:09:25 -0500503 self.transfer_path(with_cwd=with_cwd)
Roger Serwyad8cad32013-04-03 00:42:24 -0500504 console.stop_readline()
Kurt B. Kaiser1061e722003-01-04 01:43:53 +0000505 # annotate restart in shell window and mark it
Kurt B. Kaiser4cc5ef52003-01-22 00:23:23 +0000506 console.text.delete("iomark", "end-1c")
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000507 if was_executing:
508 console.write('\n')
509 console.showprompt()
Kurt B. Kaiser1061e722003-01-04 01:43:53 +0000510 halfbar = ((int(console.width) - 16) // 2) * '='
511 console.write(halfbar + ' RESTART ' + halfbar)
512 console.text.mark_set("restart", "end-1c")
513 console.text.mark_gravity("restart", "left")
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000514 console.showprompt()
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000515 # restart subprocess debugger
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000516 if debug:
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000517 # Restarted debugger connects to current instance of debug GUI
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000518 gui = RemoteDebugger.restart_subprocess_debugger(self.rpcclt)
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000519 # reload remote debugger breakpoints for all PyShellEditWindows
520 debug.load_breakpoints()
Ned Deily86d669b2011-10-30 19:58:04 -0700521 self.compile.compiler.flags = self.original_compiler_flags
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000522 self.restarting = False
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000523 return self.rpcclt
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000524
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000525 def __request_interrupt(self):
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000526 self.rpcclt.remotecall("exec", "interrupt_the_server", (), {})
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000527
528 def interrupt_subprocess(self):
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000529 threading.Thread(target=self.__request_interrupt).start()
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000530
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000531 def kill_subprocess(self):
Roger Serwy16ce43a2013-06-11 22:13:17 -0500532 if self._afterid is not None:
533 self.tkconsole.text.after_cancel(self._afterid)
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000534 try:
535 self.rpcclt.close()
536 except AttributeError: # no socket
537 pass
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000538 self.unix_terminate()
539 self.tkconsole.executing = False
540 self.rpcclt = None
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000541
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000542 def unix_terminate(self):
543 "UNIX: make sure subprocess is terminated and collect status"
544 if hasattr(os, 'kill'):
545 try:
546 os.kill(self.rpcpid, SIGTERM)
547 except OSError:
548 # process already terminated:
549 return
550 else:
551 try:
552 os.waitpid(self.rpcpid, 0)
553 except OSError:
554 return
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000555
Terry Jan Reedyb98000a2012-01-31 02:09:25 -0500556 def transfer_path(self, with_cwd=False):
557 if with_cwd: # Issue 13506
558 path = [''] # include Current Working Directory
559 path.extend(sys.path)
560 else:
561 path = sys.path
Terry Jan Reedy1d4ae482012-01-31 02:55:32 -0500562
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000563 self.runcommand("""if 1:
564 import sys as _sys
Walter Dörwald70a6b492004-02-12 17:35:32 +0000565 _sys.path = %r
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000566 del _sys
Terry Jan Reedyb98000a2012-01-31 02:09:25 -0500567 \n""" % (path,))
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000568
Chui Tey5d2af632002-05-26 13:36:41 +0000569 active_seq = None
570
571 def poll_subprocess(self):
572 clt = self.rpcclt
573 if clt is None:
574 return
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000575 try:
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000576 response = clt.pollresponse(self.active_seq, wait=0.05)
577 except (EOFError, IOError, KeyboardInterrupt):
578 # lost connection or subprocess terminated itself, restart
579 # [the KBI is from rpc.SocketIO.handle_EOF()]
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000580 if self.tkconsole.closing:
581 return
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000582 response = None
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000583 self.restart_subprocess()
Chui Tey5d2af632002-05-26 13:36:41 +0000584 if response:
585 self.tkconsole.resetoutput()
586 self.active_seq = None
587 how, what = response
Kurt B. Kaiserbc286132003-01-25 21:33:40 +0000588 console = self.tkconsole.console
Chui Tey5d2af632002-05-26 13:36:41 +0000589 if how == "OK":
590 if what is not None:
Terry Jan Reedybee003c2014-09-19 22:37:24 -0400591 print(repr(what), file=console)
Chui Tey5d2af632002-05-26 13:36:41 +0000592 elif how == "EXCEPTION":
Chui Tey5d2af632002-05-26 13:36:41 +0000593 if self.tkconsole.getvar("<<toggle-jit-stack-viewer>>"):
594 self.remote_stack_viewer()
595 elif how == "ERROR":
Kurt B. Kaiser0930c432002-12-06 21:45:24 +0000596 errmsg = "PyShell.ModifiedInterpreter: Subprocess ERROR:\n"
Terry Jan Reedybee003c2014-09-19 22:37:24 -0400597 print(errmsg, what, file=sys.__stderr__)
598 print(errmsg, what, file=console)
Kurt B. Kaiserbc286132003-01-25 21:33:40 +0000599 # we received a response to the currently active seq number:
Kurt B. Kaiserd112bc72006-08-16 05:01:42 +0000600 try:
601 self.tkconsole.endexecuting()
602 except AttributeError: # shell may have closed
603 pass
Kurt B. Kaiser88957d82003-05-19 23:11:51 +0000604 # Reschedule myself
605 if not self.tkconsole.closing:
Roger Serwy16ce43a2013-06-11 22:13:17 -0500606 self._afterid = self.tkconsole.text.after(
607 self.tkconsole.pollinterval, self.poll_subprocess)
Chui Tey5d2af632002-05-26 13:36:41 +0000608
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000609 debugger = None
610
611 def setdebugger(self, debugger):
612 self.debugger = debugger
613
614 def getdebugger(self):
615 return self.debugger
616
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000617 def open_remote_stack_viewer(self):
618 """Initiate the remote stack viewer from a separate thread.
619
620 This method is called from the subprocess, and by returning from this
621 method we allow the subprocess to unblock. After a bit the shell
622 requests the subprocess to open the remote stack viewer which returns a
Ezio Melottic569cfe2010-07-23 16:55:21 +0000623 static object looking at the last exception. It is queried through
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000624 the RPC mechanism.
625
626 """
627 self.tkconsole.text.after(300, self.remote_stack_viewer)
628 return
629
Chui Tey5d2af632002-05-26 13:36:41 +0000630 def remote_stack_viewer(self):
Florent Xiclunad630c042010-04-02 07:24:52 +0000631 from idlelib import RemoteObjectBrowser
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000632 oid = self.rpcclt.remotequeue("exec", "stackviewer", ("flist",), {})
Chui Tey5d2af632002-05-26 13:36:41 +0000633 if oid is None:
634 self.tkconsole.root.bell()
635 return
636 item = RemoteObjectBrowser.StubObjectTreeItem(self.rpcclt, oid)
Florent Xiclunad630c042010-04-02 07:24:52 +0000637 from idlelib.TreeWidget import ScrolledCanvas, TreeNode
Chui Tey5d2af632002-05-26 13:36:41 +0000638 top = Toplevel(self.tkconsole.root)
Kurt B. Kaiser73360a32004-03-08 18:15:31 +0000639 theme = idleConf.GetOption('main','Theme','name')
640 background = idleConf.GetHighlight(theme, 'normal')['background']
641 sc = ScrolledCanvas(top, bg=background, highlightthickness=0)
Chui Tey5d2af632002-05-26 13:36:41 +0000642 sc.frame.pack(expand=1, fill="both")
643 node = TreeNode(sc.canvas, None, item)
644 node.expand()
645 # XXX Should GC the remote tree when closing the window
646
David Scherer7aced172000-08-15 01:13:23 +0000647 gid = 0
648
649 def execsource(self, source):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000650 "Like runsource() but assumes complete exec source"
David Scherer7aced172000-08-15 01:13:23 +0000651 filename = self.stuffsource(source)
652 self.execfile(filename, source)
653
654 def execfile(self, filename, source=None):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000655 "Execute an existing file"
David Scherer7aced172000-08-15 01:13:23 +0000656 if source is None:
657 source = open(filename, "r").read()
658 try:
659 code = compile(source, filename, "exec")
660 except (OverflowError, SyntaxError):
661 self.tkconsole.resetoutput()
Terry Jan Reedybee003c2014-09-19 22:37:24 -0400662 print('*** Error in script or command!\n'
663 'Traceback (most recent call last):',
664 file=self.tkconsole.stderr)
David Scherer7aced172000-08-15 01:13:23 +0000665 InteractiveInterpreter.showsyntaxerror(self, filename)
Kurt B. Kaiser6e44cc22002-11-30 06:18:00 +0000666 self.tkconsole.showprompt()
David Scherer7aced172000-08-15 01:13:23 +0000667 else:
668 self.runcode(code)
669
670 def runsource(self, source):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000671 "Extend base class method: Stuff the source in the line cache first"
David Scherer7aced172000-08-15 01:13:23 +0000672 filename = self.stuffsource(source)
673 self.more = 0
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000674 self.save_warnings_filters = warnings.filters[:]
675 warnings.filterwarnings(action="error", category=SyntaxWarning)
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +0000676 if isinstance(source, types.UnicodeType):
Florent Xiclunad630c042010-04-02 07:24:52 +0000677 from idlelib import IOBinding
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +0000678 try:
679 source = source.encode(IOBinding.encoding)
680 except UnicodeError:
681 self.tkconsole.resetoutput()
Kurt B. Kaisercd3d8be2006-08-10 17:11:09 +0000682 self.write("Unsupported characters in input\n")
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +0000683 return
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000684 try:
Kurt B. Kaiser935ea9a2005-05-10 03:44:24 +0000685 # InteractiveInterpreter.runsource() calls its runcode() method,
686 # which is overridden (see below)
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000687 return InteractiveInterpreter.runsource(self, source, filename)
688 finally:
689 if self.save_warnings_filters is not None:
690 warnings.filters[:] = self.save_warnings_filters
691 self.save_warnings_filters = None
David Scherer7aced172000-08-15 01:13:23 +0000692
693 def stuffsource(self, source):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000694 "Stuff source in the filename cache"
David Scherer7aced172000-08-15 01:13:23 +0000695 filename = "<pyshell#%d>" % self.gid
696 self.gid = self.gid + 1
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +0000697 lines = source.split("\n")
David Scherer7aced172000-08-15 01:13:23 +0000698 linecache.cache[filename] = len(source)+1, 0, lines, filename
699 return filename
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000700
Kurt B. Kaiser11659ad2003-05-15 23:23:21 +0000701 def prepend_syspath(self, filename):
702 "Prepend sys.path with file's directory if not already included"
703 self.runcommand("""if 1:
Walter Dörwald70a6b492004-02-12 17:35:32 +0000704 _filename = %r
Kurt B. Kaiser11659ad2003-05-15 23:23:21 +0000705 import sys as _sys
706 from os.path import dirname as _dirname
707 _dir = _dirname(_filename)
708 if not _dir in _sys.path:
709 _sys.path.insert(0, _dir)
710 del _filename, _sys, _dirname, _dir
Walter Dörwald70a6b492004-02-12 17:35:32 +0000711 \n""" % (filename,))
Kurt B. Kaiser11659ad2003-05-15 23:23:21 +0000712
David Scherer7aced172000-08-15 01:13:23 +0000713 def showsyntaxerror(self, filename=None):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000714 """Extend base class method: Add Colorizing
715
716 Color the offending position instead of printing it and pointing at it
717 with a caret.
718
719 """
David Scherer7aced172000-08-15 01:13:23 +0000720 text = self.tkconsole.text
721 stuff = self.unpackerror()
Kurt B. Kaiser6e44cc22002-11-30 06:18:00 +0000722 if stuff:
723 msg, lineno, offset, line = stuff
724 if lineno == 1:
725 pos = "iomark + %d chars" % (offset-1)
726 else:
727 pos = "iomark linestart + %d lines + %d chars" % \
728 (lineno-1, offset-1)
729 text.tag_add("ERROR", pos)
730 text.see(pos)
731 char = text.get(pos)
732 if char and char in IDENTCHARS:
733 text.tag_add("ERROR", pos + " wordstart", pos)
734 self.tkconsole.resetoutput()
735 self.write("SyntaxError: %s\n" % str(msg))
736 else:
David Scherer7aced172000-08-15 01:13:23 +0000737 self.tkconsole.resetoutput()
738 InteractiveInterpreter.showsyntaxerror(self, filename)
Kurt B. Kaiser6e44cc22002-11-30 06:18:00 +0000739 self.tkconsole.showprompt()
David Scherer7aced172000-08-15 01:13:23 +0000740
741 def unpackerror(self):
742 type, value, tb = sys.exc_info()
743 ok = type is SyntaxError
744 if ok:
745 try:
746 msg, (dummy_filename, lineno, offset, line) = value
Kurt B. Kaiserbea57c62003-07-09 04:27:24 +0000747 if not offset:
748 offset = 0
David Scherer7aced172000-08-15 01:13:23 +0000749 except:
750 ok = 0
751 if ok:
752 return msg, lineno, offset, line
753 else:
754 return None
755
756 def showtraceback(self):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000757 "Extend base class method to reset output properly"
David Scherer7aced172000-08-15 01:13:23 +0000758 self.tkconsole.resetoutput()
759 self.checklinecache()
760 InteractiveInterpreter.showtraceback(self)
Chui Tey5d2af632002-05-26 13:36:41 +0000761 if self.tkconsole.getvar("<<toggle-jit-stack-viewer>>"):
762 self.tkconsole.open_stack_viewer()
David Scherer7aced172000-08-15 01:13:23 +0000763
764 def checklinecache(self):
765 c = linecache.cache
766 for key in c.keys():
767 if key[:1] + key[-1:] != "<>":
768 del c[key]
769
Chui Tey5d2af632002-05-26 13:36:41 +0000770 def runcommand(self, code):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000771 "Run the code without invoking the debugger"
Chui Tey5d2af632002-05-26 13:36:41 +0000772 # The code better not raise an exception!
773 if self.tkconsole.executing:
Neal Norwitzf4c4f112002-11-30 18:49:10 +0000774 self.display_executing_dialog()
Chui Tey5d2af632002-05-26 13:36:41 +0000775 return 0
776 if self.rpcclt:
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000777 self.rpcclt.remotequeue("exec", "runcode", (code,), {})
Chui Tey5d2af632002-05-26 13:36:41 +0000778 else:
779 exec code in self.locals
780 return 1
781
David Scherer7aced172000-08-15 01:13:23 +0000782 def runcode(self, code):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000783 "Override base class method"
Chui Tey5d2af632002-05-26 13:36:41 +0000784 if self.tkconsole.executing:
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000785 self.interp.restart_subprocess()
Chui Tey5d2af632002-05-26 13:36:41 +0000786 self.checklinecache()
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000787 if self.save_warnings_filters is not None:
788 warnings.filters[:] = self.save_warnings_filters
789 self.save_warnings_filters = None
David Scherer7aced172000-08-15 01:13:23 +0000790 debugger = self.debugger
791 try:
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000792 self.tkconsole.beginexecuting()
Kurt B. Kaiserdddeb0e2007-02-06 03:21:40 +0000793 if not debugger and self.rpcclt is not None:
794 self.active_seq = self.rpcclt.asyncqueue("exec", "runcode",
795 (code,), {})
796 elif debugger:
797 debugger.run(code, self.locals)
798 else:
799 exec code in self.locals
800 except SystemExit:
801 if not self.tkconsole.closing:
802 if tkMessageBox.askyesno(
803 "Exit?",
804 "Do you want to exit altogether?",
805 default="yes",
806 master=self.tkconsole.text):
Kurt B. Kaiserf137e1d2006-08-16 07:04:17 +0000807 raise
Kurt B. Kaiserdddeb0e2007-02-06 03:21:40 +0000808 else:
809 self.showtraceback()
810 else:
811 raise
812 except:
813 if use_subprocess:
Terry Jan Reedybee003c2014-09-19 22:37:24 -0400814 print("IDLE internal error in runcode()",
815 file=self.tkconsole.stderr)
David Scherer7aced172000-08-15 01:13:23 +0000816 self.showtraceback()
Kurt B. Kaiserdddeb0e2007-02-06 03:21:40 +0000817 self.tkconsole.endexecuting()
818 else:
819 if self.tkconsole.canceled:
820 self.tkconsole.canceled = False
Terry Jan Reedybee003c2014-09-19 22:37:24 -0400821 print("KeyboardInterrupt", file=self.tkconsole.stderr)
Kurt B. Kaiserdddeb0e2007-02-06 03:21:40 +0000822 else:
823 self.showtraceback()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000824 finally:
825 if not use_subprocess:
Kurt B. Kaiserd112bc72006-08-16 05:01:42 +0000826 try:
827 self.tkconsole.endexecuting()
828 except AttributeError: # shell may have closed
829 pass
David Scherer7aced172000-08-15 01:13:23 +0000830
831 def write(self, s):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000832 "Override base class method"
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000833 self.tkconsole.stderr.write(s)
David Scherer7aced172000-08-15 01:13:23 +0000834
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000835 def display_port_binding_error(self):
836 tkMessageBox.showerror(
837 "Port Binding Error",
Kurt B. Kaiser013d6cc2009-04-04 07:03:48 +0000838 "IDLE can't bind to a TCP/IP port, which is necessary to "
839 "communicate with its Python execution server. This might be "
840 "because no networking is installed on this computer. "
841 "Run IDLE with the -n command line switch to start without a "
842 "subprocess and refer to Help/IDLE Help 'Running without a "
843 "subprocess' for further details.",
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000844 master=self.tkconsole.text)
845
846 def display_no_subprocess_error(self):
847 tkMessageBox.showerror(
848 "Subprocess Startup Error",
849 "IDLE's subprocess didn't make connection. Either IDLE can't "
850 "start a subprocess or personal firewall software is blocking "
851 "the connection.",
852 master=self.tkconsole.text)
853
854 def display_executing_dialog(self):
855 tkMessageBox.showerror(
856 "Already executing",
857 "The Python Shell window is already executing a command; "
858 "please wait until it is finished.",
859 master=self.tkconsole.text)
860
861
David Scherer7aced172000-08-15 01:13:23 +0000862class PyShell(OutputWindow):
863
Terry Jan Reedyd676a3a2013-03-30 18:50:43 -0400864 shell_title = "Python " + python_version() + " Shell"
David Scherer7aced172000-08-15 01:13:23 +0000865
866 # Override classes
867 ColorDelegator = ModifiedColorDelegator
868 UndoDelegator = ModifiedUndoDelegator
869
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000870 # Override menus
Kurt B. Kaiserdc1e7092002-07-11 04:33:41 +0000871 menu_specs = [
872 ("file", "_File"),
873 ("edit", "_Edit"),
Kurt B. Kaiser4cc5ef52003-01-22 00:23:23 +0000874 ("debug", "_Debug"),
Kurt B. Kaiser1061e722003-01-04 01:43:53 +0000875 ("options", "_Options"),
Kurt B. Kaiserdc1e7092002-07-11 04:33:41 +0000876 ("windows", "_Windows"),
877 ("help", "_Help"),
878 ]
David Scherer7aced172000-08-15 01:13:23 +0000879
Ned Deily57847df2014-03-27 20:47:04 -0700880 if sys.platform == "darwin":
Ronald Oussoren19302d92006-06-11 14:33:36 +0000881 menu_specs[-2] = ("windows", "_Window")
882
883
David Scherer7aced172000-08-15 01:13:23 +0000884 # New classes
Florent Xiclunad630c042010-04-02 07:24:52 +0000885 from idlelib.IdleHistory import History
David Scherer7aced172000-08-15 01:13:23 +0000886
887 def __init__(self, flist=None):
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +0000888 if use_subprocess:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000889 ms = self.menu_specs
890 if ms[2][0] != "shell":
Kurt B. Kaiser7ae35482006-08-16 21:45:59 +0000891 ms.insert(2, ("shell", "She_ll"))
David Scherer7aced172000-08-15 01:13:23 +0000892 self.interp = ModifiedInterpreter(self)
893 if flist is None:
894 root = Tk()
895 fixwordbreaks(root)
896 root.withdraw()
897 flist = PyShellFileList(root)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000898 #
David Scherer7aced172000-08-15 01:13:23 +0000899 OutputWindow.__init__(self, flist, None, None)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000900 #
Kurt B. Kaiser6af44982005-01-19 00:22:59 +0000901## self.config(usetabs=1, indentwidth=8, context_use_ps1=1)
902 self.usetabs = True
903 # indentwidth must be 8 when using tabs. See note in EditorWindow:
904 self.indentwidth = 8
905 self.context_use_ps1 = True
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000906 #
David Scherer7aced172000-08-15 01:13:23 +0000907 text = self.text
908 text.configure(wrap="char")
909 text.bind("<<newline-and-indent>>", self.enter_callback)
910 text.bind("<<plain-newline-and-indent>>", self.linefeed_callback)
911 text.bind("<<interrupt-execution>>", self.cancel_callback)
David Scherer7aced172000-08-15 01:13:23 +0000912 text.bind("<<end-of-file>>", self.eof_callback)
913 text.bind("<<open-stack-viewer>>", self.open_stack_viewer)
Kurt B. Kaiser57bfe5d2003-05-10 00:09:52 +0000914 text.bind("<<toggle-debugger>>", self.toggle_debugger)
David Scherer7aced172000-08-15 01:13:23 +0000915 text.bind("<<toggle-jit-stack-viewer>>", self.toggle_jit_stack_viewer)
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +0000916 if use_subprocess:
917 text.bind("<<view-restart>>", self.view_restart_mark)
918 text.bind("<<restart-shell>>", self.restart_shell)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000919 #
David Scherer7aced172000-08-15 01:13:23 +0000920 self.save_stdout = sys.stdout
921 self.save_stderr = sys.stderr
922 self.save_stdin = sys.stdin
Florent Xiclunad630c042010-04-02 07:24:52 +0000923 from idlelib import IOBinding
Serhiy Storchaka9abc8302013-01-25 15:30:35 +0200924 self.stdin = PseudoInputFile(self, "stdin", IOBinding.encoding)
925 self.stdout = PseudoOutputFile(self, "stdout", IOBinding.encoding)
926 self.stderr = PseudoOutputFile(self, "stderr", IOBinding.encoding)
927 self.console = PseudoOutputFile(self, "console", IOBinding.encoding)
Chui Tey5d2af632002-05-26 13:36:41 +0000928 if not use_subprocess:
929 sys.stdout = self.stdout
930 sys.stderr = self.stderr
Martin v. Löwise2b56242012-07-25 10:56:22 +0200931 sys.stdin = self.stdin
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000932 #
David Scherer7aced172000-08-15 01:13:23 +0000933 self.history = self.History(self.text)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000934 #
Kurt B. Kaiser88957d82003-05-19 23:11:51 +0000935 self.pollinterval = 50 # millisec
Chui Tey5d2af632002-05-26 13:36:41 +0000936
Kurt B. Kaiser4d5bc602004-06-06 01:29:22 +0000937 def get_standard_extension_names(self):
938 return idleConf.GetExtensions(shell_only=True)
939
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000940 reading = False
941 executing = False
942 canceled = False
943 endoffile = False
944 closing = False
Roger Serwyad8cad32013-04-03 00:42:24 -0500945 _stop_readline_flag = False
David Scherer7aced172000-08-15 01:13:23 +0000946
Kurt B. Kaiser49a5fe12004-07-04 01:25:56 +0000947 def set_warning_stream(self, stream):
Skip Montanarod9161422004-07-06 21:53:27 +0000948 global warning_stream
949 warning_stream = stream
Kurt B. Kaiser49a5fe12004-07-04 01:25:56 +0000950
951 def get_warning_stream(self):
952 return warning_stream
953
David Scherer7aced172000-08-15 01:13:23 +0000954 def toggle_debugger(self, event=None):
955 if self.executing:
956 tkMessageBox.showerror("Don't debug now",
957 "You can only toggle the debugger when idle",
958 master=self.text)
959 self.set_debugger_indicator()
960 return "break"
961 else:
962 db = self.interp.getdebugger()
963 if db:
964 self.close_debugger()
965 else:
966 self.open_debugger()
967
968 def set_debugger_indicator(self):
969 db = self.interp.getdebugger()
970 self.setvar("<<toggle-debugger>>", not not db)
971
Kurt B. Kaiser1061e722003-01-04 01:43:53 +0000972 def toggle_jit_stack_viewer(self, event=None):
David Scherer7aced172000-08-15 01:13:23 +0000973 pass # All we need is the variable
974
975 def close_debugger(self):
976 db = self.interp.getdebugger()
977 if db:
978 self.interp.setdebugger(None)
979 db.close()
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000980 if self.interp.rpcclt:
981 RemoteDebugger.close_remote_debugger(self.interp.rpcclt)
David Scherer7aced172000-08-15 01:13:23 +0000982 self.resetoutput()
983 self.console.write("[DEBUG OFF]\n")
984 sys.ps1 = ">>> "
985 self.showprompt()
986 self.set_debugger_indicator()
987
988 def open_debugger(self):
Chui Tey5d2af632002-05-26 13:36:41 +0000989 if self.interp.rpcclt:
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000990 dbg_gui = RemoteDebugger.start_remote_debugger(self.interp.rpcclt,
991 self)
992 else:
993 dbg_gui = Debugger.Debugger(self)
994 self.interp.setdebugger(dbg_gui)
995 dbg_gui.load_breakpoints()
Chui Tey5d2af632002-05-26 13:36:41 +0000996 sys.ps1 = "[DEBUG ON]\n>>> "
997 self.showprompt()
998 self.set_debugger_indicator()
999
David Scherer7aced172000-08-15 01:13:23 +00001000 def beginexecuting(self):
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +00001001 "Helper for ModifiedInterpreter"
David Scherer7aced172000-08-15 01:13:23 +00001002 self.resetoutput()
1003 self.executing = 1
David Scherer7aced172000-08-15 01:13:23 +00001004
1005 def endexecuting(self):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +00001006 "Helper for ModifiedInterpreter"
David Scherer7aced172000-08-15 01:13:23 +00001007 self.executing = 0
1008 self.canceled = 0
Chui Tey5d2af632002-05-26 13:36:41 +00001009 self.showprompt()
David Scherer7aced172000-08-15 01:13:23 +00001010
1011 def close(self):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +00001012 "Extend EditorWindow.close()"
David Scherer7aced172000-08-15 01:13:23 +00001013 if self.executing:
Kurt B. Kaiser003091c2003-02-17 18:57:16 +00001014 response = tkMessageBox.askokcancel(
David Scherer7aced172000-08-15 01:13:23 +00001015 "Kill?",
Kurt B. Kaiser003091c2003-02-17 18:57:16 +00001016 "The program is still running!\n Do you want to kill it?",
David Scherer7aced172000-08-15 01:13:23 +00001017 default="ok",
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +00001018 parent=self.text)
Benjamin Peterson5b63acd2008-03-29 15:24:25 +00001019 if response is False:
David Scherer7aced172000-08-15 01:13:23 +00001020 return "cancel"
Roger Serwyad8cad32013-04-03 00:42:24 -05001021 self.stop_readline()
Kurt B. Kaiser5c3df352004-12-23 04:20:59 +00001022 self.canceled = True
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +00001023 self.closing = True
Kurt B. Kaiser88957d82003-05-19 23:11:51 +00001024 return EditorWindow.close(self)
David Scherer7aced172000-08-15 01:13:23 +00001025
1026 def _close(self):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +00001027 "Extend EditorWindow._close(), shut down debugger and execution server"
David Scherer7aced172000-08-15 01:13:23 +00001028 self.close_debugger()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +00001029 if use_subprocess:
1030 self.interp.kill_subprocess()
David Scherer7aced172000-08-15 01:13:23 +00001031 # Restore std streams
1032 sys.stdout = self.save_stdout
1033 sys.stderr = self.save_stderr
1034 sys.stdin = self.save_stdin
1035 # Break cycles
1036 self.interp = None
1037 self.console = None
David Scherer7aced172000-08-15 01:13:23 +00001038 self.flist.pyshell = None
1039 self.history = None
Kurt B. Kaiser83118c62002-06-24 17:03:37 +00001040 EditorWindow._close(self)
David Scherer7aced172000-08-15 01:13:23 +00001041
1042 def ispythonsource(self, filename):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +00001043 "Override EditorWindow method: never remove the colorizer"
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +00001044 return True
David Scherer7aced172000-08-15 01:13:23 +00001045
1046 def short_title(self):
1047 return self.shell_title
1048
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +00001049 COPYRIGHT = \
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001050 'Type "copyright", "credits" or "license()" for more information.'
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +00001051
David Scherer7aced172000-08-15 01:13:23 +00001052 def begin(self):
1053 self.resetoutput()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +00001054 if use_subprocess:
1055 nosub = ''
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +00001056 client = self.interp.start_subprocess()
1057 if not client:
1058 self.close()
Kurt B. Kaiser76637292004-01-21 22:10:01 +00001059 return False
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +00001060 else:
1061 nosub = "==== No Subprocess ===="
Raymond Hettingerbf3f69e2009-01-26 23:29:09 +00001062 self.write("Python %s on %s\n%s\n%s" %
1063 (sys.version, sys.platform, self.COPYRIGHT, nosub))
David Scherer7aced172000-08-15 01:13:23 +00001064 self.showprompt()
Georg Brandl6634bf22008-05-20 07:13:37 +00001065 import Tkinter
1066 Tkinter._default_root = None # 03Jan04 KBK What's this?
Kurt B. Kaiser76637292004-01-21 22:10:01 +00001067 return True
David Scherer7aced172000-08-15 01:13:23 +00001068
Roger Serwyad8cad32013-04-03 00:42:24 -05001069 def stop_readline(self):
1070 if not self.reading: # no nested mainloop to exit.
1071 return
1072 self._stop_readline_flag = True
1073 self.top.quit()
1074
David Scherer7aced172000-08-15 01:13:23 +00001075 def readline(self):
1076 save = self.reading
1077 try:
1078 self.reading = 1
Kurt B. Kaiser5c3df352004-12-23 04:20:59 +00001079 self.top.mainloop() # nested mainloop()
David Scherer7aced172000-08-15 01:13:23 +00001080 finally:
1081 self.reading = save
Roger Serwyad8cad32013-04-03 00:42:24 -05001082 if self._stop_readline_flag:
1083 self._stop_readline_flag = False
1084 return ""
David Scherer7aced172000-08-15 01:13:23 +00001085 line = self.text.get("iomark", "end-1c")
Kurt B. Kaiser5c3df352004-12-23 04:20:59 +00001086 if len(line) == 0: # may be EOF if we quit our mainloop with Ctrl-C
1087 line = "\n"
Martin v. Löwisbcc651a2003-06-22 07:52:56 +00001088 if isinstance(line, unicode):
Florent Xiclunad630c042010-04-02 07:24:52 +00001089 from idlelib import IOBinding
Martin v. Löwisbcc651a2003-06-22 07:52:56 +00001090 try:
1091 line = line.encode(IOBinding.encoding)
1092 except UnicodeError:
1093 pass
David Scherer7aced172000-08-15 01:13:23 +00001094 self.resetoutput()
1095 if self.canceled:
1096 self.canceled = 0
Kurt B. Kaiser5c3df352004-12-23 04:20:59 +00001097 if not use_subprocess:
1098 raise KeyboardInterrupt
David Scherer7aced172000-08-15 01:13:23 +00001099 if self.endoffile:
1100 self.endoffile = 0
Kurt B. Kaiser5c3df352004-12-23 04:20:59 +00001101 line = ""
David Scherer7aced172000-08-15 01:13:23 +00001102 return line
1103
1104 def isatty(self):
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +00001105 return True
David Scherer7aced172000-08-15 01:13:23 +00001106
Kurt B. Kaiser003091c2003-02-17 18:57:16 +00001107 def cancel_callback(self, event=None):
David Scherer7aced172000-08-15 01:13:23 +00001108 try:
1109 if self.text.compare("sel.first", "!=", "sel.last"):
1110 return # Active selection -- always use default binding
1111 except:
1112 pass
1113 if not (self.executing or self.reading):
1114 self.resetoutput()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +00001115 self.interp.write("KeyboardInterrupt\n")
David Scherer7aced172000-08-15 01:13:23 +00001116 self.showprompt()
1117 return "break"
1118 self.endoffile = 0
Kurt B. Kaiser003091c2003-02-17 18:57:16 +00001119 self.canceled = 1
Kurt B. Kaiser5c3df352004-12-23 04:20:59 +00001120 if (self.executing and self.interp.rpcclt):
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +00001121 if self.interp.getdebugger():
1122 self.interp.restart_subprocess()
1123 else:
1124 self.interp.interrupt_subprocess()
Kurt B. Kaiser5c3df352004-12-23 04:20:59 +00001125 if self.reading:
1126 self.top.quit() # exit the nested mainloop() in readline()
David Scherer7aced172000-08-15 01:13:23 +00001127 return "break"
1128
1129 def eof_callback(self, event):
1130 if self.executing and not self.reading:
1131 return # Let the default binding (delete next char) take over
1132 if not (self.text.compare("iomark", "==", "insert") and
1133 self.text.compare("insert", "==", "end-1c")):
1134 return # Let the default binding (delete next char) take over
1135 if not self.executing:
David Scherer7aced172000-08-15 01:13:23 +00001136 self.resetoutput()
1137 self.close()
1138 else:
1139 self.canceled = 0
1140 self.endoffile = 1
1141 self.top.quit()
1142 return "break"
1143
David Scherer7aced172000-08-15 01:13:23 +00001144 def linefeed_callback(self, event):
1145 # Insert a linefeed without entering anything (still autoindented)
1146 if self.reading:
1147 self.text.insert("insert", "\n")
1148 self.text.see("insert")
1149 else:
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +00001150 self.newline_and_indent_event(event)
David Scherer7aced172000-08-15 01:13:23 +00001151 return "break"
1152
1153 def enter_callback(self, event):
1154 if self.executing and not self.reading:
1155 return # Let the default binding (insert '\n') take over
1156 # If some text is selected, recall the selection
1157 # (but only if this before the I/O mark)
1158 try:
1159 sel = self.text.get("sel.first", "sel.last")
1160 if sel:
1161 if self.text.compare("sel.last", "<=", "iomark"):
Kurt B. Kaisera7daba62005-06-19 18:56:15 +00001162 self.recall(sel, event)
David Scherer7aced172000-08-15 01:13:23 +00001163 return "break"
1164 except:
1165 pass
1166 # If we're strictly before the line containing iomark, recall
1167 # the current line, less a leading prompt, less leading or
1168 # trailing whitespace
1169 if self.text.compare("insert", "<", "iomark linestart"):
1170 # Check if there's a relevant stdin range -- if so, use it
1171 prev = self.text.tag_prevrange("stdin", "insert")
1172 if prev and self.text.compare("insert", "<", prev[1]):
Kurt B. Kaisera7daba62005-06-19 18:56:15 +00001173 self.recall(self.text.get(prev[0], prev[1]), event)
David Scherer7aced172000-08-15 01:13:23 +00001174 return "break"
1175 next = self.text.tag_nextrange("stdin", "insert")
1176 if next and self.text.compare("insert lineend", ">=", next[0]):
Kurt B. Kaisera7daba62005-06-19 18:56:15 +00001177 self.recall(self.text.get(next[0], next[1]), event)
David Scherer7aced172000-08-15 01:13:23 +00001178 return "break"
Kurt B. Kaiser4ada7ad2002-12-29 22:03:38 +00001179 # No stdin mark -- just get the current line, less any prompt
Kurt B. Kaiserb1754452005-11-18 22:05:48 +00001180 indices = self.text.tag_nextrange("console", "insert linestart")
1181 if indices and \
1182 self.text.compare(indices[0], "<=", "insert linestart"):
1183 self.recall(self.text.get(indices[1], "insert lineend"), event)
1184 else:
1185 self.recall(self.text.get("insert linestart", "insert lineend"), event)
David Scherer7aced172000-08-15 01:13:23 +00001186 return "break"
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +00001187 # If we're between the beginning of the line and the iomark, i.e.
Kurt B. Kaiser4ada7ad2002-12-29 22:03:38 +00001188 # in the prompt area, move to the end of the prompt
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +00001189 if self.text.compare("insert", "<", "iomark"):
Kurt B. Kaiser4ada7ad2002-12-29 22:03:38 +00001190 self.text.mark_set("insert", "iomark")
David Scherer7aced172000-08-15 01:13:23 +00001191 # If we're in the current input and there's only whitespace
1192 # beyond the cursor, erase that whitespace first
1193 s = self.text.get("insert", "end-1c")
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +00001194 if s and not s.strip():
David Scherer7aced172000-08-15 01:13:23 +00001195 self.text.delete("insert", "end-1c")
1196 # If we're in the current input before its last line,
1197 # insert a newline right at the insert point
1198 if self.text.compare("insert", "<", "end-1c linestart"):
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +00001199 self.newline_and_indent_event(event)
David Scherer7aced172000-08-15 01:13:23 +00001200 return "break"
1201 # We're in the last line; append a newline and submit it
1202 self.text.mark_set("insert", "end-1c")
1203 if self.reading:
1204 self.text.insert("insert", "\n")
1205 self.text.see("insert")
1206 else:
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +00001207 self.newline_and_indent_event(event)
David Scherer7aced172000-08-15 01:13:23 +00001208 self.text.tag_add("stdin", "iomark", "end-1c")
1209 self.text.update_idletasks()
1210 if self.reading:
1211 self.top.quit() # Break out of recursive mainloop() in raw_input()
1212 else:
1213 self.runit()
1214 return "break"
1215
Kurt B. Kaisera7daba62005-06-19 18:56:15 +00001216 def recall(self, s, event):
Kurt B. Kaisercd3d8be2006-08-10 17:11:09 +00001217 # remove leading and trailing empty or whitespace lines
1218 s = re.sub(r'^\s*\n', '' , s)
1219 s = re.sub(r'\n\s*$', '', s)
1220 lines = s.split('\n')
Kurt B. Kaisera7daba62005-06-19 18:56:15 +00001221 self.text.undo_block_start()
1222 try:
1223 self.text.tag_remove("sel", "1.0", "end")
1224 self.text.mark_set("insert", "end-1c")
Kurt B. Kaisercd3d8be2006-08-10 17:11:09 +00001225 prefix = self.text.get("insert linestart", "insert")
1226 if prefix.rstrip().endswith(':'):
Kurt B. Kaiser8fa7eb52005-06-21 02:42:17 +00001227 self.newline_and_indent_event(event)
Kurt B. Kaisercd3d8be2006-08-10 17:11:09 +00001228 prefix = self.text.get("insert linestart", "insert")
1229 self.text.insert("insert", lines[0].strip())
Kurt B. Kaiser8fa7eb52005-06-21 02:42:17 +00001230 if len(lines) > 1:
Kurt B. Kaisercd3d8be2006-08-10 17:11:09 +00001231 orig_base_indent = re.search(r'^([ \t]*)', lines[0]).group(0)
1232 new_base_indent = re.search(r'^([ \t]*)', prefix).group(0)
Kurt B. Kaiser8fa7eb52005-06-21 02:42:17 +00001233 for line in lines[1:]:
Kurt B. Kaisercd3d8be2006-08-10 17:11:09 +00001234 if line.startswith(orig_base_indent):
1235 # replace orig base indentation with new indentation
1236 line = new_base_indent + line[len(orig_base_indent):]
1237 self.text.insert('insert', '\n'+line.rstrip())
Kurt B. Kaisera7daba62005-06-19 18:56:15 +00001238 finally:
1239 self.text.see("insert")
1240 self.text.undo_block_stop()
David Scherer7aced172000-08-15 01:13:23 +00001241
1242 def runit(self):
1243 line = self.text.get("iomark", "end-1c")
1244 # Strip off last newline and surrounding whitespace.
1245 # (To allow you to hit return twice to end a statement.)
1246 i = len(line)
1247 while i > 0 and line[i-1] in " \t":
1248 i = i-1
1249 if i > 0 and line[i-1] == "\n":
1250 i = i-1
1251 while i > 0 and line[i-1] in " \t":
1252 i = i-1
1253 line = line[:i]
1254 more = self.interp.runsource(line)
David Scherer7aced172000-08-15 01:13:23 +00001255
David Scherer7aced172000-08-15 01:13:23 +00001256 def open_stack_viewer(self, event=None):
Chui Tey5d2af632002-05-26 13:36:41 +00001257 if self.interp.rpcclt:
1258 return self.interp.remote_stack_viewer()
David Scherer7aced172000-08-15 01:13:23 +00001259 try:
1260 sys.last_traceback
1261 except:
1262 tkMessageBox.showerror("No stack trace",
1263 "There is no stack trace yet.\n"
1264 "(sys.last_traceback is not defined)",
1265 master=self.text)
1266 return
Florent Xiclunad630c042010-04-02 07:24:52 +00001267 from idlelib.StackViewer import StackBrowser
David Scherer7aced172000-08-15 01:13:23 +00001268 sv = StackBrowser(self.root, self.flist)
1269
Kurt B. Kaiser1061e722003-01-04 01:43:53 +00001270 def view_restart_mark(self, event=None):
1271 self.text.see("iomark")
1272 self.text.see("restart")
1273
1274 def restart_shell(self, event=None):
Terry Jan Reedyb98000a2012-01-31 02:09:25 -05001275 "Callback for Run/Restart Shell Cntl-F6"
1276 self.interp.restart_subprocess(with_cwd=True)
Kurt B. Kaiser1061e722003-01-04 01:43:53 +00001277
David Scherer7aced172000-08-15 01:13:23 +00001278 def showprompt(self):
1279 self.resetoutput()
1280 try:
1281 s = str(sys.ps1)
1282 except:
1283 s = ""
1284 self.console.write(s)
1285 self.text.mark_set("insert", "end-1c")
Chui Tey5d2af632002-05-26 13:36:41 +00001286 self.set_line_and_column()
Kurt B. Kaiserdc1e7092002-07-11 04:33:41 +00001287 self.io.reset_undo()
David Scherer7aced172000-08-15 01:13:23 +00001288
1289 def resetoutput(self):
1290 source = self.text.get("iomark", "end-1c")
1291 if self.history:
Terry Jan Reedyb638a382013-08-13 19:51:04 -04001292 self.history.store(source)
David Scherer7aced172000-08-15 01:13:23 +00001293 if self.text.get("end-2c") != "\n":
1294 self.text.insert("end-1c", "\n")
1295 self.text.mark_set("iomark", "end-1c")
Chui Tey5d2af632002-05-26 13:36:41 +00001296 self.set_line_and_column()
David Scherer7aced172000-08-15 01:13:23 +00001297 sys.stdout.softspace = 0
1298
1299 def write(self, s, tags=()):
Kurt B. Kaiser003091c2003-02-17 18:57:16 +00001300 try:
1301 self.text.mark_gravity("iomark", "right")
1302 OutputWindow.write(self, s, tags, "iomark")
1303 self.text.mark_gravity("iomark", "left")
1304 except:
1305 pass
David Scherer7aced172000-08-15 01:13:23 +00001306 if self.canceled:
1307 self.canceled = 0
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +00001308 if not use_subprocess:
1309 raise KeyboardInterrupt
David Scherer7aced172000-08-15 01:13:23 +00001310
Andrew Svetlov5018db72012-11-01 22:39:14 +02001311 def rmenu_check_cut(self):
1312 try:
1313 if self.text.compare('sel.first', '<', 'iomark'):
1314 return 'disabled'
1315 except TclError: # no selection, so the index 'sel.first' doesn't exist
1316 return 'disabled'
1317 return super(PyShell, self).rmenu_check_cut()
1318
1319 def rmenu_check_paste(self):
1320 if self.text.compare('insert', '<', 'iomark'):
1321 return 'disabled'
1322 return super(PyShell, self).rmenu_check_paste()
1323
Serhiy Storchaka9abc8302013-01-25 15:30:35 +02001324class PseudoFile(io.TextIOBase):
David Scherer7aced172000-08-15 01:13:23 +00001325
Martin v. Löwisbcc651a2003-06-22 07:52:56 +00001326 def __init__(self, shell, tags, encoding=None):
David Scherer7aced172000-08-15 01:13:23 +00001327 self.shell = shell
1328 self.tags = tags
Chui Tey5d2af632002-05-26 13:36:41 +00001329 self.softspace = 0
Serhiy Storchaka9abc8302013-01-25 15:30:35 +02001330 self._encoding = encoding
David Scherer7aced172000-08-15 01:13:23 +00001331
Serhiy Storchaka9abc8302013-01-25 15:30:35 +02001332 @property
1333 def encoding(self):
1334 return self._encoding
David Scherer7aced172000-08-15 01:13:23 +00001335
Serhiy Storchaka9abc8302013-01-25 15:30:35 +02001336 @property
1337 def name(self):
1338 return '<%s>' % self.tags
David Scherer7aced172000-08-15 01:13:23 +00001339
1340 def isatty(self):
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +00001341 return True
David Scherer7aced172000-08-15 01:13:23 +00001342
Serhiy Storchaka9abc8302013-01-25 15:30:35 +02001343
1344class PseudoOutputFile(PseudoFile):
1345
1346 def writable(self):
1347 return True
Martin v. Löwise2b56242012-07-25 10:56:22 +02001348
1349 def write(self, s):
Serhiy Storchaka9abc8302013-01-25 15:30:35 +02001350 if self.closed:
1351 raise ValueError("write to closed file")
Serhiy Storchaka7057f3f2013-12-10 10:04:41 +02001352 if type(s) not in (unicode, str, bytearray):
1353 # See issue #19481
1354 if isinstance(s, unicode):
1355 s = unicode.__getslice__(s, None, None)
1356 elif isinstance(s, str):
1357 s = str.__str__(s)
1358 elif isinstance(s, bytearray):
1359 s = bytearray.__str__(s)
1360 else:
1361 raise TypeError('must be string, not ' + type(s).__name__)
Serhiy Storchaka9abc8302013-01-25 15:30:35 +02001362 return self.shell.write(s, self.tags)
1363
1364
1365class PseudoInputFile(PseudoFile):
1366
1367 def __init__(self, shell, tags, encoding=None):
1368 PseudoFile.__init__(self, shell, tags, encoding)
1369 self._line_buffer = ''
1370
1371 def readable(self):
1372 return True
1373
1374 def read(self, size=-1):
1375 if self.closed:
1376 raise ValueError("read from closed file")
1377 if size is None:
1378 size = -1
1379 elif not isinstance(size, int):
1380 raise TypeError('must be int, not ' + type(size).__name__)
1381 result = self._line_buffer
1382 self._line_buffer = ''
1383 if size < 0:
1384 while True:
1385 line = self.shell.readline()
1386 if not line: break
1387 result += line
1388 else:
1389 while len(result) < size:
1390 line = self.shell.readline()
1391 if not line: break
1392 result += line
1393 self._line_buffer = result[size:]
1394 result = result[:size]
1395 return result
1396
1397 def readline(self, size=-1):
1398 if self.closed:
1399 raise ValueError("read from closed file")
1400 if size is None:
1401 size = -1
1402 elif not isinstance(size, int):
1403 raise TypeError('must be int, not ' + type(size).__name__)
1404 line = self._line_buffer or self.shell.readline()
1405 if size < 0:
1406 size = len(line)
Serhiy Storchaka0b6b3352013-12-25 14:24:17 +02001407 eol = line.find('\n', 0, size)
1408 if eol >= 0:
1409 size = eol + 1
Serhiy Storchaka9abc8302013-01-25 15:30:35 +02001410 self._line_buffer = line[size:]
1411 return line[:size]
Martin v. Löwise2b56242012-07-25 10:56:22 +02001412
Roger Serwy53dc4f02013-04-11 19:13:21 -05001413 def close(self):
1414 self.shell.close()
1415
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001416
David Scherer7aced172000-08-15 01:13:23 +00001417usage_msg = """\
David Scherer7aced172000-08-15 01:13:23 +00001418
Kurt B. Kaiser11659ad2003-05-15 23:23:21 +00001419USAGE: idle [-deins] [-t title] [file]*
1420 idle [-dns] [-t title] (-c cmd | -r file) [arg]*
1421 idle [-dns] [-t title] - [arg]*
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001422
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001423 -h print this help message and exit
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001424 -n run IDLE without a subprocess (see Help/IDLE Help for details)
David Scherer7aced172000-08-15 01:13:23 +00001425
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001426The following options will override the IDLE 'settings' configuration:
Kurt B. Kaiser96d88422001-07-17 04:59:01 +00001427
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001428 -e open an edit window
1429 -i open a shell window
1430
1431The following options imply -i and will open a shell:
1432
1433 -c cmd run the command in a shell, or
1434 -r file run script from file
1435
1436 -d enable the debugger
1437 -s run $IDLESTARTUP or $PYTHONSTARTUP before anything else
1438 -t title set title of shell window
1439
1440A default edit window will be bypassed when -c, -r, or - are used.
1441
1442[arg]* are passed to the command (-c) or script (-r) in sys.argv[1:].
1443
1444Examples:
1445
1446idle
1447 Open an edit window or shell depending on IDLE's configuration.
1448
1449idle foo.py foobar.py
1450 Edit the files, also open a shell if configured to start with shell.
1451
1452idle -est "Baz" foo.py
1453 Run $IDLESTARTUP or $PYTHONSTARTUP, edit foo.py, and open a shell
1454 window with the title "Baz".
1455
1456idle -c "import sys; print sys.argv" "foo"
1457 Open a shell window and run the command, passing "-c" in sys.argv[0]
1458 and "foo" in sys.argv[1].
1459
1460idle -d -s -r foo.py "Hello World"
1461 Open a shell window, run a startup script, enable the debugger, and
1462 run foo.py, passing "foo.py" in sys.argv[0] and "Hello World" in
1463 sys.argv[1].
1464
1465echo "import sys; print sys.argv" | idle - "foobar"
1466 Open a shell window, run the script piped in, passing '' in sys.argv[0]
1467 and "foobar" in sys.argv[1].
David Scherer7aced172000-08-15 01:13:23 +00001468"""
1469
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001470def main():
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001471 global flist, root, use_subprocess
David Scherer7aced172000-08-15 01:13:23 +00001472
Terry Jan Reedy8eab0082013-06-28 23:51:34 -04001473 capture_warnings(True)
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001474 use_subprocess = True
Roger Serwy34d0c662013-03-31 23:28:55 -05001475 enable_shell = False
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001476 enable_edit = False
1477 debug = False
1478 cmd = None
1479 script = None
1480 startup = False
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001481 try:
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001482 opts, args = getopt.getopt(sys.argv[1:], "c:deihnr:st:")
Terry Jan Reedy2b149862013-06-29 00:59:34 -04001483 except getopt.error as msg:
Terry Jan Reedybee003c2014-09-19 22:37:24 -04001484 print("Error: %s\n%s" % (msg, usage_msg), file=sys.stderr)
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001485 sys.exit(2)
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001486 for o, a in opts:
1487 if o == '-c':
1488 cmd = a
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001489 enable_shell = True
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001490 if o == '-d':
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001491 debug = True
1492 enable_shell = True
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001493 if o == '-e':
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001494 enable_edit = True
1495 if o == '-h':
1496 sys.stdout.write(usage_msg)
1497 sys.exit()
1498 if o == '-i':
1499 enable_shell = True
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001500 if o == '-n':
1501 use_subprocess = False
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001502 if o == '-r':
1503 script = a
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001504 if os.path.isfile(script):
1505 pass
1506 else:
Terry Jan Reedybee003c2014-09-19 22:37:24 -04001507 print("No script file: ", script, file=sys.stderr)
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001508 sys.exit()
1509 enable_shell = True
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001510 if o == '-s':
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001511 startup = True
1512 enable_shell = True
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001513 if o == '-t':
1514 PyShell.shell_title = a
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001515 enable_shell = True
1516 if args and args[0] == '-':
1517 cmd = sys.stdin.read()
1518 enable_shell = True
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001519 # process sys.argv and sys.path:
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001520 for i in range(len(sys.path)):
1521 sys.path[i] = os.path.abspath(sys.path[i])
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001522 if args and args[0] == '-':
1523 sys.argv = [''] + args[1:]
1524 elif cmd:
1525 sys.argv = ['-c'] + args
1526 elif script:
1527 sys.argv = [script] + args
1528 elif args:
1529 enable_edit = True
1530 pathx = []
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001531 for filename in args:
1532 pathx.append(os.path.dirname(filename))
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001533 for dir in pathx:
1534 dir = os.path.abspath(dir)
Florent Xiclunad630c042010-04-02 07:24:52 +00001535 if dir not in sys.path:
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001536 sys.path.insert(0, dir)
Kurt B. Kaiserff002b92002-12-21 21:39:11 +00001537 else:
1538 dir = os.getcwd()
1539 if not dir in sys.path:
1540 sys.path.insert(0, dir)
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001541 # check the IDLE settings configuration (but command line overrides)
1542 edit_start = idleConf.GetOption('main', 'General',
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001543 'editor-on-startup', type='bool')
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001544 enable_edit = enable_edit or edit_start
Roger Serwy34d0c662013-03-31 23:28:55 -05001545 enable_shell = enable_shell or not enable_edit
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001546 # start editor and/or shell windows:
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001547 root = Tk(className="Idle")
Ronald Oussoren19302d92006-06-11 14:33:36 +00001548
Terry Jan Reedy4ade2d22014-02-08 09:39:51 -05001549 # set application icon
1550 icondir = os.path.join(os.path.dirname(__file__), 'Icons')
1551 if system() == 'Windows':
1552 iconfile = os.path.join(icondir, 'idle.ico')
1553 root.wm_iconbitmap(default=iconfile)
1554 elif TkVersion >= 8.5:
1555 ext = '.png' if TkVersion >= 8.6 else '.gif'
1556 iconfiles = [os.path.join(icondir, 'idle_%d%s' % (size, ext))
1557 for size in (16, 32, 48)]
1558 icons = [PhotoImage(file=iconfile) for iconfile in iconfiles]
1559 root.tk.call('wm', 'iconphoto', str(root), "-default", *icons)
1560
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001561 fixwordbreaks(root)
1562 root.withdraw()
1563 flist = PyShellFileList(root)
Ronald Oussoren19302d92006-06-11 14:33:36 +00001564 macosxSupport.setupApp(root, flist)
1565
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001566 if enable_edit:
1567 if not (cmd or script):
Andrew Svetlov7c010ee2012-03-21 13:35:08 +02001568 for filename in args[:]:
1569 if flist.open(filename) is None:
1570 # filename is a directory actually, disconsider it
1571 args.remove(filename)
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001572 if not args:
1573 flist.new()
Ned Deily278543d2013-12-10 16:21:58 -08001574
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +00001575 if enable_shell:
Ronald Oussoren19302d92006-06-11 14:33:36 +00001576 shell = flist.open_shell()
1577 if not shell:
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +00001578 return # couldn't open shell
Ned Deily57847df2014-03-27 20:47:04 -07001579 if macosxSupport.isAquaTk() and flist.dict:
Ronald Oussoren19302d92006-06-11 14:33:36 +00001580 # On OSX: when the user has double-clicked on a file that causes
Tim Peters4f96f1f2006-06-11 19:42:51 +00001581 # IDLE to be launched the shell window will open just in front of
1582 # the file she wants to see. Lower the interpreter window when
Ronald Oussoren19302d92006-06-11 14:33:36 +00001583 # there are open files.
1584 shell.top.lower()
Ned Deily278543d2013-12-10 16:21:58 -08001585 else:
1586 shell = flist.pyshell
Ronald Oussoren19302d92006-06-11 14:33:36 +00001587
Ned Deily278543d2013-12-10 16:21:58 -08001588 # Handle remaining options. If any of these are set, enable_shell
1589 # was set also, so shell must be true to reach here.
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001590 if debug:
1591 shell.open_debugger()
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001592 if startup:
1593 filename = os.environ.get("IDLESTARTUP") or \
1594 os.environ.get("PYTHONSTARTUP")
1595 if filename and os.path.isfile(filename):
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001596 shell.interp.execfile(filename)
Ned Deily278543d2013-12-10 16:21:58 -08001597 if cmd or script:
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001598 shell.interp.runcommand("""if 1:
1599 import sys as _sys
Walter Dörwald70a6b492004-02-12 17:35:32 +00001600 _sys.argv = %r
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001601 del _sys
Walter Dörwald70a6b492004-02-12 17:35:32 +00001602 \n""" % (sys.argv,))
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001603 if cmd:
1604 shell.interp.execsource(cmd)
1605 elif script:
Kurt B. Kaiser11659ad2003-05-15 23:23:21 +00001606 shell.interp.prepend_syspath(script)
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001607 shell.interp.execfile(script)
Ned Deily278543d2013-12-10 16:21:58 -08001608 elif shell:
1609 # If there is a shell window and no cmd or script in progress,
1610 # check for problematic OS X Tk versions and print a warning
1611 # message in the IDLE shell window; this is less intrusive
1612 # than always opening a separate window.
1613 tkversionwarning = macosxSupport.tkVersionWarning(root)
1614 if tkversionwarning:
1615 shell.interp.runcommand("print('%s')" % tkversionwarning)
Ned Deily2a6f4b32011-01-30 00:18:47 +00001616
Terry Jan Reedyeaa7e782012-05-26 20:33:32 -04001617 while flist.inversedict: # keep IDLE running while files are open.
1618 root.mainloop()
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001619 root.destroy()
Terry Jan Reedy8eab0082013-06-28 23:51:34 -04001620 capture_warnings(False)
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001621
David Scherer7aced172000-08-15 01:13:23 +00001622if __name__ == "__main__":
Kurt B. Kaiser9e8b8282003-06-15 17:38:45 +00001623 sys.modules['PyShell'] = sys.modules['__main__']
David Scherer7aced172000-08-15 01:13:23 +00001624 main()
Terry Jan Reedy8eab0082013-06-28 23:51:34 -04001625
1626capture_warnings(False) # Make sure turned off; see issue 18081