blob: 47028bd73086d1aefaf416bf4d373e0464f88735 [file] [log] [blame]
David Scherer7aced172000-08-15 01:13:23 +00001#! /usr/bin/env python
2
David Scherer7aced172000-08-15 01:13:23 +00003import os
Kurt B. Kaiser6e44cc22002-11-30 06:18:00 +00004import os.path
David Scherer7aced172000-08-15 01:13:23 +00005import sys
6import string
7import getopt
8import re
Chui Tey5d2af632002-05-26 13:36:41 +00009import socket
10import time
Kurt B. Kaiser003091c2003-02-17 18:57:16 +000011import threading
Chui Tey5d2af632002-05-26 13:36:41 +000012import traceback
Kurt B. Kaiser62833982002-09-18 17:07:05 +000013import types
Kurt B. Kaiser0930c432002-12-06 21:45:24 +000014import exceptions
David Scherer7aced172000-08-15 01:13:23 +000015
16import linecache
17from code import InteractiveInterpreter
18
19from Tkinter import *
20import tkMessageBox
21
22from EditorWindow import EditorWindow, fixwordbreaks
23from FileList import FileList
24from ColorDelegator import ColorDelegator
25from UndoDelegator import UndoDelegator
Kurt B. Kaiser969de452002-06-12 03:28:57 +000026from OutputWindow import OutputWindow
Steven M. Gava99300612001-11-04 07:03:08 +000027from configHandler import idleConf
David Scherer7aced172000-08-15 01:13:23 +000028import idlever
29
Chui Tey5d2af632002-05-26 13:36:41 +000030import rpc
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +000031import Debugger
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +000032import RemoteDebugger
Chui Tey5d2af632002-05-26 13:36:41 +000033
Kurt B. Kaiserb9764192002-09-23 04:10:37 +000034IDENTCHARS = string.ascii_letters + string.digits + "_"
Kurt B. Kaiser24d7e0c2003-06-05 23:51:29 +000035LOCALHOST = '127.0.0.1'
Kurt B. Kaiserb9764192002-09-23 04:10:37 +000036
Kurt B. Kaisera00050f2003-05-08 20:26:55 +000037try:
38 from signal import SIGTERM
39except ImportError:
40 SIGTERM = 15
41
Chui Tey5d2af632002-05-26 13:36:41 +000042# Change warnings module to write to sys.__stderr__
43try:
44 import warnings
45except ImportError:
46 pass
47else:
48 def idle_showwarning(message, category, filename, lineno):
49 file = sys.__stderr__
50 file.write(warnings.formatwarning(message, category, filename, lineno))
51 warnings.showwarning = idle_showwarning
52
Kurt B. Kaiser81885592002-11-29 22:10:53 +000053def extended_linecache_checkcache(orig_checkcache=linecache.checkcache):
Kurt B. Kaiser45186c42002-10-23 04:48:08 +000054 """Extend linecache.checkcache to preserve the <pyshell#...> entries
55
Kurt B. Kaiser81885592002-11-29 22:10:53 +000056 Rather than repeating the linecache code, patch it to save the pyshell#
57 entries, call the original linecache.checkcache(), and then restore the
58 saved entries. Assigning the orig_checkcache keyword arg freezes its value
59 at definition time to the (original) method linecache.checkcache(), i.e.
60 makes orig_checkcache lexical.
Kurt B. Kaiser45186c42002-10-23 04:48:08 +000061
62 """
David Scherer7aced172000-08-15 01:13:23 +000063 cache = linecache.cache
64 save = {}
65 for filename in cache.keys():
66 if filename[:1] + filename[-1:] == '<>':
67 save[filename] = cache[filename]
68 orig_checkcache()
69 cache.update(save)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +000070
Kurt B. Kaiser81885592002-11-29 22:10:53 +000071# Patch linecache.checkcache():
72linecache.checkcache = extended_linecache_checkcache
David Scherer7aced172000-08-15 01:13:23 +000073
Kurt B. Kaiser45186c42002-10-23 04:48:08 +000074
David Scherer7aced172000-08-15 01:13:23 +000075class PyShellEditorWindow(EditorWindow):
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +000076 "Regular text edit window when a shell is present"
Kurt B. Kaiser45186c42002-10-23 04:48:08 +000077
David Scherer7aced172000-08-15 01:13:23 +000078 def __init__(self, *args):
Kurt B. Kaiser45186c42002-10-23 04:48:08 +000079 self.breakpoints = []
Raymond Hettinger931237e2003-07-09 18:48:24 +000080 EditorWindow.__init__(self, *args)
David Scherer7aced172000-08-15 01:13:23 +000081 self.text.bind("<<set-breakpoint-here>>", self.set_breakpoint_here)
Kurt B. Kaiser45186c42002-10-23 04:48:08 +000082 self.text.bind("<<clear-breakpoint-here>>", self.clear_breakpoint_here)
David Scherer7aced172000-08-15 01:13:23 +000083 self.text.bind("<<open-python-shell>>", self.flist.open_shell)
84
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +000085 self.breakpointPath = os.path.join(idleConf.GetUserCfgDir(),
86 'breakpoints.lst')
Chui Teya2adb0f2002-11-04 22:14:54 +000087 # whenever a file is changed, restore breakpoints
88 if self.io.filename: self.restore_file_breaks()
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +000089 def filename_changed_hook(old_hook=self.io.filename_change_hook,
90 self=self):
Chui Teya2adb0f2002-11-04 22:14:54 +000091 self.restore_file_breaks()
92 old_hook()
93 self.io.set_filename_change_hook(filename_changed_hook)
94
Kurt B. Kaiser45186c42002-10-23 04:48:08 +000095 rmenu_specs = [("Set Breakpoint", "<<set-breakpoint-here>>"),
96 ("Clear Breakpoint", "<<clear-breakpoint-here>>")]
David Scherer7aced172000-08-15 01:13:23 +000097
Chui Teya2adb0f2002-11-04 22:14:54 +000098 def set_breakpoint(self, lineno):
99 text = self.text
100 filename = self.io.filename
101 text.tag_add("BREAK", "%d.0" % lineno, "%d.0" % (lineno+1))
102 try:
103 i = self.breakpoints.index(lineno)
104 except ValueError: # only add if missing, i.e. do once
105 self.breakpoints.append(lineno)
106 try: # update the subprocess debugger
107 debug = self.flist.pyshell.interp.debugger
108 debug.set_breakpoint_here(filename, lineno)
109 except: # but debugger may not be active right now....
110 pass
111
David Scherer7aced172000-08-15 01:13:23 +0000112 def set_breakpoint_here(self, event=None):
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000113 text = self.text
114 filename = self.io.filename
115 if not filename:
116 text.bell()
David Scherer7aced172000-08-15 01:13:23 +0000117 return
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000118 lineno = int(float(text.index("insert")))
Chui Teya2adb0f2002-11-04 22:14:54 +0000119 self.set_breakpoint(lineno)
David Scherer7aced172000-08-15 01:13:23 +0000120
Kurt B. Kaiser669f4c32002-06-20 04:01:47 +0000121 def clear_breakpoint_here(self, event=None):
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000122 text = self.text
123 filename = self.io.filename
124 if not filename:
125 text.bell()
Kurt B. Kaiser669f4c32002-06-20 04:01:47 +0000126 return
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000127 lineno = int(float(text.index("insert")))
128 try:
129 self.breakpoints.remove(lineno)
130 except:
131 pass
132 text.tag_remove("BREAK", "insert linestart",\
133 "insert lineend +1char")
134 try:
135 debug = self.flist.pyshell.interp.debugger
136 debug.clear_breakpoint_here(filename, lineno)
137 except:
138 pass
139
140 def clear_file_breaks(self):
141 if self.breakpoints:
142 text = self.text
143 filename = self.io.filename
144 if not filename:
145 text.bell()
146 return
147 self.breakpoints = []
148 text.tag_remove("BREAK", "1.0", END)
149 try:
150 debug = self.flist.pyshell.interp.debugger
151 debug.clear_file_breaks(filename)
152 except:
153 pass
154
Chui Teya2adb0f2002-11-04 22:14:54 +0000155 def store_file_breaks(self):
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000156 "Save breakpoints when file is saved"
157 # XXX 13 Dec 2002 KBK Currently the file must be saved before it can
158 # be run. The breaks are saved at that time. If we introduce
159 # a temporary file save feature the save breaks functionality
160 # needs to be re-verified, since the breaks at the time the
161 # temp file is created may differ from the breaks at the last
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000162 # permanent save of the file. Currently, a break introduced
163 # after a save will be effective, but not persistent.
164 # This is necessary to keep the saved breaks synched with the
165 # saved file.
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000166 #
167 # Breakpoints are set as tagged ranges in the text. Certain
168 # kinds of edits cause these ranges to be deleted: Inserting
169 # or deleting a line just before a breakpoint, and certain
170 # deletions prior to a breakpoint. These issues need to be
171 # investigated and understood. It's not clear if they are
172 # Tk issues or IDLE issues, or whether they can actually
173 # be fixed. Since a modified file has to be saved before it is
174 # run, and since self.breakpoints (from which the subprocess
175 # debugger is loaded) is updated during the save, the visible
176 # breaks stay synched with the subprocess even if one of these
177 # unexpected breakpoint deletions occurs.
178 breaks = self.breakpoints
179 filename = self.io.filename
Chui Teya2adb0f2002-11-04 22:14:54 +0000180 try:
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000181 lines = open(self.breakpointPath,"r").readlines()
Chui Teya2adb0f2002-11-04 22:14:54 +0000182 except IOError:
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000183 lines = []
184 new_file = open(self.breakpointPath,"w")
Chui Teya2adb0f2002-11-04 22:14:54 +0000185 for line in lines:
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000186 if not line.startswith(filename + '='):
Chui Teya2adb0f2002-11-04 22:14:54 +0000187 new_file.write(line)
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000188 self.update_breakpoints()
189 breaks = self.breakpoints
190 if breaks:
191 new_file.write(filename + '=' + str(breaks) + '\n')
Chui Teya2adb0f2002-11-04 22:14:54 +0000192 new_file.close()
193
194 def restore_file_breaks(self):
195 self.text.update() # this enables setting "BREAK" tags to be visible
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000196 filename = self.io.filename
197 if filename is None:
198 return
Chui Tey69371d62002-11-04 23:39:45 +0000199 if os.path.isfile(self.breakpointPath):
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000200 lines = open(self.breakpointPath,"r").readlines()
Chui Tey69371d62002-11-04 23:39:45 +0000201 for line in lines:
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000202 if line.startswith(filename + '='):
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000203 breakpoint_linenumbers = eval(line[len(filename)+1:])
Chui Tey69371d62002-11-04 23:39:45 +0000204 for breakpoint_linenumber in breakpoint_linenumbers:
205 self.set_breakpoint(breakpoint_linenumber)
Chui Teya2adb0f2002-11-04 22:14:54 +0000206
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000207 def update_breakpoints(self):
208 "Retrieves all the breakpoints in the current window"
Chui Teya2adb0f2002-11-04 22:14:54 +0000209 text = self.text
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000210 ranges = text.tag_ranges("BREAK")
211 linenumber_list = self.ranges_to_linenumbers(ranges)
212 self.breakpoints = linenumber_list
213
214 def ranges_to_linenumbers(self, ranges):
215 lines = []
216 for index in range(0, len(ranges), 2):
217 lineno = int(float(ranges[index]))
218 end = int(float(ranges[index+1]))
219 while lineno < end:
220 lines.append(lineno)
221 lineno += 1
222 return lines
223
Kurt B. Kaiser11220fa2002-12-24 00:57:22 +0000224# XXX 13 Dec 2002 KBK Not used currently
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000225# def saved_change_hook(self):
226# "Extend base method - clear breaks if module is modified"
227# if not self.get_saved():
228# self.clear_file_breaks()
229# EditorWindow.saved_change_hook(self)
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000230
231 def _close(self):
232 "Extend base method - clear breaks when module is closed"
233 self.clear_file_breaks()
234 EditorWindow._close(self)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000235
David Scherer7aced172000-08-15 01:13:23 +0000236
237class PyShellFileList(FileList):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000238 "Extend base class: file list when a shell is present"
David Scherer7aced172000-08-15 01:13:23 +0000239
240 EditorWindow = PyShellEditorWindow
241
242 pyshell = None
243
244 def open_shell(self, event=None):
245 if self.pyshell:
246 self.pyshell.wakeup()
247 else:
248 self.pyshell = PyShell(self)
249 self.pyshell.begin()
250 return self.pyshell
251
252
253class ModifiedColorDelegator(ColorDelegator):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000254 "Extend base class: colorizer for the shell window itself"
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000255
Steven M. Gavab77d3432002-03-02 07:16:21 +0000256 def __init__(self):
257 ColorDelegator.__init__(self)
258 self.LoadTagDefs()
David Scherer7aced172000-08-15 01:13:23 +0000259
260 def recolorize_main(self):
261 self.tag_remove("TODO", "1.0", "iomark")
262 self.tag_add("SYNC", "1.0", "iomark")
263 ColorDelegator.recolorize_main(self)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000264
Steven M. Gavab77d3432002-03-02 07:16:21 +0000265 def LoadTagDefs(self):
266 ColorDelegator.LoadTagDefs(self)
267 theme = idleConf.GetOption('main','Theme','name')
268 self.tagdefs.update({
269 "stdin": {'background':None,'foreground':None},
270 "stdout": idleConf.GetHighlight(theme, "stdout"),
271 "stderr": idleConf.GetHighlight(theme, "stderr"),
272 "console": idleConf.GetHighlight(theme, "console"),
Steven M. Gavab77d3432002-03-02 07:16:21 +0000273 None: idleConf.GetHighlight(theme, "normal"),
274 })
David Scherer7aced172000-08-15 01:13:23 +0000275
David Scherer7aced172000-08-15 01:13:23 +0000276class ModifiedUndoDelegator(UndoDelegator):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000277 "Extend base class: forbid insert/delete before the I/O mark"
David Scherer7aced172000-08-15 01:13:23 +0000278
279 def insert(self, index, chars, tags=None):
280 try:
281 if self.delegate.compare(index, "<", "iomark"):
282 self.delegate.bell()
283 return
284 except TclError:
285 pass
286 UndoDelegator.insert(self, index, chars, tags)
287
288 def delete(self, index1, index2=None):
289 try:
290 if self.delegate.compare(index1, "<", "iomark"):
291 self.delegate.bell()
292 return
293 except TclError:
294 pass
295 UndoDelegator.delete(self, index1, index2)
296
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000297
298class MyRPCClient(rpc.RPCClient):
299
300 def handle_EOF(self):
301 "Override the base class - just re-raise EOFError"
302 raise EOFError
303
Kurt B. Kaiser8d1f11b2003-05-26 22:20:34 +0000304
David Scherer7aced172000-08-15 01:13:23 +0000305class ModifiedInterpreter(InteractiveInterpreter):
306
307 def __init__(self, tkconsole):
308 self.tkconsole = tkconsole
309 locals = sys.modules['__main__'].__dict__
310 InteractiveInterpreter.__init__(self, locals=locals)
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000311 self.save_warnings_filters = None
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000312 self.restarting = False
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000313 self.subprocess_arglist = self.build_subprocess_arglist()
David Scherer7aced172000-08-15 01:13:23 +0000314
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000315 port = 8833
Chui Tey5d2af632002-05-26 13:36:41 +0000316 rpcclt = None
317 rpcpid = None
318
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000319 def spawn_subprocess(self):
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000320 args = self.subprocess_arglist
Chui Tey5d2af632002-05-26 13:36:41 +0000321 self.rpcpid = os.spawnv(os.P_NOWAIT, args[0], args)
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000322
Tony Lowndsf53dec22002-12-20 04:24:43 +0000323 def build_subprocess_arglist(self):
Tony Lownds2398d572003-05-13 15:28:21 +0000324 w = ['-W' + s for s in sys.warnoptions]
325 # Maybe IDLE is installed and is being accessed via sys.path,
326 # or maybe it's not installed and the idle.py script is being
327 # run from the IDLE source directory.
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000328 del_exitf = idleConf.GetOption('main', 'General', 'delete-exitfunc',
329 default=False, type='bool')
Tony Lownds2398d572003-05-13 15:28:21 +0000330 if __name__ == 'idlelib.PyShell':
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000331 command = "__import__('idlelib.run').run.main(" + `del_exitf` +")"
Tony Lowndsf2324b92002-09-29 00:34:10 +0000332 else:
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000333 command = "__import__('run').main(" + `del_exitf` + ")"
Tony Lownds2398d572003-05-13 15:28:21 +0000334 return [sys.executable] + w + ["-c", command, str(self.port)]
Tony Lowndsf2324b92002-09-29 00:34:10 +0000335
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000336 def start_subprocess(self):
Kurt B. Kaiser24d7e0c2003-06-05 23:51:29 +0000337 addr = (LOCALHOST, self.port)
Kurt B. Kaiser8dcdb772002-08-05 03:52:10 +0000338 # Idle starts listening for connection on localhost
Kurt B. Kaiser5db48432003-05-15 03:40:51 +0000339 for i in range(3):
Chui Tey5d2af632002-05-26 13:36:41 +0000340 time.sleep(i)
341 try:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000342 self.rpcclt = MyRPCClient(addr)
Chui Tey5d2af632002-05-26 13:36:41 +0000343 break
344 except socket.error, err:
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +0000345 print>>sys.__stderr__,"IDLE socket error: " + err[1]\
Kurt B. Kaiserb4179362002-07-26 00:06:42 +0000346 + ", retrying..."
Chui Tey5d2af632002-05-26 13:36:41 +0000347 else:
Kurt B. Kaiser969de452002-06-12 03:28:57 +0000348 display_port_binding_error()
Kurt B. Kaisera2a3cb22002-12-24 03:33:12 +0000349 sys.exit()
Kurt B. Kaiser5db48432003-05-15 03:40:51 +0000350 self.spawn_subprocess()
Kurt B. Kaiserb4179362002-07-26 00:06:42 +0000351 # Accept the connection from the Python execution server
352 self.rpcclt.accept()
Kurt B. Kaiser969de452002-06-12 03:28:57 +0000353 self.rpcclt.register("stdin", self.tkconsole)
354 self.rpcclt.register("stdout", self.tkconsole.stdout)
355 self.rpcclt.register("stderr", self.tkconsole.stderr)
Chui Tey5d2af632002-05-26 13:36:41 +0000356 self.rpcclt.register("flist", self.tkconsole.flist)
Kurt B. Kaiser8cd0def2003-01-31 05:06:43 +0000357 self.rpcclt.register("linecache", linecache)
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000358 self.rpcclt.register("interp", self)
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000359 self.transfer_path()
Chui Tey5d2af632002-05-26 13:36:41 +0000360 self.poll_subprocess()
361
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000362 def restart_subprocess(self):
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000363 if self.restarting:
364 return
365 self.restarting = True
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000366 # close only the subprocess debugger
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000367 debug = self.getdebugger()
368 if debug:
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000369 try:
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000370 # Only close subprocess debugger, don't unregister gui_adap!
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000371 RemoteDebugger.close_subprocess_debugger(self.rpcclt)
372 except:
373 pass
374 # Kill subprocess, spawn a new one, accept connection.
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000375 self.rpcclt.close()
376 self.unix_terminate()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000377 console = self.tkconsole
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000378 was_executing = console.executing
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000379 console.executing = False
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000380 self.spawn_subprocess()
381 self.rpcclt.accept()
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000382 self.transfer_path()
Kurt B. Kaiser1061e722003-01-04 01:43:53 +0000383 # annotate restart in shell window and mark it
Kurt B. Kaiser4cc5ef52003-01-22 00:23:23 +0000384 console.text.delete("iomark", "end-1c")
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000385 if was_executing:
386 console.write('\n')
387 console.showprompt()
Kurt B. Kaiser1061e722003-01-04 01:43:53 +0000388 halfbar = ((int(console.width) - 16) // 2) * '='
389 console.write(halfbar + ' RESTART ' + halfbar)
390 console.text.mark_set("restart", "end-1c")
391 console.text.mark_gravity("restart", "left")
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000392 console.showprompt()
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000393 # restart subprocess debugger
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000394 if debug:
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000395 # Restarted debugger connects to current instance of debug GUI
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000396 gui = RemoteDebugger.restart_subprocess_debugger(self.rpcclt)
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000397 # reload remote debugger breakpoints for all PyShellEditWindows
398 debug.load_breakpoints()
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000399 self.restarting = False
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000400
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000401 def __request_interrupt(self):
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000402 self.rpcclt.remotecall("exec", "interrupt_the_server", (), {})
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000403
404 def interrupt_subprocess(self):
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000405 threading.Thread(target=self.__request_interrupt).start()
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000406
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000407 def kill_subprocess(self):
408 self.rpcclt.close()
409 self.unix_terminate()
410 self.tkconsole.executing = False
411 self.rpcclt = None
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000412
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000413 def unix_terminate(self):
414 "UNIX: make sure subprocess is terminated and collect status"
415 if hasattr(os, 'kill'):
416 try:
417 os.kill(self.rpcpid, SIGTERM)
418 except OSError:
419 # process already terminated:
420 return
421 else:
422 try:
423 os.waitpid(self.rpcpid, 0)
424 except OSError:
425 return
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000426
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000427 def transfer_path(self):
428 self.runcommand("""if 1:
429 import sys as _sys
430 _sys.path = %s
431 del _sys
Kurt B. Kaiserb2487332003-03-04 04:03:45 +0000432 _msg = 'Use File/Exit or your end-of-file key to quit IDLE'
433 __builtins__.quit = __builtins__.exit = _msg
434 del _msg
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000435 \n""" % `sys.path`)
436
Chui Tey5d2af632002-05-26 13:36:41 +0000437 active_seq = None
438
439 def poll_subprocess(self):
440 clt = self.rpcclt
441 if clt is None:
442 return
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000443 try:
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000444 response = clt.pollresponse(self.active_seq, wait=0.05)
445 except (EOFError, IOError, KeyboardInterrupt):
446 # lost connection or subprocess terminated itself, restart
447 # [the KBI is from rpc.SocketIO.handle_EOF()]
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000448 if self.tkconsole.closing:
449 return
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000450 response = None
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000451 self.restart_subprocess()
Chui Tey5d2af632002-05-26 13:36:41 +0000452 if response:
453 self.tkconsole.resetoutput()
454 self.active_seq = None
455 how, what = response
Kurt B. Kaiserbc286132003-01-25 21:33:40 +0000456 console = self.tkconsole.console
Chui Tey5d2af632002-05-26 13:36:41 +0000457 if how == "OK":
458 if what is not None:
Kurt B. Kaiserbc286132003-01-25 21:33:40 +0000459 print >>console, `what`
Chui Tey5d2af632002-05-26 13:36:41 +0000460 elif how == "EXCEPTION":
Chui Tey5d2af632002-05-26 13:36:41 +0000461 if self.tkconsole.getvar("<<toggle-jit-stack-viewer>>"):
462 self.remote_stack_viewer()
463 elif how == "ERROR":
Kurt B. Kaiser0930c432002-12-06 21:45:24 +0000464 errmsg = "PyShell.ModifiedInterpreter: Subprocess ERROR:\n"
465 print >>sys.__stderr__, errmsg, what
Kurt B. Kaiserbc286132003-01-25 21:33:40 +0000466 print >>console, errmsg, what
467 # we received a response to the currently active seq number:
Chui Tey5d2af632002-05-26 13:36:41 +0000468 self.tkconsole.endexecuting()
Kurt B. Kaiser88957d82003-05-19 23:11:51 +0000469 # Reschedule myself
470 if not self.tkconsole.closing:
471 self.tkconsole.text.after(self.tkconsole.pollinterval,
472 self.poll_subprocess)
Chui Tey5d2af632002-05-26 13:36:41 +0000473
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000474 debugger = None
475
476 def setdebugger(self, debugger):
477 self.debugger = debugger
478
479 def getdebugger(self):
480 return self.debugger
481
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000482 def open_remote_stack_viewer(self):
483 """Initiate the remote stack viewer from a separate thread.
484
485 This method is called from the subprocess, and by returning from this
486 method we allow the subprocess to unblock. After a bit the shell
487 requests the subprocess to open the remote stack viewer which returns a
488 static object looking at the last exceptiopn. It is queried through
489 the RPC mechanism.
490
491 """
492 self.tkconsole.text.after(300, self.remote_stack_viewer)
493 return
494
Chui Tey5d2af632002-05-26 13:36:41 +0000495 def remote_stack_viewer(self):
496 import RemoteObjectBrowser
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000497 oid = self.rpcclt.remotequeue("exec", "stackviewer", ("flist",), {})
Chui Tey5d2af632002-05-26 13:36:41 +0000498 if oid is None:
499 self.tkconsole.root.bell()
500 return
501 item = RemoteObjectBrowser.StubObjectTreeItem(self.rpcclt, oid)
502 from TreeWidget import ScrolledCanvas, TreeNode
503 top = Toplevel(self.tkconsole.root)
504 sc = ScrolledCanvas(top, bg="white", highlightthickness=0)
505 sc.frame.pack(expand=1, fill="both")
506 node = TreeNode(sc.canvas, None, item)
507 node.expand()
508 # XXX Should GC the remote tree when closing the window
509
David Scherer7aced172000-08-15 01:13:23 +0000510 gid = 0
511
512 def execsource(self, source):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000513 "Like runsource() but assumes complete exec source"
David Scherer7aced172000-08-15 01:13:23 +0000514 filename = self.stuffsource(source)
515 self.execfile(filename, source)
516
517 def execfile(self, filename, source=None):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000518 "Execute an existing file"
David Scherer7aced172000-08-15 01:13:23 +0000519 if source is None:
520 source = open(filename, "r").read()
521 try:
522 code = compile(source, filename, "exec")
523 except (OverflowError, SyntaxError):
524 self.tkconsole.resetoutput()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000525 tkerr = self.tkconsole.stderr
526 print>>tkerr, '*** Error in script or command!\n'
527 print>>tkerr, 'Traceback (most recent call last):'
David Scherer7aced172000-08-15 01:13:23 +0000528 InteractiveInterpreter.showsyntaxerror(self, filename)
Kurt B. Kaiser6e44cc22002-11-30 06:18:00 +0000529 self.tkconsole.showprompt()
David Scherer7aced172000-08-15 01:13:23 +0000530 else:
531 self.runcode(code)
532
533 def runsource(self, source):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000534 "Extend base class method: Stuff the source in the line cache first"
David Scherer7aced172000-08-15 01:13:23 +0000535 filename = self.stuffsource(source)
536 self.more = 0
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000537 self.save_warnings_filters = warnings.filters[:]
538 warnings.filterwarnings(action="error", category=SyntaxWarning)
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +0000539 if isinstance(source, types.UnicodeType):
540 import IOBinding
541 try:
542 source = source.encode(IOBinding.encoding)
543 except UnicodeError:
544 self.tkconsole.resetoutput()
545 self.write("Unsupported characters in input")
546 return
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000547 try:
548 return InteractiveInterpreter.runsource(self, source, filename)
549 finally:
550 if self.save_warnings_filters is not None:
551 warnings.filters[:] = self.save_warnings_filters
552 self.save_warnings_filters = None
David Scherer7aced172000-08-15 01:13:23 +0000553
554 def stuffsource(self, source):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000555 "Stuff source in the filename cache"
David Scherer7aced172000-08-15 01:13:23 +0000556 filename = "<pyshell#%d>" % self.gid
557 self.gid = self.gid + 1
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +0000558 lines = source.split("\n")
David Scherer7aced172000-08-15 01:13:23 +0000559 linecache.cache[filename] = len(source)+1, 0, lines, filename
560 return filename
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000561
Kurt B. Kaiser11659ad2003-05-15 23:23:21 +0000562 def prepend_syspath(self, filename):
563 "Prepend sys.path with file's directory if not already included"
564 self.runcommand("""if 1:
565 _filename = %s
566 import sys as _sys
567 from os.path import dirname as _dirname
568 _dir = _dirname(_filename)
569 if not _dir in _sys.path:
570 _sys.path.insert(0, _dir)
571 del _filename, _sys, _dirname, _dir
572 \n""" % `filename`)
573
David Scherer7aced172000-08-15 01:13:23 +0000574 def showsyntaxerror(self, filename=None):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000575 """Extend base class method: Add Colorizing
576
577 Color the offending position instead of printing it and pointing at it
578 with a caret.
579
580 """
David Scherer7aced172000-08-15 01:13:23 +0000581 text = self.tkconsole.text
582 stuff = self.unpackerror()
Kurt B. Kaiser6e44cc22002-11-30 06:18:00 +0000583 if stuff:
584 msg, lineno, offset, line = stuff
585 if lineno == 1:
586 pos = "iomark + %d chars" % (offset-1)
587 else:
588 pos = "iomark linestart + %d lines + %d chars" % \
589 (lineno-1, offset-1)
590 text.tag_add("ERROR", pos)
591 text.see(pos)
592 char = text.get(pos)
593 if char and char in IDENTCHARS:
594 text.tag_add("ERROR", pos + " wordstart", pos)
595 self.tkconsole.resetoutput()
596 self.write("SyntaxError: %s\n" % str(msg))
597 else:
David Scherer7aced172000-08-15 01:13:23 +0000598 self.tkconsole.resetoutput()
599 InteractiveInterpreter.showsyntaxerror(self, filename)
Kurt B. Kaiser6e44cc22002-11-30 06:18:00 +0000600 self.tkconsole.showprompt()
David Scherer7aced172000-08-15 01:13:23 +0000601
602 def unpackerror(self):
603 type, value, tb = sys.exc_info()
604 ok = type is SyntaxError
605 if ok:
606 try:
607 msg, (dummy_filename, lineno, offset, line) = value
Kurt B. Kaiserbea57c62003-07-09 04:27:24 +0000608 if not offset:
609 offset = 0
David Scherer7aced172000-08-15 01:13:23 +0000610 except:
611 ok = 0
612 if ok:
613 return msg, lineno, offset, line
614 else:
615 return None
616
617 def showtraceback(self):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000618 "Extend base class method to reset output properly"
David Scherer7aced172000-08-15 01:13:23 +0000619 self.tkconsole.resetoutput()
620 self.checklinecache()
621 InteractiveInterpreter.showtraceback(self)
Chui Tey5d2af632002-05-26 13:36:41 +0000622 if self.tkconsole.getvar("<<toggle-jit-stack-viewer>>"):
623 self.tkconsole.open_stack_viewer()
David Scherer7aced172000-08-15 01:13:23 +0000624
625 def checklinecache(self):
626 c = linecache.cache
627 for key in c.keys():
628 if key[:1] + key[-1:] != "<>":
629 del c[key]
630
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000631 def display_executing_dialog(self):
632 tkMessageBox.showerror(
633 "Already executing",
634 "The Python Shell window is already executing a command; "
635 "please wait until it is finished.",
636 master=self.tkconsole.text)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000637
Chui Tey5d2af632002-05-26 13:36:41 +0000638 def runcommand(self, code):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000639 "Run the code without invoking the debugger"
Chui Tey5d2af632002-05-26 13:36:41 +0000640 # The code better not raise an exception!
641 if self.tkconsole.executing:
Neal Norwitzf4c4f112002-11-30 18:49:10 +0000642 self.display_executing_dialog()
Chui Tey5d2af632002-05-26 13:36:41 +0000643 return 0
644 if self.rpcclt:
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000645 self.rpcclt.remotequeue("exec", "runcode", (code,), {})
Chui Tey5d2af632002-05-26 13:36:41 +0000646 else:
647 exec code in self.locals
648 return 1
649
David Scherer7aced172000-08-15 01:13:23 +0000650 def runcode(self, code):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000651 "Override base class method"
Chui Tey5d2af632002-05-26 13:36:41 +0000652 if self.tkconsole.executing:
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000653 self.interp.restart_subprocess()
Chui Tey5d2af632002-05-26 13:36:41 +0000654 self.checklinecache()
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000655 if self.save_warnings_filters is not None:
656 warnings.filters[:] = self.save_warnings_filters
657 self.save_warnings_filters = None
David Scherer7aced172000-08-15 01:13:23 +0000658 debugger = self.debugger
659 try:
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000660 self.tkconsole.beginexecuting()
661 try:
662 if not debugger and self.rpcclt is not None:
663 self.active_seq = self.rpcclt.asyncqueue("exec", "runcode",
664 (code,), {})
665 elif debugger:
666 debugger.run(code, self.locals)
667 else:
668 exec code in self.locals
669 except SystemExit:
670 if tkMessageBox.askyesno(
671 "Exit?",
672 "Do you want to exit altogether?",
673 default="yes",
674 master=self.tkconsole.text):
675 raise
676 else:
677 self.showtraceback()
678 except:
David Scherer7aced172000-08-15 01:13:23 +0000679 self.showtraceback()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000680 finally:
681 if not use_subprocess:
682 self.tkconsole.endexecuting()
David Scherer7aced172000-08-15 01:13:23 +0000683
684 def write(self, s):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000685 "Override base class method"
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000686 self.tkconsole.stderr.write(s)
David Scherer7aced172000-08-15 01:13:23 +0000687
David Scherer7aced172000-08-15 01:13:23 +0000688class PyShell(OutputWindow):
689
690 shell_title = "Python Shell"
691
692 # Override classes
693 ColorDelegator = ModifiedColorDelegator
694 UndoDelegator = ModifiedUndoDelegator
695
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000696 # Override menus
Kurt B. Kaiserdc1e7092002-07-11 04:33:41 +0000697 menu_specs = [
698 ("file", "_File"),
699 ("edit", "_Edit"),
Kurt B. Kaiser4cc5ef52003-01-22 00:23:23 +0000700 ("debug", "_Debug"),
Kurt B. Kaiser1061e722003-01-04 01:43:53 +0000701 ("options", "_Options"),
Kurt B. Kaiserdc1e7092002-07-11 04:33:41 +0000702 ("windows", "_Windows"),
703 ("help", "_Help"),
704 ]
David Scherer7aced172000-08-15 01:13:23 +0000705
706 # New classes
707 from IdleHistory import History
708
709 def __init__(self, flist=None):
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +0000710 if use_subprocess:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000711 ms = self.menu_specs
712 if ms[2][0] != "shell":
713 ms.insert(2, ("shell", "_Shell"))
David Scherer7aced172000-08-15 01:13:23 +0000714 self.interp = ModifiedInterpreter(self)
715 if flist is None:
716 root = Tk()
717 fixwordbreaks(root)
718 root.withdraw()
719 flist = PyShellFileList(root)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000720 #
David Scherer7aced172000-08-15 01:13:23 +0000721 OutputWindow.__init__(self, flist, None, None)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000722 #
David Scherer7aced172000-08-15 01:13:23 +0000723 import __builtin__
724 __builtin__.quit = __builtin__.exit = "To exit, type Ctrl-D."
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000725 #
Kurt B. Kaiseree7afca2002-09-14 02:50:56 +0000726 self.config(usetabs=1, indentwidth=8, context_use_ps1=1)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000727 #
David Scherer7aced172000-08-15 01:13:23 +0000728 text = self.text
729 text.configure(wrap="char")
730 text.bind("<<newline-and-indent>>", self.enter_callback)
731 text.bind("<<plain-newline-and-indent>>", self.linefeed_callback)
732 text.bind("<<interrupt-execution>>", self.cancel_callback)
733 text.bind("<<beginning-of-line>>", self.home_callback)
734 text.bind("<<end-of-file>>", self.eof_callback)
735 text.bind("<<open-stack-viewer>>", self.open_stack_viewer)
Kurt B. Kaiser57bfe5d2003-05-10 00:09:52 +0000736 text.bind("<<toggle-debugger>>", self.toggle_debugger)
David Scherer7aced172000-08-15 01:13:23 +0000737 text.bind("<<open-python-shell>>", self.flist.open_shell)
738 text.bind("<<toggle-jit-stack-viewer>>", self.toggle_jit_stack_viewer)
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +0000739 if use_subprocess:
740 text.bind("<<view-restart>>", self.view_restart_mark)
741 text.bind("<<restart-shell>>", self.restart_shell)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000742 #
David Scherer7aced172000-08-15 01:13:23 +0000743 self.save_stdout = sys.stdout
744 self.save_stderr = sys.stderr
745 self.save_stdin = sys.stdin
Martin v. Löwisbcc651a2003-06-22 07:52:56 +0000746 import IOBinding
747 self.stdout = PseudoFile(self, "stdout", IOBinding.encoding)
748 self.stderr = PseudoFile(self, "stderr", IOBinding.encoding)
749 self.console = PseudoFile(self, "console", IOBinding.encoding)
Chui Tey5d2af632002-05-26 13:36:41 +0000750 if not use_subprocess:
751 sys.stdout = self.stdout
752 sys.stderr = self.stderr
753 sys.stdin = self
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000754 #
David Scherer7aced172000-08-15 01:13:23 +0000755 self.history = self.History(self.text)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000756 #
Kurt B. Kaiser88957d82003-05-19 23:11:51 +0000757 self.pollinterval = 50 # millisec
Chui Tey5d2af632002-05-26 13:36:41 +0000758 if use_subprocess:
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000759 self.interp.start_subprocess()
Chui Tey5d2af632002-05-26 13:36:41 +0000760
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000761 reading = False
762 executing = False
763 canceled = False
764 endoffile = False
765 closing = False
David Scherer7aced172000-08-15 01:13:23 +0000766
767 def toggle_debugger(self, event=None):
768 if self.executing:
769 tkMessageBox.showerror("Don't debug now",
770 "You can only toggle the debugger when idle",
771 master=self.text)
772 self.set_debugger_indicator()
773 return "break"
774 else:
775 db = self.interp.getdebugger()
776 if db:
777 self.close_debugger()
778 else:
779 self.open_debugger()
780
781 def set_debugger_indicator(self):
782 db = self.interp.getdebugger()
783 self.setvar("<<toggle-debugger>>", not not db)
784
Kurt B. Kaiser1061e722003-01-04 01:43:53 +0000785 def toggle_jit_stack_viewer(self, event=None):
David Scherer7aced172000-08-15 01:13:23 +0000786 pass # All we need is the variable
787
788 def close_debugger(self):
789 db = self.interp.getdebugger()
790 if db:
791 self.interp.setdebugger(None)
792 db.close()
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000793 if self.interp.rpcclt:
794 RemoteDebugger.close_remote_debugger(self.interp.rpcclt)
David Scherer7aced172000-08-15 01:13:23 +0000795 self.resetoutput()
796 self.console.write("[DEBUG OFF]\n")
797 sys.ps1 = ">>> "
798 self.showprompt()
799 self.set_debugger_indicator()
800
801 def open_debugger(self):
Chui Tey5d2af632002-05-26 13:36:41 +0000802 if self.interp.rpcclt:
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000803 dbg_gui = RemoteDebugger.start_remote_debugger(self.interp.rpcclt,
804 self)
805 else:
806 dbg_gui = Debugger.Debugger(self)
807 self.interp.setdebugger(dbg_gui)
808 dbg_gui.load_breakpoints()
Chui Tey5d2af632002-05-26 13:36:41 +0000809 sys.ps1 = "[DEBUG ON]\n>>> "
810 self.showprompt()
811 self.set_debugger_indicator()
812
David Scherer7aced172000-08-15 01:13:23 +0000813 def beginexecuting(self):
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000814 "Helper for ModifiedInterpreter"
David Scherer7aced172000-08-15 01:13:23 +0000815 self.resetoutput()
816 self.executing = 1
David Scherer7aced172000-08-15 01:13:23 +0000817
818 def endexecuting(self):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000819 "Helper for ModifiedInterpreter"
David Scherer7aced172000-08-15 01:13:23 +0000820 self.executing = 0
821 self.canceled = 0
Chui Tey5d2af632002-05-26 13:36:41 +0000822 self.showprompt()
David Scherer7aced172000-08-15 01:13:23 +0000823
824 def close(self):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000825 "Extend EditorWindow.close()"
David Scherer7aced172000-08-15 01:13:23 +0000826 if self.executing:
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000827 response = tkMessageBox.askokcancel(
David Scherer7aced172000-08-15 01:13:23 +0000828 "Kill?",
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000829 "The program is still running!\n Do you want to kill it?",
David Scherer7aced172000-08-15 01:13:23 +0000830 default="ok",
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000831 parent=self.text)
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000832 if response == False:
David Scherer7aced172000-08-15 01:13:23 +0000833 return "cancel"
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000834 self.closing = True
835 # Wait for poll_subprocess() rescheduling to stop
836 self.text.after(2 * self.pollinterval, self.close2)
Kurt B. Kaiser88957d82003-05-19 23:11:51 +0000837
838 def close2(self):
839 return EditorWindow.close(self)
David Scherer7aced172000-08-15 01:13:23 +0000840
841 def _close(self):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000842 "Extend EditorWindow._close(), shut down debugger and execution server"
David Scherer7aced172000-08-15 01:13:23 +0000843 self.close_debugger()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000844 if use_subprocess:
845 self.interp.kill_subprocess()
David Scherer7aced172000-08-15 01:13:23 +0000846 # Restore std streams
847 sys.stdout = self.save_stdout
848 sys.stderr = self.save_stderr
849 sys.stdin = self.save_stdin
850 # Break cycles
851 self.interp = None
852 self.console = None
David Scherer7aced172000-08-15 01:13:23 +0000853 self.flist.pyshell = None
854 self.history = None
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000855 EditorWindow._close(self)
David Scherer7aced172000-08-15 01:13:23 +0000856
857 def ispythonsource(self, filename):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000858 "Override EditorWindow method: never remove the colorizer"
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +0000859 return True
David Scherer7aced172000-08-15 01:13:23 +0000860
861 def short_title(self):
862 return self.shell_title
863
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000864 COPYRIGHT = \
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +0000865 'Type "copyright", "credits" or "license()" for more information.'
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000866
David Scherer7aced172000-08-15 01:13:23 +0000867 def begin(self):
868 self.resetoutput()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000869 if use_subprocess:
870 nosub = ''
871 else:
872 nosub = "==== No Subprocess ===="
Kurt B. Kaiserae8bbff2003-06-14 03:23:56 +0000873 self.write("Python %s on %s\n%s\nIDLE %s %s\n" %
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000874 (sys.version, sys.platform, self.COPYRIGHT,
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000875 idlever.IDLE_VERSION, nosub))
David Scherer7aced172000-08-15 01:13:23 +0000876 self.showprompt()
877 import Tkinter
878 Tkinter._default_root = None
879
880 def interact(self):
881 self.begin()
882 self.top.mainloop()
883
884 def readline(self):
885 save = self.reading
886 try:
887 self.reading = 1
888 self.top.mainloop()
889 finally:
890 self.reading = save
891 line = self.text.get("iomark", "end-1c")
Martin v. Löwisbcc651a2003-06-22 07:52:56 +0000892 if isinstance(line, unicode):
893 import IOBinding
894 try:
895 line = line.encode(IOBinding.encoding)
896 except UnicodeError:
897 pass
David Scherer7aced172000-08-15 01:13:23 +0000898 self.resetoutput()
899 if self.canceled:
900 self.canceled = 0
901 raise KeyboardInterrupt
902 if self.endoffile:
903 self.endoffile = 0
904 return ""
905 return line
906
907 def isatty(self):
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +0000908 return True
David Scherer7aced172000-08-15 01:13:23 +0000909
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000910 def cancel_callback(self, event=None):
David Scherer7aced172000-08-15 01:13:23 +0000911 try:
912 if self.text.compare("sel.first", "!=", "sel.last"):
913 return # Active selection -- always use default binding
914 except:
915 pass
916 if not (self.executing or self.reading):
917 self.resetoutput()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000918 self.interp.write("KeyboardInterrupt\n")
David Scherer7aced172000-08-15 01:13:23 +0000919 self.showprompt()
920 return "break"
921 self.endoffile = 0
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000922 self.canceled = 1
David Scherer7aced172000-08-15 01:13:23 +0000923 if self.reading:
924 self.top.quit()
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000925 elif (self.executing and self.interp.rpcclt):
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000926 if self.interp.getdebugger():
927 self.interp.restart_subprocess()
928 else:
929 self.interp.interrupt_subprocess()
David Scherer7aced172000-08-15 01:13:23 +0000930 return "break"
931
932 def eof_callback(self, event):
933 if self.executing and not self.reading:
934 return # Let the default binding (delete next char) take over
935 if not (self.text.compare("iomark", "==", "insert") and
936 self.text.compare("insert", "==", "end-1c")):
937 return # Let the default binding (delete next char) take over
938 if not self.executing:
David Scherer7aced172000-08-15 01:13:23 +0000939 self.resetoutput()
940 self.close()
941 else:
942 self.canceled = 0
943 self.endoffile = 1
944 self.top.quit()
945 return "break"
946
947 def home_callback(self, event):
948 if event.state != 0 and event.keysym == "Home":
949 return # <Modifier-Home>; fall back to class binding
950 if self.text.compare("iomark", "<=", "insert") and \
951 self.text.compare("insert linestart", "<=", "iomark"):
952 self.text.mark_set("insert", "iomark")
953 self.text.tag_remove("sel", "1.0", "end")
954 self.text.see("insert")
955 return "break"
956
957 def linefeed_callback(self, event):
958 # Insert a linefeed without entering anything (still autoindented)
959 if self.reading:
960 self.text.insert("insert", "\n")
961 self.text.see("insert")
962 else:
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +0000963 self.newline_and_indent_event(event)
David Scherer7aced172000-08-15 01:13:23 +0000964 return "break"
965
966 def enter_callback(self, event):
967 if self.executing and not self.reading:
968 return # Let the default binding (insert '\n') take over
969 # If some text is selected, recall the selection
970 # (but only if this before the I/O mark)
971 try:
972 sel = self.text.get("sel.first", "sel.last")
973 if sel:
974 if self.text.compare("sel.last", "<=", "iomark"):
975 self.recall(sel)
976 return "break"
977 except:
978 pass
979 # If we're strictly before the line containing iomark, recall
980 # the current line, less a leading prompt, less leading or
981 # trailing whitespace
982 if self.text.compare("insert", "<", "iomark linestart"):
983 # Check if there's a relevant stdin range -- if so, use it
984 prev = self.text.tag_prevrange("stdin", "insert")
985 if prev and self.text.compare("insert", "<", prev[1]):
986 self.recall(self.text.get(prev[0], prev[1]))
987 return "break"
988 next = self.text.tag_nextrange("stdin", "insert")
989 if next and self.text.compare("insert lineend", ">=", next[0]):
990 self.recall(self.text.get(next[0], next[1]))
991 return "break"
Kurt B. Kaiser4ada7ad2002-12-29 22:03:38 +0000992 # No stdin mark -- just get the current line, less any prompt
993 line = self.text.get("insert linestart", "insert lineend")
994 last_line_of_prompt = sys.ps1.split('\n')[-1]
995 if line.startswith(last_line_of_prompt):
996 line = line[len(last_line_of_prompt):]
997 self.recall(line)
David Scherer7aced172000-08-15 01:13:23 +0000998 return "break"
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +0000999 # If we're between the beginning of the line and the iomark, i.e.
Kurt B. Kaiser4ada7ad2002-12-29 22:03:38 +00001000 # in the prompt area, move to the end of the prompt
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +00001001 if self.text.compare("insert", "<", "iomark"):
Kurt B. Kaiser4ada7ad2002-12-29 22:03:38 +00001002 self.text.mark_set("insert", "iomark")
David Scherer7aced172000-08-15 01:13:23 +00001003 # If we're in the current input and there's only whitespace
1004 # beyond the cursor, erase that whitespace first
1005 s = self.text.get("insert", "end-1c")
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +00001006 if s and not s.strip():
David Scherer7aced172000-08-15 01:13:23 +00001007 self.text.delete("insert", "end-1c")
1008 # If we're in the current input before its last line,
1009 # insert a newline right at the insert point
1010 if self.text.compare("insert", "<", "end-1c linestart"):
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +00001011 self.newline_and_indent_event(event)
David Scherer7aced172000-08-15 01:13:23 +00001012 return "break"
1013 # We're in the last line; append a newline and submit it
1014 self.text.mark_set("insert", "end-1c")
1015 if self.reading:
1016 self.text.insert("insert", "\n")
1017 self.text.see("insert")
1018 else:
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +00001019 self.newline_and_indent_event(event)
David Scherer7aced172000-08-15 01:13:23 +00001020 self.text.tag_add("stdin", "iomark", "end-1c")
1021 self.text.update_idletasks()
1022 if self.reading:
1023 self.top.quit() # Break out of recursive mainloop() in raw_input()
1024 else:
1025 self.runit()
1026 return "break"
1027
1028 def recall(self, s):
1029 if self.history:
1030 self.history.recall(s)
1031
1032 def runit(self):
1033 line = self.text.get("iomark", "end-1c")
1034 # Strip off last newline and surrounding whitespace.
1035 # (To allow you to hit return twice to end a statement.)
1036 i = len(line)
1037 while i > 0 and line[i-1] in " \t":
1038 i = i-1
1039 if i > 0 and line[i-1] == "\n":
1040 i = i-1
1041 while i > 0 and line[i-1] in " \t":
1042 i = i-1
1043 line = line[:i]
1044 more = self.interp.runsource(line)
David Scherer7aced172000-08-15 01:13:23 +00001045
David Scherer7aced172000-08-15 01:13:23 +00001046 def open_stack_viewer(self, event=None):
Chui Tey5d2af632002-05-26 13:36:41 +00001047 if self.interp.rpcclt:
1048 return self.interp.remote_stack_viewer()
David Scherer7aced172000-08-15 01:13:23 +00001049 try:
1050 sys.last_traceback
1051 except:
1052 tkMessageBox.showerror("No stack trace",
1053 "There is no stack trace yet.\n"
1054 "(sys.last_traceback is not defined)",
1055 master=self.text)
1056 return
1057 from StackViewer import StackBrowser
1058 sv = StackBrowser(self.root, self.flist)
1059
Kurt B. Kaiser1061e722003-01-04 01:43:53 +00001060 def view_restart_mark(self, event=None):
1061 self.text.see("iomark")
1062 self.text.see("restart")
1063
1064 def restart_shell(self, event=None):
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +00001065 self.interp.restart_subprocess()
Kurt B. Kaiser1061e722003-01-04 01:43:53 +00001066
David Scherer7aced172000-08-15 01:13:23 +00001067 def showprompt(self):
1068 self.resetoutput()
1069 try:
1070 s = str(sys.ps1)
1071 except:
1072 s = ""
1073 self.console.write(s)
1074 self.text.mark_set("insert", "end-1c")
Chui Tey5d2af632002-05-26 13:36:41 +00001075 self.set_line_and_column()
Kurt B. Kaiserdc1e7092002-07-11 04:33:41 +00001076 self.io.reset_undo()
David Scherer7aced172000-08-15 01:13:23 +00001077
1078 def resetoutput(self):
1079 source = self.text.get("iomark", "end-1c")
1080 if self.history:
1081 self.history.history_store(source)
1082 if self.text.get("end-2c") != "\n":
1083 self.text.insert("end-1c", "\n")
1084 self.text.mark_set("iomark", "end-1c")
Chui Tey5d2af632002-05-26 13:36:41 +00001085 self.set_line_and_column()
David Scherer7aced172000-08-15 01:13:23 +00001086 sys.stdout.softspace = 0
1087
1088 def write(self, s, tags=()):
Kurt B. Kaiser003091c2003-02-17 18:57:16 +00001089 try:
1090 self.text.mark_gravity("iomark", "right")
1091 OutputWindow.write(self, s, tags, "iomark")
1092 self.text.mark_gravity("iomark", "left")
1093 except:
1094 pass
David Scherer7aced172000-08-15 01:13:23 +00001095 if self.canceled:
1096 self.canceled = 0
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +00001097 if not use_subprocess:
1098 raise KeyboardInterrupt
David Scherer7aced172000-08-15 01:13:23 +00001099
1100class PseudoFile:
1101
Martin v. Löwisbcc651a2003-06-22 07:52:56 +00001102 def __init__(self, shell, tags, encoding=None):
David Scherer7aced172000-08-15 01:13:23 +00001103 self.shell = shell
1104 self.tags = tags
Chui Tey5d2af632002-05-26 13:36:41 +00001105 self.softspace = 0
Martin v. Löwisbcc651a2003-06-22 07:52:56 +00001106 self.encoding = encoding
David Scherer7aced172000-08-15 01:13:23 +00001107
1108 def write(self, s):
1109 self.shell.write(s, self.tags)
1110
1111 def writelines(self, l):
1112 map(self.write, l)
1113
1114 def flush(self):
1115 pass
1116
1117 def isatty(self):
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +00001118 return True
David Scherer7aced172000-08-15 01:13:23 +00001119
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001120
David Scherer7aced172000-08-15 01:13:23 +00001121usage_msg = """\
David Scherer7aced172000-08-15 01:13:23 +00001122
Kurt B. Kaiser11659ad2003-05-15 23:23:21 +00001123USAGE: idle [-deins] [-t title] [file]*
1124 idle [-dns] [-t title] (-c cmd | -r file) [arg]*
1125 idle [-dns] [-t title] - [arg]*
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001126
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001127 -h print this help message and exit
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001128 -n run IDLE without a subprocess (see Help/IDLE Help for details)
David Scherer7aced172000-08-15 01:13:23 +00001129
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001130The following options will override the IDLE 'settings' configuration:
Kurt B. Kaiser96d88422001-07-17 04:59:01 +00001131
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001132 -e open an edit window
1133 -i open a shell window
1134
1135The following options imply -i and will open a shell:
1136
1137 -c cmd run the command in a shell, or
1138 -r file run script from file
1139
1140 -d enable the debugger
1141 -s run $IDLESTARTUP or $PYTHONSTARTUP before anything else
1142 -t title set title of shell window
1143
1144A default edit window will be bypassed when -c, -r, or - are used.
1145
1146[arg]* are passed to the command (-c) or script (-r) in sys.argv[1:].
1147
1148Examples:
1149
1150idle
1151 Open an edit window or shell depending on IDLE's configuration.
1152
1153idle foo.py foobar.py
1154 Edit the files, also open a shell if configured to start with shell.
1155
1156idle -est "Baz" foo.py
1157 Run $IDLESTARTUP or $PYTHONSTARTUP, edit foo.py, and open a shell
1158 window with the title "Baz".
1159
1160idle -c "import sys; print sys.argv" "foo"
1161 Open a shell window and run the command, passing "-c" in sys.argv[0]
1162 and "foo" in sys.argv[1].
1163
1164idle -d -s -r foo.py "Hello World"
1165 Open a shell window, run a startup script, enable the debugger, and
1166 run foo.py, passing "foo.py" in sys.argv[0] and "Hello World" in
1167 sys.argv[1].
1168
1169echo "import sys; print sys.argv" | idle - "foobar"
1170 Open a shell window, run the script piped in, passing '' in sys.argv[0]
1171 and "foobar" in sys.argv[1].
David Scherer7aced172000-08-15 01:13:23 +00001172"""
1173
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001174def main():
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001175 global flist, root, use_subprocess
David Scherer7aced172000-08-15 01:13:23 +00001176
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001177 use_subprocess = True
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001178 enable_shell = False
1179 enable_edit = False
1180 debug = False
1181 cmd = None
1182 script = None
1183 startup = False
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001184 try:
Kurt B. Kaiser4ada7ad2002-12-29 22:03:38 +00001185 sys.ps1
1186 except AttributeError:
1187 sys.ps1 = '>>> '
1188 try:
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001189 opts, args = getopt.getopt(sys.argv[1:], "c:deihnr:st:")
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001190 except getopt.error, msg:
1191 sys.stderr.write("Error: %s\n" % str(msg))
1192 sys.stderr.write(usage_msg)
1193 sys.exit(2)
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001194 for o, a in opts:
1195 if o == '-c':
1196 cmd = a
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001197 enable_shell = True
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001198 if o == '-d':
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001199 debug = True
1200 enable_shell = True
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001201 if o == '-e':
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001202 enable_edit = True
1203 if o == '-h':
1204 sys.stdout.write(usage_msg)
1205 sys.exit()
1206 if o == '-i':
1207 enable_shell = True
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001208 if o == '-n':
1209 use_subprocess = False
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001210 if o == '-r':
1211 script = a
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001212 if os.path.isfile(script):
1213 pass
1214 else:
1215 print "No script file: ", script
1216 sys.exit()
1217 enable_shell = True
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001218 if o == '-s':
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001219 startup = True
1220 enable_shell = True
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001221 if o == '-t':
1222 PyShell.shell_title = a
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001223 enable_shell = True
1224 if args and args[0] == '-':
1225 cmd = sys.stdin.read()
1226 enable_shell = True
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001227 # process sys.argv and sys.path:
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001228 for i in range(len(sys.path)):
1229 sys.path[i] = os.path.abspath(sys.path[i])
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001230 if args and args[0] == '-':
1231 sys.argv = [''] + args[1:]
1232 elif cmd:
1233 sys.argv = ['-c'] + args
1234 elif script:
1235 sys.argv = [script] + args
1236 elif args:
1237 enable_edit = True
1238 pathx = []
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001239 for filename in args:
1240 pathx.append(os.path.dirname(filename))
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001241 for dir in pathx:
1242 dir = os.path.abspath(dir)
1243 if not dir in sys.path:
1244 sys.path.insert(0, dir)
Kurt B. Kaiserff002b92002-12-21 21:39:11 +00001245 else:
1246 dir = os.getcwd()
1247 if not dir in sys.path:
1248 sys.path.insert(0, dir)
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001249 # check the IDLE settings configuration (but command line overrides)
1250 edit_start = idleConf.GetOption('main', 'General',
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001251 'editor-on-startup', type='bool')
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001252 enable_edit = enable_edit or edit_start
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001253 enable_shell = enable_shell or not edit_start
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001254 # start editor and/or shell windows:
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001255 root = Tk(className="Idle")
1256 fixwordbreaks(root)
1257 root.withdraw()
1258 flist = PyShellFileList(root)
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001259 if enable_edit:
1260 if not (cmd or script):
1261 for filename in args:
1262 flist.open(filename)
1263 if not args:
1264 flist.new()
1265 if enable_shell:
1266 flist.open_shell()
1267 elif enable_shell:
1268 flist.pyshell = PyShell(flist)
1269 flist.pyshell.begin()
1270 shell = flist.pyshell
1271 # handle remaining options:
1272 if debug:
1273 shell.open_debugger()
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001274 if startup:
1275 filename = os.environ.get("IDLESTARTUP") or \
1276 os.environ.get("PYTHONSTARTUP")
1277 if filename and os.path.isfile(filename):
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001278 shell.interp.execfile(filename)
1279 if cmd or script:
1280 shell.interp.runcommand("""if 1:
1281 import sys as _sys
1282 _sys.argv = %s
1283 del _sys
1284 \n""" % `sys.argv`)
1285 if cmd:
1286 shell.interp.execsource(cmd)
1287 elif script:
Kurt B. Kaiser11659ad2003-05-15 23:23:21 +00001288 shell.interp.prepend_syspath(script)
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001289 shell.interp.execfile(script)
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001290 root.mainloop()
1291 root.destroy()
1292
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001293
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001294def display_port_binding_error():
1295 print """\
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001296\nIDLE cannot run.
Steven M. Gava1f733ba2001-10-07 11:44:49 +00001297
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001298IDLE needs to use a specific TCP/IP port (8833) in order to communicate with
1299its Python execution server. IDLE is unable to bind to this port, and so
1300cannot start. Here are some possible causes of this problem:
Steven M. Gava1f733ba2001-10-07 11:44:49 +00001301
1302 1. TCP/IP networking is not installed or not working on this computer
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001303 2. Another program (another IDLE?) is running that uses this port
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001304 3. Personal firewall software is preventing IDLE from using this port
Steven M. Gava1f733ba2001-10-07 11:44:49 +00001305
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001306Run IDLE with the -n command line switch to start without a subprocess
1307and refer to Help/IDLE Help "Running without a subprocess" for further
1308details.
Steven M. Gava1f733ba2001-10-07 11:44:49 +00001309"""
David Scherer7aced172000-08-15 01:13:23 +00001310
1311if __name__ == "__main__":
Kurt B. Kaiser9e8b8282003-06-15 17:38:45 +00001312 sys.modules['PyShell'] = sys.modules['__main__']
David Scherer7aced172000-08-15 01:13:23 +00001313 main()