blob: 83f2de8b9af9190c29a5c2ff294460161eee74a7 [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 = []
David Scherer7aced172000-08-15 01:13:23 +000080 apply(EditorWindow.__init__, (self,) + args)
81 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
608 except:
609 ok = 0
610 if ok:
611 return msg, lineno, offset, line
612 else:
613 return None
614
615 def showtraceback(self):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000616 "Extend base class method to reset output properly"
David Scherer7aced172000-08-15 01:13:23 +0000617 self.tkconsole.resetoutput()
618 self.checklinecache()
619 InteractiveInterpreter.showtraceback(self)
Chui Tey5d2af632002-05-26 13:36:41 +0000620 if self.tkconsole.getvar("<<toggle-jit-stack-viewer>>"):
621 self.tkconsole.open_stack_viewer()
David Scherer7aced172000-08-15 01:13:23 +0000622
623 def checklinecache(self):
624 c = linecache.cache
625 for key in c.keys():
626 if key[:1] + key[-1:] != "<>":
627 del c[key]
628
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000629 def display_executing_dialog(self):
630 tkMessageBox.showerror(
631 "Already executing",
632 "The Python Shell window is already executing a command; "
633 "please wait until it is finished.",
634 master=self.tkconsole.text)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000635
Chui Tey5d2af632002-05-26 13:36:41 +0000636 def runcommand(self, code):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000637 "Run the code without invoking the debugger"
Chui Tey5d2af632002-05-26 13:36:41 +0000638 # The code better not raise an exception!
639 if self.tkconsole.executing:
Neal Norwitzf4c4f112002-11-30 18:49:10 +0000640 self.display_executing_dialog()
Chui Tey5d2af632002-05-26 13:36:41 +0000641 return 0
642 if self.rpcclt:
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000643 self.rpcclt.remotequeue("exec", "runcode", (code,), {})
Chui Tey5d2af632002-05-26 13:36:41 +0000644 else:
645 exec code in self.locals
646 return 1
647
David Scherer7aced172000-08-15 01:13:23 +0000648 def runcode(self, code):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000649 "Override base class method"
Chui Tey5d2af632002-05-26 13:36:41 +0000650 if self.tkconsole.executing:
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000651 self.interp.restart_subprocess()
Chui Tey5d2af632002-05-26 13:36:41 +0000652 self.checklinecache()
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000653 if self.save_warnings_filters is not None:
654 warnings.filters[:] = self.save_warnings_filters
655 self.save_warnings_filters = None
David Scherer7aced172000-08-15 01:13:23 +0000656 debugger = self.debugger
657 try:
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000658 self.tkconsole.beginexecuting()
659 try:
660 if not debugger and self.rpcclt is not None:
661 self.active_seq = self.rpcclt.asyncqueue("exec", "runcode",
662 (code,), {})
663 elif debugger:
664 debugger.run(code, self.locals)
665 else:
666 exec code in self.locals
667 except SystemExit:
668 if tkMessageBox.askyesno(
669 "Exit?",
670 "Do you want to exit altogether?",
671 default="yes",
672 master=self.tkconsole.text):
673 raise
674 else:
675 self.showtraceback()
676 except:
David Scherer7aced172000-08-15 01:13:23 +0000677 self.showtraceback()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000678 finally:
679 if not use_subprocess:
680 self.tkconsole.endexecuting()
David Scherer7aced172000-08-15 01:13:23 +0000681
682 def write(self, s):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000683 "Override base class method"
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000684 self.tkconsole.stderr.write(s)
David Scherer7aced172000-08-15 01:13:23 +0000685
David Scherer7aced172000-08-15 01:13:23 +0000686class PyShell(OutputWindow):
687
688 shell_title = "Python Shell"
689
690 # Override classes
691 ColorDelegator = ModifiedColorDelegator
692 UndoDelegator = ModifiedUndoDelegator
693
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000694 # Override menus
Kurt B. Kaiserdc1e7092002-07-11 04:33:41 +0000695 menu_specs = [
696 ("file", "_File"),
697 ("edit", "_Edit"),
Kurt B. Kaiser4cc5ef52003-01-22 00:23:23 +0000698 ("debug", "_Debug"),
Kurt B. Kaiser1061e722003-01-04 01:43:53 +0000699 ("options", "_Options"),
Kurt B. Kaiserdc1e7092002-07-11 04:33:41 +0000700 ("windows", "_Windows"),
701 ("help", "_Help"),
702 ]
David Scherer7aced172000-08-15 01:13:23 +0000703
704 # New classes
705 from IdleHistory import History
706
707 def __init__(self, flist=None):
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +0000708 if use_subprocess:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000709 ms = self.menu_specs
710 if ms[2][0] != "shell":
711 ms.insert(2, ("shell", "_Shell"))
David Scherer7aced172000-08-15 01:13:23 +0000712 self.interp = ModifiedInterpreter(self)
713 if flist is None:
714 root = Tk()
715 fixwordbreaks(root)
716 root.withdraw()
717 flist = PyShellFileList(root)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000718 #
David Scherer7aced172000-08-15 01:13:23 +0000719 OutputWindow.__init__(self, flist, None, None)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000720 #
David Scherer7aced172000-08-15 01:13:23 +0000721 import __builtin__
722 __builtin__.quit = __builtin__.exit = "To exit, type Ctrl-D."
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000723 #
Kurt B. Kaiseree7afca2002-09-14 02:50:56 +0000724 self.config(usetabs=1, indentwidth=8, context_use_ps1=1)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000725 #
David Scherer7aced172000-08-15 01:13:23 +0000726 text = self.text
727 text.configure(wrap="char")
728 text.bind("<<newline-and-indent>>", self.enter_callback)
729 text.bind("<<plain-newline-and-indent>>", self.linefeed_callback)
730 text.bind("<<interrupt-execution>>", self.cancel_callback)
731 text.bind("<<beginning-of-line>>", self.home_callback)
732 text.bind("<<end-of-file>>", self.eof_callback)
733 text.bind("<<open-stack-viewer>>", self.open_stack_viewer)
Kurt B. Kaiser57bfe5d2003-05-10 00:09:52 +0000734 text.bind("<<toggle-debugger>>", self.toggle_debugger)
David Scherer7aced172000-08-15 01:13:23 +0000735 text.bind("<<open-python-shell>>", self.flist.open_shell)
736 text.bind("<<toggle-jit-stack-viewer>>", self.toggle_jit_stack_viewer)
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +0000737 if use_subprocess:
738 text.bind("<<view-restart>>", self.view_restart_mark)
739 text.bind("<<restart-shell>>", self.restart_shell)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000740 #
David Scherer7aced172000-08-15 01:13:23 +0000741 self.save_stdout = sys.stdout
742 self.save_stderr = sys.stderr
743 self.save_stdin = sys.stdin
Martin v. Löwisbcc651a2003-06-22 07:52:56 +0000744 import IOBinding
745 self.stdout = PseudoFile(self, "stdout", IOBinding.encoding)
746 self.stderr = PseudoFile(self, "stderr", IOBinding.encoding)
747 self.console = PseudoFile(self, "console", IOBinding.encoding)
Chui Tey5d2af632002-05-26 13:36:41 +0000748 if not use_subprocess:
749 sys.stdout = self.stdout
750 sys.stderr = self.stderr
751 sys.stdin = self
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000752 #
David Scherer7aced172000-08-15 01:13:23 +0000753 self.history = self.History(self.text)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000754 #
Kurt B. Kaiser88957d82003-05-19 23:11:51 +0000755 self.pollinterval = 50 # millisec
Chui Tey5d2af632002-05-26 13:36:41 +0000756 if use_subprocess:
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000757 self.interp.start_subprocess()
Chui Tey5d2af632002-05-26 13:36:41 +0000758
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000759 reading = False
760 executing = False
761 canceled = False
762 endoffile = False
763 closing = False
David Scherer7aced172000-08-15 01:13:23 +0000764
765 def toggle_debugger(self, event=None):
766 if self.executing:
767 tkMessageBox.showerror("Don't debug now",
768 "You can only toggle the debugger when idle",
769 master=self.text)
770 self.set_debugger_indicator()
771 return "break"
772 else:
773 db = self.interp.getdebugger()
774 if db:
775 self.close_debugger()
776 else:
777 self.open_debugger()
778
779 def set_debugger_indicator(self):
780 db = self.interp.getdebugger()
781 self.setvar("<<toggle-debugger>>", not not db)
782
Kurt B. Kaiser1061e722003-01-04 01:43:53 +0000783 def toggle_jit_stack_viewer(self, event=None):
David Scherer7aced172000-08-15 01:13:23 +0000784 pass # All we need is the variable
785
786 def close_debugger(self):
787 db = self.interp.getdebugger()
788 if db:
789 self.interp.setdebugger(None)
790 db.close()
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000791 if self.interp.rpcclt:
792 RemoteDebugger.close_remote_debugger(self.interp.rpcclt)
David Scherer7aced172000-08-15 01:13:23 +0000793 self.resetoutput()
794 self.console.write("[DEBUG OFF]\n")
795 sys.ps1 = ">>> "
796 self.showprompt()
797 self.set_debugger_indicator()
798
799 def open_debugger(self):
Chui Tey5d2af632002-05-26 13:36:41 +0000800 if self.interp.rpcclt:
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000801 dbg_gui = RemoteDebugger.start_remote_debugger(self.interp.rpcclt,
802 self)
803 else:
804 dbg_gui = Debugger.Debugger(self)
805 self.interp.setdebugger(dbg_gui)
806 dbg_gui.load_breakpoints()
Chui Tey5d2af632002-05-26 13:36:41 +0000807 sys.ps1 = "[DEBUG ON]\n>>> "
808 self.showprompt()
809 self.set_debugger_indicator()
810
David Scherer7aced172000-08-15 01:13:23 +0000811 def beginexecuting(self):
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000812 "Helper for ModifiedInterpreter"
David Scherer7aced172000-08-15 01:13:23 +0000813 self.resetoutput()
814 self.executing = 1
David Scherer7aced172000-08-15 01:13:23 +0000815
816 def endexecuting(self):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000817 "Helper for ModifiedInterpreter"
David Scherer7aced172000-08-15 01:13:23 +0000818 self.executing = 0
819 self.canceled = 0
Chui Tey5d2af632002-05-26 13:36:41 +0000820 self.showprompt()
David Scherer7aced172000-08-15 01:13:23 +0000821
822 def close(self):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000823 "Extend EditorWindow.close()"
David Scherer7aced172000-08-15 01:13:23 +0000824 if self.executing:
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000825 response = tkMessageBox.askokcancel(
David Scherer7aced172000-08-15 01:13:23 +0000826 "Kill?",
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000827 "The program is still running!\n Do you want to kill it?",
David Scherer7aced172000-08-15 01:13:23 +0000828 default="ok",
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000829 parent=self.text)
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000830 if response == False:
David Scherer7aced172000-08-15 01:13:23 +0000831 return "cancel"
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000832 self.closing = True
833 # Wait for poll_subprocess() rescheduling to stop
834 self.text.after(2 * self.pollinterval, self.close2)
Kurt B. Kaiser88957d82003-05-19 23:11:51 +0000835
836 def close2(self):
837 return EditorWindow.close(self)
David Scherer7aced172000-08-15 01:13:23 +0000838
839 def _close(self):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000840 "Extend EditorWindow._close(), shut down debugger and execution server"
David Scherer7aced172000-08-15 01:13:23 +0000841 self.close_debugger()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000842 if use_subprocess:
843 self.interp.kill_subprocess()
David Scherer7aced172000-08-15 01:13:23 +0000844 # Restore std streams
845 sys.stdout = self.save_stdout
846 sys.stderr = self.save_stderr
847 sys.stdin = self.save_stdin
848 # Break cycles
849 self.interp = None
850 self.console = None
David Scherer7aced172000-08-15 01:13:23 +0000851 self.flist.pyshell = None
852 self.history = None
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000853 EditorWindow._close(self)
David Scherer7aced172000-08-15 01:13:23 +0000854
855 def ispythonsource(self, filename):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000856 "Override EditorWindow method: never remove the colorizer"
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +0000857 return True
David Scherer7aced172000-08-15 01:13:23 +0000858
859 def short_title(self):
860 return self.shell_title
861
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000862 COPYRIGHT = \
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +0000863 'Type "copyright", "credits" or "license()" for more information.'
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000864
David Scherer7aced172000-08-15 01:13:23 +0000865 def begin(self):
866 self.resetoutput()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000867 if use_subprocess:
868 nosub = ''
869 else:
870 nosub = "==== No Subprocess ===="
Kurt B. Kaiserae8bbff2003-06-14 03:23:56 +0000871 self.write("Python %s on %s\n%s\nIDLE %s %s\n" %
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000872 (sys.version, sys.platform, self.COPYRIGHT,
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000873 idlever.IDLE_VERSION, nosub))
David Scherer7aced172000-08-15 01:13:23 +0000874 self.showprompt()
875 import Tkinter
876 Tkinter._default_root = None
877
878 def interact(self):
879 self.begin()
880 self.top.mainloop()
881
882 def readline(self):
883 save = self.reading
884 try:
885 self.reading = 1
886 self.top.mainloop()
887 finally:
888 self.reading = save
889 line = self.text.get("iomark", "end-1c")
Martin v. Löwisbcc651a2003-06-22 07:52:56 +0000890 if isinstance(line, unicode):
891 import IOBinding
892 try:
893 line = line.encode(IOBinding.encoding)
894 except UnicodeError:
895 pass
David Scherer7aced172000-08-15 01:13:23 +0000896 self.resetoutput()
897 if self.canceled:
898 self.canceled = 0
899 raise KeyboardInterrupt
900 if self.endoffile:
901 self.endoffile = 0
902 return ""
903 return line
904
905 def isatty(self):
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +0000906 return True
David Scherer7aced172000-08-15 01:13:23 +0000907
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000908 def cancel_callback(self, event=None):
David Scherer7aced172000-08-15 01:13:23 +0000909 try:
910 if self.text.compare("sel.first", "!=", "sel.last"):
911 return # Active selection -- always use default binding
912 except:
913 pass
914 if not (self.executing or self.reading):
915 self.resetoutput()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000916 self.interp.write("KeyboardInterrupt\n")
David Scherer7aced172000-08-15 01:13:23 +0000917 self.showprompt()
918 return "break"
919 self.endoffile = 0
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000920 self.canceled = 1
David Scherer7aced172000-08-15 01:13:23 +0000921 if self.reading:
922 self.top.quit()
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000923 elif (self.executing and self.interp.rpcclt):
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000924 if self.interp.getdebugger():
925 self.interp.restart_subprocess()
926 else:
927 self.interp.interrupt_subprocess()
David Scherer7aced172000-08-15 01:13:23 +0000928 return "break"
929
930 def eof_callback(self, event):
931 if self.executing and not self.reading:
932 return # Let the default binding (delete next char) take over
933 if not (self.text.compare("iomark", "==", "insert") and
934 self.text.compare("insert", "==", "end-1c")):
935 return # Let the default binding (delete next char) take over
936 if not self.executing:
David Scherer7aced172000-08-15 01:13:23 +0000937 self.resetoutput()
938 self.close()
939 else:
940 self.canceled = 0
941 self.endoffile = 1
942 self.top.quit()
943 return "break"
944
945 def home_callback(self, event):
946 if event.state != 0 and event.keysym == "Home":
947 return # <Modifier-Home>; fall back to class binding
948 if self.text.compare("iomark", "<=", "insert") and \
949 self.text.compare("insert linestart", "<=", "iomark"):
950 self.text.mark_set("insert", "iomark")
951 self.text.tag_remove("sel", "1.0", "end")
952 self.text.see("insert")
953 return "break"
954
955 def linefeed_callback(self, event):
956 # Insert a linefeed without entering anything (still autoindented)
957 if self.reading:
958 self.text.insert("insert", "\n")
959 self.text.see("insert")
960 else:
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +0000961 self.newline_and_indent_event(event)
David Scherer7aced172000-08-15 01:13:23 +0000962 return "break"
963
964 def enter_callback(self, event):
965 if self.executing and not self.reading:
966 return # Let the default binding (insert '\n') take over
967 # If some text is selected, recall the selection
968 # (but only if this before the I/O mark)
969 try:
970 sel = self.text.get("sel.first", "sel.last")
971 if sel:
972 if self.text.compare("sel.last", "<=", "iomark"):
973 self.recall(sel)
974 return "break"
975 except:
976 pass
977 # If we're strictly before the line containing iomark, recall
978 # the current line, less a leading prompt, less leading or
979 # trailing whitespace
980 if self.text.compare("insert", "<", "iomark linestart"):
981 # Check if there's a relevant stdin range -- if so, use it
982 prev = self.text.tag_prevrange("stdin", "insert")
983 if prev and self.text.compare("insert", "<", prev[1]):
984 self.recall(self.text.get(prev[0], prev[1]))
985 return "break"
986 next = self.text.tag_nextrange("stdin", "insert")
987 if next and self.text.compare("insert lineend", ">=", next[0]):
988 self.recall(self.text.get(next[0], next[1]))
989 return "break"
Kurt B. Kaiser4ada7ad2002-12-29 22:03:38 +0000990 # No stdin mark -- just get the current line, less any prompt
991 line = self.text.get("insert linestart", "insert lineend")
992 last_line_of_prompt = sys.ps1.split('\n')[-1]
993 if line.startswith(last_line_of_prompt):
994 line = line[len(last_line_of_prompt):]
995 self.recall(line)
David Scherer7aced172000-08-15 01:13:23 +0000996 return "break"
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +0000997 # If we're between the beginning of the line and the iomark, i.e.
Kurt B. Kaiser4ada7ad2002-12-29 22:03:38 +0000998 # in the prompt area, move to the end of the prompt
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +0000999 if self.text.compare("insert", "<", "iomark"):
Kurt B. Kaiser4ada7ad2002-12-29 22:03:38 +00001000 self.text.mark_set("insert", "iomark")
David Scherer7aced172000-08-15 01:13:23 +00001001 # If we're in the current input and there's only whitespace
1002 # beyond the cursor, erase that whitespace first
1003 s = self.text.get("insert", "end-1c")
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +00001004 if s and not s.strip():
David Scherer7aced172000-08-15 01:13:23 +00001005 self.text.delete("insert", "end-1c")
1006 # If we're in the current input before its last line,
1007 # insert a newline right at the insert point
1008 if self.text.compare("insert", "<", "end-1c linestart"):
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +00001009 self.newline_and_indent_event(event)
David Scherer7aced172000-08-15 01:13:23 +00001010 return "break"
1011 # We're in the last line; append a newline and submit it
1012 self.text.mark_set("insert", "end-1c")
1013 if self.reading:
1014 self.text.insert("insert", "\n")
1015 self.text.see("insert")
1016 else:
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +00001017 self.newline_and_indent_event(event)
David Scherer7aced172000-08-15 01:13:23 +00001018 self.text.tag_add("stdin", "iomark", "end-1c")
1019 self.text.update_idletasks()
1020 if self.reading:
1021 self.top.quit() # Break out of recursive mainloop() in raw_input()
1022 else:
1023 self.runit()
1024 return "break"
1025
1026 def recall(self, s):
1027 if self.history:
1028 self.history.recall(s)
1029
1030 def runit(self):
1031 line = self.text.get("iomark", "end-1c")
1032 # Strip off last newline and surrounding whitespace.
1033 # (To allow you to hit return twice to end a statement.)
1034 i = len(line)
1035 while i > 0 and line[i-1] in " \t":
1036 i = i-1
1037 if i > 0 and line[i-1] == "\n":
1038 i = i-1
1039 while i > 0 and line[i-1] in " \t":
1040 i = i-1
1041 line = line[:i]
1042 more = self.interp.runsource(line)
David Scherer7aced172000-08-15 01:13:23 +00001043
David Scherer7aced172000-08-15 01:13:23 +00001044 def open_stack_viewer(self, event=None):
Chui Tey5d2af632002-05-26 13:36:41 +00001045 if self.interp.rpcclt:
1046 return self.interp.remote_stack_viewer()
David Scherer7aced172000-08-15 01:13:23 +00001047 try:
1048 sys.last_traceback
1049 except:
1050 tkMessageBox.showerror("No stack trace",
1051 "There is no stack trace yet.\n"
1052 "(sys.last_traceback is not defined)",
1053 master=self.text)
1054 return
1055 from StackViewer import StackBrowser
1056 sv = StackBrowser(self.root, self.flist)
1057
Kurt B. Kaiser1061e722003-01-04 01:43:53 +00001058 def view_restart_mark(self, event=None):
1059 self.text.see("iomark")
1060 self.text.see("restart")
1061
1062 def restart_shell(self, event=None):
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +00001063 self.interp.restart_subprocess()
Kurt B. Kaiser1061e722003-01-04 01:43:53 +00001064
David Scherer7aced172000-08-15 01:13:23 +00001065 def showprompt(self):
1066 self.resetoutput()
1067 try:
1068 s = str(sys.ps1)
1069 except:
1070 s = ""
1071 self.console.write(s)
1072 self.text.mark_set("insert", "end-1c")
Chui Tey5d2af632002-05-26 13:36:41 +00001073 self.set_line_and_column()
Kurt B. Kaiserdc1e7092002-07-11 04:33:41 +00001074 self.io.reset_undo()
David Scherer7aced172000-08-15 01:13:23 +00001075
1076 def resetoutput(self):
1077 source = self.text.get("iomark", "end-1c")
1078 if self.history:
1079 self.history.history_store(source)
1080 if self.text.get("end-2c") != "\n":
1081 self.text.insert("end-1c", "\n")
1082 self.text.mark_set("iomark", "end-1c")
Chui Tey5d2af632002-05-26 13:36:41 +00001083 self.set_line_and_column()
David Scherer7aced172000-08-15 01:13:23 +00001084 sys.stdout.softspace = 0
1085
1086 def write(self, s, tags=()):
Kurt B. Kaiser003091c2003-02-17 18:57:16 +00001087 try:
1088 self.text.mark_gravity("iomark", "right")
1089 OutputWindow.write(self, s, tags, "iomark")
1090 self.text.mark_gravity("iomark", "left")
1091 except:
1092 pass
David Scherer7aced172000-08-15 01:13:23 +00001093 if self.canceled:
1094 self.canceled = 0
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +00001095 if not use_subprocess:
1096 raise KeyboardInterrupt
David Scherer7aced172000-08-15 01:13:23 +00001097
1098class PseudoFile:
1099
Martin v. Löwisbcc651a2003-06-22 07:52:56 +00001100 def __init__(self, shell, tags, encoding=None):
David Scherer7aced172000-08-15 01:13:23 +00001101 self.shell = shell
1102 self.tags = tags
Chui Tey5d2af632002-05-26 13:36:41 +00001103 self.softspace = 0
Martin v. Löwisbcc651a2003-06-22 07:52:56 +00001104 self.encoding = encoding
David Scherer7aced172000-08-15 01:13:23 +00001105
1106 def write(self, s):
1107 self.shell.write(s, self.tags)
1108
1109 def writelines(self, l):
1110 map(self.write, l)
1111
1112 def flush(self):
1113 pass
1114
1115 def isatty(self):
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +00001116 return True
David Scherer7aced172000-08-15 01:13:23 +00001117
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001118
David Scherer7aced172000-08-15 01:13:23 +00001119usage_msg = """\
David Scherer7aced172000-08-15 01:13:23 +00001120
Kurt B. Kaiser11659ad2003-05-15 23:23:21 +00001121USAGE: idle [-deins] [-t title] [file]*
1122 idle [-dns] [-t title] (-c cmd | -r file) [arg]*
1123 idle [-dns] [-t title] - [arg]*
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001124
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001125 -h print this help message and exit
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001126 -n run IDLE without a subprocess (see Help/IDLE Help for details)
David Scherer7aced172000-08-15 01:13:23 +00001127
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001128The following options will override the IDLE 'settings' configuration:
Kurt B. Kaiser96d88422001-07-17 04:59:01 +00001129
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001130 -e open an edit window
1131 -i open a shell window
1132
1133The following options imply -i and will open a shell:
1134
1135 -c cmd run the command in a shell, or
1136 -r file run script from file
1137
1138 -d enable the debugger
1139 -s run $IDLESTARTUP or $PYTHONSTARTUP before anything else
1140 -t title set title of shell window
1141
1142A default edit window will be bypassed when -c, -r, or - are used.
1143
1144[arg]* are passed to the command (-c) or script (-r) in sys.argv[1:].
1145
1146Examples:
1147
1148idle
1149 Open an edit window or shell depending on IDLE's configuration.
1150
1151idle foo.py foobar.py
1152 Edit the files, also open a shell if configured to start with shell.
1153
1154idle -est "Baz" foo.py
1155 Run $IDLESTARTUP or $PYTHONSTARTUP, edit foo.py, and open a shell
1156 window with the title "Baz".
1157
1158idle -c "import sys; print sys.argv" "foo"
1159 Open a shell window and run the command, passing "-c" in sys.argv[0]
1160 and "foo" in sys.argv[1].
1161
1162idle -d -s -r foo.py "Hello World"
1163 Open a shell window, run a startup script, enable the debugger, and
1164 run foo.py, passing "foo.py" in sys.argv[0] and "Hello World" in
1165 sys.argv[1].
1166
1167echo "import sys; print sys.argv" | idle - "foobar"
1168 Open a shell window, run the script piped in, passing '' in sys.argv[0]
1169 and "foobar" in sys.argv[1].
David Scherer7aced172000-08-15 01:13:23 +00001170"""
1171
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001172def main():
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001173 global flist, root, use_subprocess
David Scherer7aced172000-08-15 01:13:23 +00001174
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001175 use_subprocess = True
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001176 enable_shell = False
1177 enable_edit = False
1178 debug = False
1179 cmd = None
1180 script = None
1181 startup = False
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001182 try:
Kurt B. Kaiser4ada7ad2002-12-29 22:03:38 +00001183 sys.ps1
1184 except AttributeError:
1185 sys.ps1 = '>>> '
1186 try:
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001187 opts, args = getopt.getopt(sys.argv[1:], "c:deihnr:st:")
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001188 except getopt.error, msg:
1189 sys.stderr.write("Error: %s\n" % str(msg))
1190 sys.stderr.write(usage_msg)
1191 sys.exit(2)
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001192 for o, a in opts:
1193 if o == '-c':
1194 cmd = a
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001195 enable_shell = True
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001196 if o == '-d':
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001197 debug = True
1198 enable_shell = True
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001199 if o == '-e':
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001200 enable_edit = True
1201 if o == '-h':
1202 sys.stdout.write(usage_msg)
1203 sys.exit()
1204 if o == '-i':
1205 enable_shell = True
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001206 if o == '-n':
1207 use_subprocess = False
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001208 if o == '-r':
1209 script = a
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001210 if os.path.isfile(script):
1211 pass
1212 else:
1213 print "No script file: ", script
1214 sys.exit()
1215 enable_shell = True
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001216 if o == '-s':
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001217 startup = True
1218 enable_shell = True
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001219 if o == '-t':
1220 PyShell.shell_title = a
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001221 enable_shell = True
1222 if args and args[0] == '-':
1223 cmd = sys.stdin.read()
1224 enable_shell = True
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001225 # process sys.argv and sys.path:
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001226 for i in range(len(sys.path)):
1227 sys.path[i] = os.path.abspath(sys.path[i])
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001228 if args and args[0] == '-':
1229 sys.argv = [''] + args[1:]
1230 elif cmd:
1231 sys.argv = ['-c'] + args
1232 elif script:
1233 sys.argv = [script] + args
1234 elif args:
1235 enable_edit = True
1236 pathx = []
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001237 for filename in args:
1238 pathx.append(os.path.dirname(filename))
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001239 for dir in pathx:
1240 dir = os.path.abspath(dir)
1241 if not dir in sys.path:
1242 sys.path.insert(0, dir)
Kurt B. Kaiserff002b92002-12-21 21:39:11 +00001243 else:
1244 dir = os.getcwd()
1245 if not dir in sys.path:
1246 sys.path.insert(0, dir)
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001247 # check the IDLE settings configuration (but command line overrides)
1248 edit_start = idleConf.GetOption('main', 'General',
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001249 'editor-on-startup', type='bool')
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001250 enable_edit = enable_edit or edit_start
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001251 enable_shell = enable_shell or not edit_start
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001252 # start editor and/or shell windows:
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001253 root = Tk(className="Idle")
1254 fixwordbreaks(root)
1255 root.withdraw()
1256 flist = PyShellFileList(root)
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001257 if enable_edit:
1258 if not (cmd or script):
1259 for filename in args:
1260 flist.open(filename)
1261 if not args:
1262 flist.new()
1263 if enable_shell:
1264 flist.open_shell()
1265 elif enable_shell:
1266 flist.pyshell = PyShell(flist)
1267 flist.pyshell.begin()
1268 shell = flist.pyshell
1269 # handle remaining options:
1270 if debug:
1271 shell.open_debugger()
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001272 if startup:
1273 filename = os.environ.get("IDLESTARTUP") or \
1274 os.environ.get("PYTHONSTARTUP")
1275 if filename and os.path.isfile(filename):
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001276 shell.interp.execfile(filename)
1277 if cmd or script:
1278 shell.interp.runcommand("""if 1:
1279 import sys as _sys
1280 _sys.argv = %s
1281 del _sys
1282 \n""" % `sys.argv`)
1283 if cmd:
1284 shell.interp.execsource(cmd)
1285 elif script:
Kurt B. Kaiser11659ad2003-05-15 23:23:21 +00001286 shell.interp.prepend_syspath(script)
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001287 shell.interp.execfile(script)
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001288 root.mainloop()
1289 root.destroy()
1290
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001291
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001292def display_port_binding_error():
1293 print """\
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001294\nIDLE cannot run.
Steven M. Gava1f733ba2001-10-07 11:44:49 +00001295
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001296IDLE needs to use a specific TCP/IP port (8833) in order to communicate with
1297its Python execution server. IDLE is unable to bind to this port, and so
1298cannot start. Here are some possible causes of this problem:
Steven M. Gava1f733ba2001-10-07 11:44:49 +00001299
1300 1. TCP/IP networking is not installed or not working on this computer
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001301 2. Another program (another IDLE?) is running that uses this port
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001302 3. Personal firewall software is preventing IDLE from using this port
Steven M. Gava1f733ba2001-10-07 11:44:49 +00001303
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001304Run IDLE with the -n command line switch to start without a subprocess
1305and refer to Help/IDLE Help "Running without a subprocess" for further
1306details.
Steven M. Gava1f733ba2001-10-07 11:44:49 +00001307"""
David Scherer7aced172000-08-15 01:13:23 +00001308
1309if __name__ == "__main__":
Kurt B. Kaiser9e8b8282003-06-15 17:38:45 +00001310 sys.modules['PyShell'] = sys.modules['__main__']
David Scherer7aced172000-08-15 01:13:23 +00001311 main()