Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / sam-t2 / devtools / amd64 / lib / python2.4 / idlelib / PyShell.py
CommitLineData
920dae64
AT
1#! /usr/bin/env python
2
3import os
4import os.path
5import sys
6import string
7import getopt
8import re
9import socket
10import time
11import threading
12import traceback
13import types
14import exceptions
15
16import linecache
17from code import InteractiveInterpreter
18
19try:
20 from Tkinter import *
21except ImportError:
22 print>>sys.__stderr__, "** IDLE can't import Tkinter. " \
23 "Your Python may not be configured for Tk. **"
24 sys.exit(1)
25import tkMessageBox
26
27from EditorWindow import EditorWindow, fixwordbreaks
28from FileList import FileList
29from ColorDelegator import ColorDelegator
30from UndoDelegator import UndoDelegator
31from OutputWindow import OutputWindow
32from configHandler import idleConf
33import idlever
34
35import rpc
36import Debugger
37import RemoteDebugger
38
39IDENTCHARS = string.ascii_letters + string.digits + "_"
40LOCALHOST = '127.0.0.1'
41
42try:
43 from signal import SIGTERM
44except ImportError:
45 SIGTERM = 15
46
47# Override warnings module to write to warning_stream. Initialize to send IDLE
48# internal warnings to the console. ScriptBinding.check_syntax() will
49# temporarily redirect the stream to the shell window to display warnings when
50# checking user's code.
51global warning_stream
52warning_stream = sys.__stderr__
53try:
54 import warnings
55except ImportError:
56 pass
57else:
58 def idle_showwarning(message, category, filename, lineno):
59 file = warning_stream
60 try:
61 file.write(warnings.formatwarning(message, category, filename, lineno))
62 except IOError:
63 pass ## file (probably __stderr__) is invalid, warning dropped.
64 warnings.showwarning = idle_showwarning
65 def idle_formatwarning(message, category, filename, lineno):
66 """Format warnings the IDLE way"""
67 s = "\nWarning (from warnings module):\n"
68 s += ' File \"%s\", line %s\n' % (filename, lineno)
69 line = linecache.getline(filename, lineno).strip()
70 if line:
71 s += " %s\n" % line
72 s += "%s: %s\n>>> " % (category.__name__, message)
73 return s
74 warnings.formatwarning = idle_formatwarning
75
76def extended_linecache_checkcache(filename=None,
77 orig_checkcache=linecache.checkcache):
78 """Extend linecache.checkcache to preserve the <pyshell#...> entries
79
80 Rather than repeating the linecache code, patch it to save the
81 <pyshell#...> entries, call the original linecache.checkcache()
82 (which destroys them), and then restore the saved entries.
83
84 orig_checkcache is bound at definition time to the original
85 method, allowing it to be patched.
86
87 """
88 cache = linecache.cache
89 save = {}
90 for filename in cache.keys():
91 if filename[:1] + filename[-1:] == '<>':
92 save[filename] = cache[filename]
93 orig_checkcache()
94 cache.update(save)
95
96# Patch linecache.checkcache():
97linecache.checkcache = extended_linecache_checkcache
98
99
100class PyShellEditorWindow(EditorWindow):
101 "Regular text edit window in IDLE, supports breakpoints"
102
103 def __init__(self, *args):
104 self.breakpoints = []
105 EditorWindow.__init__(self, *args)
106 self.text.bind("<<set-breakpoint-here>>", self.set_breakpoint_here)
107 self.text.bind("<<clear-breakpoint-here>>", self.clear_breakpoint_here)
108 self.text.bind("<<open-python-shell>>", self.flist.open_shell)
109
110 self.breakpointPath = os.path.join(idleConf.GetUserCfgDir(),
111 'breakpoints.lst')
112 # whenever a file is changed, restore breakpoints
113 if self.io.filename: self.restore_file_breaks()
114 def filename_changed_hook(old_hook=self.io.filename_change_hook,
115 self=self):
116 self.restore_file_breaks()
117 old_hook()
118 self.io.set_filename_change_hook(filename_changed_hook)
119
120 rmenu_specs = [("Set Breakpoint", "<<set-breakpoint-here>>"),
121 ("Clear Breakpoint", "<<clear-breakpoint-here>>")]
122
123 def set_breakpoint(self, lineno):
124 text = self.text
125 filename = self.io.filename
126 text.tag_add("BREAK", "%d.0" % lineno, "%d.0" % (lineno+1))
127 try:
128 i = self.breakpoints.index(lineno)
129 except ValueError: # only add if missing, i.e. do once
130 self.breakpoints.append(lineno)
131 try: # update the subprocess debugger
132 debug = self.flist.pyshell.interp.debugger
133 debug.set_breakpoint_here(filename, lineno)
134 except: # but debugger may not be active right now....
135 pass
136
137 def set_breakpoint_here(self, event=None):
138 text = self.text
139 filename = self.io.filename
140 if not filename:
141 text.bell()
142 return
143 lineno = int(float(text.index("insert")))
144 self.set_breakpoint(lineno)
145
146 def clear_breakpoint_here(self, event=None):
147 text = self.text
148 filename = self.io.filename
149 if not filename:
150 text.bell()
151 return
152 lineno = int(float(text.index("insert")))
153 try:
154 self.breakpoints.remove(lineno)
155 except:
156 pass
157 text.tag_remove("BREAK", "insert linestart",\
158 "insert lineend +1char")
159 try:
160 debug = self.flist.pyshell.interp.debugger
161 debug.clear_breakpoint_here(filename, lineno)
162 except:
163 pass
164
165 def clear_file_breaks(self):
166 if self.breakpoints:
167 text = self.text
168 filename = self.io.filename
169 if not filename:
170 text.bell()
171 return
172 self.breakpoints = []
173 text.tag_remove("BREAK", "1.0", END)
174 try:
175 debug = self.flist.pyshell.interp.debugger
176 debug.clear_file_breaks(filename)
177 except:
178 pass
179
180 def store_file_breaks(self):
181 "Save breakpoints when file is saved"
182 # XXX 13 Dec 2002 KBK Currently the file must be saved before it can
183 # be run. The breaks are saved at that time. If we introduce
184 # a temporary file save feature the save breaks functionality
185 # needs to be re-verified, since the breaks at the time the
186 # temp file is created may differ from the breaks at the last
187 # permanent save of the file. Currently, a break introduced
188 # after a save will be effective, but not persistent.
189 # This is necessary to keep the saved breaks synched with the
190 # saved file.
191 #
192 # Breakpoints are set as tagged ranges in the text. Certain
193 # kinds of edits cause these ranges to be deleted: Inserting
194 # or deleting a line just before a breakpoint, and certain
195 # deletions prior to a breakpoint. These issues need to be
196 # investigated and understood. It's not clear if they are
197 # Tk issues or IDLE issues, or whether they can actually
198 # be fixed. Since a modified file has to be saved before it is
199 # run, and since self.breakpoints (from which the subprocess
200 # debugger is loaded) is updated during the save, the visible
201 # breaks stay synched with the subprocess even if one of these
202 # unexpected breakpoint deletions occurs.
203 breaks = self.breakpoints
204 filename = self.io.filename
205 try:
206 lines = open(self.breakpointPath,"r").readlines()
207 except IOError:
208 lines = []
209 new_file = open(self.breakpointPath,"w")
210 for line in lines:
211 if not line.startswith(filename + '='):
212 new_file.write(line)
213 self.update_breakpoints()
214 breaks = self.breakpoints
215 if breaks:
216 new_file.write(filename + '=' + str(breaks) + '\n')
217 new_file.close()
218
219 def restore_file_breaks(self):
220 self.text.update() # this enables setting "BREAK" tags to be visible
221 filename = self.io.filename
222 if filename is None:
223 return
224 if os.path.isfile(self.breakpointPath):
225 lines = open(self.breakpointPath,"r").readlines()
226 for line in lines:
227 if line.startswith(filename + '='):
228 breakpoint_linenumbers = eval(line[len(filename)+1:])
229 for breakpoint_linenumber in breakpoint_linenumbers:
230 self.set_breakpoint(breakpoint_linenumber)
231
232 def update_breakpoints(self):
233 "Retrieves all the breakpoints in the current window"
234 text = self.text
235 ranges = text.tag_ranges("BREAK")
236 linenumber_list = self.ranges_to_linenumbers(ranges)
237 self.breakpoints = linenumber_list
238
239 def ranges_to_linenumbers(self, ranges):
240 lines = []
241 for index in range(0, len(ranges), 2):
242 lineno = int(float(ranges[index]))
243 end = int(float(ranges[index+1]))
244 while lineno < end:
245 lines.append(lineno)
246 lineno += 1
247 return lines
248
249# XXX 13 Dec 2002 KBK Not used currently
250# def saved_change_hook(self):
251# "Extend base method - clear breaks if module is modified"
252# if not self.get_saved():
253# self.clear_file_breaks()
254# EditorWindow.saved_change_hook(self)
255
256 def _close(self):
257 "Extend base method - clear breaks when module is closed"
258 self.clear_file_breaks()
259 EditorWindow._close(self)
260
261
262class PyShellFileList(FileList):
263 "Extend base class: IDLE supports a shell and breakpoints"
264
265 # override FileList's class variable, instances return PyShellEditorWindow
266 # instead of EditorWindow when new edit windows are created.
267 EditorWindow = PyShellEditorWindow
268
269 pyshell = None
270
271 def open_shell(self, event=None):
272 if self.pyshell:
273 self.pyshell.top.wakeup()
274 else:
275 self.pyshell = PyShell(self)
276 if self.pyshell:
277 if not self.pyshell.begin():
278 return None
279 return self.pyshell
280
281
282class ModifiedColorDelegator(ColorDelegator):
283 "Extend base class: colorizer for the shell window itself"
284
285 def __init__(self):
286 ColorDelegator.__init__(self)
287 self.LoadTagDefs()
288
289 def recolorize_main(self):
290 self.tag_remove("TODO", "1.0", "iomark")
291 self.tag_add("SYNC", "1.0", "iomark")
292 ColorDelegator.recolorize_main(self)
293
294 def LoadTagDefs(self):
295 ColorDelegator.LoadTagDefs(self)
296 theme = idleConf.GetOption('main','Theme','name')
297 self.tagdefs.update({
298 "stdin": {'background':None,'foreground':None},
299 "stdout": idleConf.GetHighlight(theme, "stdout"),
300 "stderr": idleConf.GetHighlight(theme, "stderr"),
301 "console": idleConf.GetHighlight(theme, "console"),
302 None: idleConf.GetHighlight(theme, "normal"),
303 })
304
305class ModifiedUndoDelegator(UndoDelegator):
306 "Extend base class: forbid insert/delete before the I/O mark"
307
308 def insert(self, index, chars, tags=None):
309 try:
310 if self.delegate.compare(index, "<", "iomark"):
311 self.delegate.bell()
312 return
313 except TclError:
314 pass
315 UndoDelegator.insert(self, index, chars, tags)
316
317 def delete(self, index1, index2=None):
318 try:
319 if self.delegate.compare(index1, "<", "iomark"):
320 self.delegate.bell()
321 return
322 except TclError:
323 pass
324 UndoDelegator.delete(self, index1, index2)
325
326
327class MyRPCClient(rpc.RPCClient):
328
329 def handle_EOF(self):
330 "Override the base class - just re-raise EOFError"
331 raise EOFError
332
333
334class ModifiedInterpreter(InteractiveInterpreter):
335
336 def __init__(self, tkconsole):
337 self.tkconsole = tkconsole
338 locals = sys.modules['__main__'].__dict__
339 InteractiveInterpreter.__init__(self, locals=locals)
340 self.save_warnings_filters = None
341 self.restarting = False
342 self.subprocess_arglist = self.build_subprocess_arglist()
343
344 port = 8833
345 rpcclt = None
346 rpcpid = None
347
348 def spawn_subprocess(self):
349 args = self.subprocess_arglist
350 self.rpcpid = os.spawnv(os.P_NOWAIT, sys.executable, args)
351
352 def build_subprocess_arglist(self):
353 w = ['-W' + s for s in sys.warnoptions]
354 # Maybe IDLE is installed and is being accessed via sys.path,
355 # or maybe it's not installed and the idle.py script is being
356 # run from the IDLE source directory.
357 del_exitf = idleConf.GetOption('main', 'General', 'delete-exitfunc',
358 default=False, type='bool')
359 if __name__ == 'idlelib.PyShell':
360 command = "__import__('idlelib.run').run.main(%r)" % (del_exitf,)
361 else:
362 command = "__import__('run').main(%r)" % (del_exitf,)
363 if sys.platform[:3] == 'win' and ' ' in sys.executable:
364 # handle embedded space in path by quoting the argument
365 decorated_exec = '"%s"' % sys.executable
366 else:
367 decorated_exec = sys.executable
368 return [decorated_exec] + w + ["-c", command, str(self.port)]
369
370 def start_subprocess(self):
371 # spawning first avoids passing a listening socket to the subprocess
372 self.spawn_subprocess()
373 #time.sleep(20) # test to simulate GUI not accepting connection
374 addr = (LOCALHOST, self.port)
375 # Idle starts listening for connection on localhost
376 for i in range(3):
377 time.sleep(i)
378 try:
379 self.rpcclt = MyRPCClient(addr)
380 break
381 except socket.error, err:
382 pass
383 else:
384 self.display_port_binding_error()
385 return None
386 # Accept the connection from the Python execution server
387 self.rpcclt.listening_sock.settimeout(10)
388 try:
389 self.rpcclt.accept()
390 except socket.timeout, err:
391 self.display_no_subprocess_error()
392 return None
393 self.rpcclt.register("stdin", self.tkconsole)
394 self.rpcclt.register("stdout", self.tkconsole.stdout)
395 self.rpcclt.register("stderr", self.tkconsole.stderr)
396 self.rpcclt.register("flist", self.tkconsole.flist)
397 self.rpcclt.register("linecache", linecache)
398 self.rpcclt.register("interp", self)
399 self.transfer_path()
400 self.poll_subprocess()
401 return self.rpcclt
402
403 def restart_subprocess(self):
404 if self.restarting:
405 return self.rpcclt
406 self.restarting = True
407 # close only the subprocess debugger
408 debug = self.getdebugger()
409 if debug:
410 try:
411 # Only close subprocess debugger, don't unregister gui_adap!
412 RemoteDebugger.close_subprocess_debugger(self.rpcclt)
413 except:
414 pass
415 # Kill subprocess, spawn a new one, accept connection.
416 self.rpcclt.close()
417 self.unix_terminate()
418 console = self.tkconsole
419 was_executing = console.executing
420 console.executing = False
421 self.spawn_subprocess()
422 try:
423 self.rpcclt.accept()
424 except socket.timeout, err:
425 self.display_no_subprocess_error()
426 return None
427 self.transfer_path()
428 # annotate restart in shell window and mark it
429 console.text.delete("iomark", "end-1c")
430 if was_executing:
431 console.write('\n')
432 console.showprompt()
433 halfbar = ((int(console.width) - 16) // 2) * '='
434 console.write(halfbar + ' RESTART ' + halfbar)
435 console.text.mark_set("restart", "end-1c")
436 console.text.mark_gravity("restart", "left")
437 console.showprompt()
438 # restart subprocess debugger
439 if debug:
440 # Restarted debugger connects to current instance of debug GUI
441 gui = RemoteDebugger.restart_subprocess_debugger(self.rpcclt)
442 # reload remote debugger breakpoints for all PyShellEditWindows
443 debug.load_breakpoints()
444 self.restarting = False
445 return self.rpcclt
446
447 def __request_interrupt(self):
448 self.rpcclt.remotecall("exec", "interrupt_the_server", (), {})
449
450 def interrupt_subprocess(self):
451 threading.Thread(target=self.__request_interrupt).start()
452
453 def kill_subprocess(self):
454 try:
455 self.rpcclt.close()
456 except AttributeError: # no socket
457 pass
458 self.unix_terminate()
459 self.tkconsole.executing = False
460 self.rpcclt = None
461
462 def unix_terminate(self):
463 "UNIX: make sure subprocess is terminated and collect status"
464 if hasattr(os, 'kill'):
465 try:
466 os.kill(self.rpcpid, SIGTERM)
467 except OSError:
468 # process already terminated:
469 return
470 else:
471 try:
472 os.waitpid(self.rpcpid, 0)
473 except OSError:
474 return
475
476 def transfer_path(self):
477 self.runcommand("""if 1:
478 import sys as _sys
479 _sys.path = %r
480 del _sys
481 _msg = 'Use File/Exit or your end-of-file key to quit IDLE'
482 __builtins__.quit = __builtins__.exit = _msg
483 del _msg
484 \n""" % (sys.path,))
485
486 active_seq = None
487
488 def poll_subprocess(self):
489 clt = self.rpcclt
490 if clt is None:
491 return
492 try:
493 response = clt.pollresponse(self.active_seq, wait=0.05)
494 except (EOFError, IOError, KeyboardInterrupt):
495 # lost connection or subprocess terminated itself, restart
496 # [the KBI is from rpc.SocketIO.handle_EOF()]
497 if self.tkconsole.closing:
498 return
499 response = None
500 self.restart_subprocess()
501 if response:
502 self.tkconsole.resetoutput()
503 self.active_seq = None
504 how, what = response
505 console = self.tkconsole.console
506 if how == "OK":
507 if what is not None:
508 print >>console, repr(what)
509 elif how == "EXCEPTION":
510 if self.tkconsole.getvar("<<toggle-jit-stack-viewer>>"):
511 self.remote_stack_viewer()
512 elif how == "ERROR":
513 errmsg = "PyShell.ModifiedInterpreter: Subprocess ERROR:\n"
514 print >>sys.__stderr__, errmsg, what
515 print >>console, errmsg, what
516 # we received a response to the currently active seq number:
517 self.tkconsole.endexecuting()
518 # Reschedule myself
519 if not self.tkconsole.closing:
520 self.tkconsole.text.after(self.tkconsole.pollinterval,
521 self.poll_subprocess)
522
523 debugger = None
524
525 def setdebugger(self, debugger):
526 self.debugger = debugger
527
528 def getdebugger(self):
529 return self.debugger
530
531 def open_remote_stack_viewer(self):
532 """Initiate the remote stack viewer from a separate thread.
533
534 This method is called from the subprocess, and by returning from this
535 method we allow the subprocess to unblock. After a bit the shell
536 requests the subprocess to open the remote stack viewer which returns a
537 static object looking at the last exceptiopn. It is queried through
538 the RPC mechanism.
539
540 """
541 self.tkconsole.text.after(300, self.remote_stack_viewer)
542 return
543
544 def remote_stack_viewer(self):
545 import RemoteObjectBrowser
546 oid = self.rpcclt.remotequeue("exec", "stackviewer", ("flist",), {})
547 if oid is None:
548 self.tkconsole.root.bell()
549 return
550 item = RemoteObjectBrowser.StubObjectTreeItem(self.rpcclt, oid)
551 from TreeWidget import ScrolledCanvas, TreeNode
552 top = Toplevel(self.tkconsole.root)
553 theme = idleConf.GetOption('main','Theme','name')
554 background = idleConf.GetHighlight(theme, 'normal')['background']
555 sc = ScrolledCanvas(top, bg=background, highlightthickness=0)
556 sc.frame.pack(expand=1, fill="both")
557 node = TreeNode(sc.canvas, None, item)
558 node.expand()
559 # XXX Should GC the remote tree when closing the window
560
561 gid = 0
562
563 def execsource(self, source):
564 "Like runsource() but assumes complete exec source"
565 filename = self.stuffsource(source)
566 self.execfile(filename, source)
567
568 def execfile(self, filename, source=None):
569 "Execute an existing file"
570 if source is None:
571 source = open(filename, "r").read()
572 try:
573 code = compile(source, filename, "exec")
574 except (OverflowError, SyntaxError):
575 self.tkconsole.resetoutput()
576 tkerr = self.tkconsole.stderr
577 print>>tkerr, '*** Error in script or command!\n'
578 print>>tkerr, 'Traceback (most recent call last):'
579 InteractiveInterpreter.showsyntaxerror(self, filename)
580 self.tkconsole.showprompt()
581 else:
582 self.runcode(code)
583
584 def runsource(self, source):
585 "Extend base class method: Stuff the source in the line cache first"
586 filename = self.stuffsource(source)
587 self.more = 0
588 self.save_warnings_filters = warnings.filters[:]
589 warnings.filterwarnings(action="error", category=SyntaxWarning)
590 if isinstance(source, types.UnicodeType):
591 import IOBinding
592 try:
593 source = source.encode(IOBinding.encoding)
594 except UnicodeError:
595 self.tkconsole.resetoutput()
596 self.write("Unsupported characters in input")
597 return
598 try:
599 return InteractiveInterpreter.runsource(self, source, filename)
600 finally:
601 if self.save_warnings_filters is not None:
602 warnings.filters[:] = self.save_warnings_filters
603 self.save_warnings_filters = None
604
605 def stuffsource(self, source):
606 "Stuff source in the filename cache"
607 filename = "<pyshell#%d>" % self.gid
608 self.gid = self.gid + 1
609 lines = source.split("\n")
610 linecache.cache[filename] = len(source)+1, 0, lines, filename
611 return filename
612
613 def prepend_syspath(self, filename):
614 "Prepend sys.path with file's directory if not already included"
615 self.runcommand("""if 1:
616 _filename = %r
617 import sys as _sys
618 from os.path import dirname as _dirname
619 _dir = _dirname(_filename)
620 if not _dir in _sys.path:
621 _sys.path.insert(0, _dir)
622 del _filename, _sys, _dirname, _dir
623 \n""" % (filename,))
624
625 def showsyntaxerror(self, filename=None):
626 """Extend base class method: Add Colorizing
627
628 Color the offending position instead of printing it and pointing at it
629 with a caret.
630
631 """
632 text = self.tkconsole.text
633 stuff = self.unpackerror()
634 if stuff:
635 msg, lineno, offset, line = stuff
636 if lineno == 1:
637 pos = "iomark + %d chars" % (offset-1)
638 else:
639 pos = "iomark linestart + %d lines + %d chars" % \
640 (lineno-1, offset-1)
641 text.tag_add("ERROR", pos)
642 text.see(pos)
643 char = text.get(pos)
644 if char and char in IDENTCHARS:
645 text.tag_add("ERROR", pos + " wordstart", pos)
646 self.tkconsole.resetoutput()
647 self.write("SyntaxError: %s\n" % str(msg))
648 else:
649 self.tkconsole.resetoutput()
650 InteractiveInterpreter.showsyntaxerror(self, filename)
651 self.tkconsole.showprompt()
652
653 def unpackerror(self):
654 type, value, tb = sys.exc_info()
655 ok = type is SyntaxError
656 if ok:
657 try:
658 msg, (dummy_filename, lineno, offset, line) = value
659 if not offset:
660 offset = 0
661 except:
662 ok = 0
663 if ok:
664 return msg, lineno, offset, line
665 else:
666 return None
667
668 def showtraceback(self):
669 "Extend base class method to reset output properly"
670 self.tkconsole.resetoutput()
671 self.checklinecache()
672 InteractiveInterpreter.showtraceback(self)
673 if self.tkconsole.getvar("<<toggle-jit-stack-viewer>>"):
674 self.tkconsole.open_stack_viewer()
675
676 def checklinecache(self):
677 c = linecache.cache
678 for key in c.keys():
679 if key[:1] + key[-1:] != "<>":
680 del c[key]
681
682 def runcommand(self, code):
683 "Run the code without invoking the debugger"
684 # The code better not raise an exception!
685 if self.tkconsole.executing:
686 self.display_executing_dialog()
687 return 0
688 if self.rpcclt:
689 self.rpcclt.remotequeue("exec", "runcode", (code,), {})
690 else:
691 exec code in self.locals
692 return 1
693
694 def runcode(self, code):
695 "Override base class method"
696 if self.tkconsole.executing:
697 self.interp.restart_subprocess()
698 self.checklinecache()
699 if self.save_warnings_filters is not None:
700 warnings.filters[:] = self.save_warnings_filters
701 self.save_warnings_filters = None
702 debugger = self.debugger
703 try:
704 self.tkconsole.beginexecuting()
705 try:
706 if not debugger and self.rpcclt is not None:
707 self.active_seq = self.rpcclt.asyncqueue("exec", "runcode",
708 (code,), {})
709 elif debugger:
710 debugger.run(code, self.locals)
711 else:
712 exec code in self.locals
713 except SystemExit:
714 if tkMessageBox.askyesno(
715 "Exit?",
716 "Do you want to exit altogether?",
717 default="yes",
718 master=self.tkconsole.text):
719 raise
720 else:
721 self.showtraceback()
722 except:
723 self.showtraceback()
724 finally:
725 if not use_subprocess:
726 self.tkconsole.endexecuting()
727
728 def write(self, s):
729 "Override base class method"
730 self.tkconsole.stderr.write(s)
731
732 def display_port_binding_error(self):
733 tkMessageBox.showerror(
734 "Port Binding Error",
735 "IDLE can't bind TCP/IP port 8833, which is necessary to "
736 "communicate with its Python execution server. Either "
737 "no networking is installed on this computer or another "
738 "process (another IDLE?) is using the port. Run IDLE with the -n "
739 "command line switch to start without a subprocess and refer to "
740 "Help/IDLE Help 'Running without a subprocess' for further "
741 "details.",
742 master=self.tkconsole.text)
743
744 def display_no_subprocess_error(self):
745 tkMessageBox.showerror(
746 "Subprocess Startup Error",
747 "IDLE's subprocess didn't make connection. Either IDLE can't "
748 "start a subprocess or personal firewall software is blocking "
749 "the connection.",
750 master=self.tkconsole.text)
751
752 def display_executing_dialog(self):
753 tkMessageBox.showerror(
754 "Already executing",
755 "The Python Shell window is already executing a command; "
756 "please wait until it is finished.",
757 master=self.tkconsole.text)
758
759
760class PyShell(OutputWindow):
761
762 shell_title = "Python Shell"
763
764 # Override classes
765 ColorDelegator = ModifiedColorDelegator
766 UndoDelegator = ModifiedUndoDelegator
767
768 # Override menus
769 menu_specs = [
770 ("file", "_File"),
771 ("edit", "_Edit"),
772 ("debug", "_Debug"),
773 ("options", "_Options"),
774 ("windows", "_Windows"),
775 ("help", "_Help"),
776 ]
777
778 # New classes
779 from IdleHistory import History
780
781 def __init__(self, flist=None):
782 if use_subprocess:
783 ms = self.menu_specs
784 if ms[2][0] != "shell":
785 ms.insert(2, ("shell", "_Shell"))
786 self.interp = ModifiedInterpreter(self)
787 if flist is None:
788 root = Tk()
789 fixwordbreaks(root)
790 root.withdraw()
791 flist = PyShellFileList(root)
792 #
793 OutputWindow.__init__(self, flist, None, None)
794 #
795 import __builtin__
796 __builtin__.quit = __builtin__.exit = "To exit, type Ctrl-D."
797 #
798 self.config(usetabs=1, indentwidth=8, context_use_ps1=1)
799 #
800 text = self.text
801 text.configure(wrap="char")
802 text.bind("<<newline-and-indent>>", self.enter_callback)
803 text.bind("<<plain-newline-and-indent>>", self.linefeed_callback)
804 text.bind("<<interrupt-execution>>", self.cancel_callback)
805 text.bind("<<beginning-of-line>>", self.home_callback)
806 text.bind("<<end-of-file>>", self.eof_callback)
807 text.bind("<<open-stack-viewer>>", self.open_stack_viewer)
808 text.bind("<<toggle-debugger>>", self.toggle_debugger)
809 text.bind("<<toggle-jit-stack-viewer>>", self.toggle_jit_stack_viewer)
810 if use_subprocess:
811 text.bind("<<view-restart>>", self.view_restart_mark)
812 text.bind("<<restart-shell>>", self.restart_shell)
813 #
814 self.save_stdout = sys.stdout
815 self.save_stderr = sys.stderr
816 self.save_stdin = sys.stdin
817 import IOBinding
818 self.stdout = PseudoFile(self, "stdout", IOBinding.encoding)
819 self.stderr = PseudoFile(self, "stderr", IOBinding.encoding)
820 self.console = PseudoFile(self, "console", IOBinding.encoding)
821 if not use_subprocess:
822 sys.stdout = self.stdout
823 sys.stderr = self.stderr
824 sys.stdin = self
825 #
826 self.history = self.History(self.text)
827 #
828 self.pollinterval = 50 # millisec
829
830 def get_standard_extension_names(self):
831 return idleConf.GetExtensions(shell_only=True)
832
833 reading = False
834 executing = False
835 canceled = False
836 endoffile = False
837 closing = False
838
839 def set_warning_stream(self, stream):
840 global warning_stream
841 warning_stream = stream
842
843 def get_warning_stream(self):
844 return warning_stream
845
846 def toggle_debugger(self, event=None):
847 if self.executing:
848 tkMessageBox.showerror("Don't debug now",
849 "You can only toggle the debugger when idle",
850 master=self.text)
851 self.set_debugger_indicator()
852 return "break"
853 else:
854 db = self.interp.getdebugger()
855 if db:
856 self.close_debugger()
857 else:
858 self.open_debugger()
859
860 def set_debugger_indicator(self):
861 db = self.interp.getdebugger()
862 self.setvar("<<toggle-debugger>>", not not db)
863
864 def toggle_jit_stack_viewer(self, event=None):
865 pass # All we need is the variable
866
867 def close_debugger(self):
868 db = self.interp.getdebugger()
869 if db:
870 self.interp.setdebugger(None)
871 db.close()
872 if self.interp.rpcclt:
873 RemoteDebugger.close_remote_debugger(self.interp.rpcclt)
874 self.resetoutput()
875 self.console.write("[DEBUG OFF]\n")
876 sys.ps1 = ">>> "
877 self.showprompt()
878 self.set_debugger_indicator()
879
880 def open_debugger(self):
881 if self.interp.rpcclt:
882 dbg_gui = RemoteDebugger.start_remote_debugger(self.interp.rpcclt,
883 self)
884 else:
885 dbg_gui = Debugger.Debugger(self)
886 self.interp.setdebugger(dbg_gui)
887 dbg_gui.load_breakpoints()
888 sys.ps1 = "[DEBUG ON]\n>>> "
889 self.showprompt()
890 self.set_debugger_indicator()
891
892 def beginexecuting(self):
893 "Helper for ModifiedInterpreter"
894 self.resetoutput()
895 self.executing = 1
896
897 def endexecuting(self):
898 "Helper for ModifiedInterpreter"
899 self.executing = 0
900 self.canceled = 0
901 self.showprompt()
902
903 def close(self):
904 "Extend EditorWindow.close()"
905 if self.executing:
906 response = tkMessageBox.askokcancel(
907 "Kill?",
908 "The program is still running!\n Do you want to kill it?",
909 default="ok",
910 parent=self.text)
911 if response == False:
912 return "cancel"
913 if self.reading:
914 self.top.quit()
915 self.canceled = True
916 self.closing = True
917 # Wait for poll_subprocess() rescheduling to stop
918 self.text.after(2 * self.pollinterval, self.close2)
919
920 def close2(self):
921 return EditorWindow.close(self)
922
923 def _close(self):
924 "Extend EditorWindow._close(), shut down debugger and execution server"
925 self.close_debugger()
926 if use_subprocess:
927 self.interp.kill_subprocess()
928 # Restore std streams
929 sys.stdout = self.save_stdout
930 sys.stderr = self.save_stderr
931 sys.stdin = self.save_stdin
932 # Break cycles
933 self.interp = None
934 self.console = None
935 self.flist.pyshell = None
936 self.history = None
937 EditorWindow._close(self)
938
939 def ispythonsource(self, filename):
940 "Override EditorWindow method: never remove the colorizer"
941 return True
942
943 def short_title(self):
944 return self.shell_title
945
946 COPYRIGHT = \
947 'Type "copyright", "credits" or "license()" for more information.'
948
949 firewallmessage = """
950 ****************************************************************
951 Personal firewall software may warn about the connection IDLE
952 makes to its subprocess using this computer's internal loopback
953 interface. This connection is not visible on any external
954 interface and no data is sent to or received from the Internet.
955 ****************************************************************
956 """
957
958 def begin(self):
959 self.resetoutput()
960 if use_subprocess:
961 nosub = ''
962 client = self.interp.start_subprocess()
963 if not client:
964 self.close()
965 return False
966 else:
967 nosub = "==== No Subprocess ===="
968 self.write("Python %s on %s\n%s\n%s\nIDLE %s %s\n" %
969 (sys.version, sys.platform, self.COPYRIGHT,
970 self.firewallmessage, idlever.IDLE_VERSION, nosub))
971 self.showprompt()
972 import Tkinter
973 Tkinter._default_root = None # 03Jan04 KBK What's this?
974 return True
975
976 def readline(self):
977 save = self.reading
978 try:
979 self.reading = 1
980 self.top.mainloop() # nested mainloop()
981 finally:
982 self.reading = save
983 line = self.text.get("iomark", "end-1c")
984 if len(line) == 0: # may be EOF if we quit our mainloop with Ctrl-C
985 line = "\n"
986 if isinstance(line, unicode):
987 import IOBinding
988 try:
989 line = line.encode(IOBinding.encoding)
990 except UnicodeError:
991 pass
992 self.resetoutput()
993 if self.canceled:
994 self.canceled = 0
995 if not use_subprocess:
996 raise KeyboardInterrupt
997 if self.endoffile:
998 self.endoffile = 0
999 line = ""
1000 return line
1001
1002 def isatty(self):
1003 return True
1004
1005 def cancel_callback(self, event=None):
1006 try:
1007 if self.text.compare("sel.first", "!=", "sel.last"):
1008 return # Active selection -- always use default binding
1009 except:
1010 pass
1011 if not (self.executing or self.reading):
1012 self.resetoutput()
1013 self.interp.write("KeyboardInterrupt\n")
1014 self.showprompt()
1015 return "break"
1016 self.endoffile = 0
1017 self.canceled = 1
1018 if (self.executing and self.interp.rpcclt):
1019 if self.interp.getdebugger():
1020 self.interp.restart_subprocess()
1021 else:
1022 self.interp.interrupt_subprocess()
1023 if self.reading:
1024 self.top.quit() # exit the nested mainloop() in readline()
1025 return "break"
1026
1027 def eof_callback(self, event):
1028 if self.executing and not self.reading:
1029 return # Let the default binding (delete next char) take over
1030 if not (self.text.compare("iomark", "==", "insert") and
1031 self.text.compare("insert", "==", "end-1c")):
1032 return # Let the default binding (delete next char) take over
1033 if not self.executing:
1034 self.resetoutput()
1035 self.close()
1036 else:
1037 self.canceled = 0
1038 self.endoffile = 1
1039 self.top.quit()
1040 return "break"
1041
1042 def home_callback(self, event):
1043 if event.state != 0 and event.keysym == "Home":
1044 return # <Modifier-Home>; fall back to class binding
1045 if self.text.compare("iomark", "<=", "insert") and \
1046 self.text.compare("insert linestart", "<=", "iomark"):
1047 self.text.mark_set("insert", "iomark")
1048 self.text.tag_remove("sel", "1.0", "end")
1049 self.text.see("insert")
1050 return "break"
1051
1052 def linefeed_callback(self, event):
1053 # Insert a linefeed without entering anything (still autoindented)
1054 if self.reading:
1055 self.text.insert("insert", "\n")
1056 self.text.see("insert")
1057 else:
1058 self.newline_and_indent_event(event)
1059 return "break"
1060
1061 def enter_callback(self, event):
1062 if self.executing and not self.reading:
1063 return # Let the default binding (insert '\n') take over
1064 # If some text is selected, recall the selection
1065 # (but only if this before the I/O mark)
1066 try:
1067 sel = self.text.get("sel.first", "sel.last")
1068 if sel:
1069 if self.text.compare("sel.last", "<=", "iomark"):
1070 self.recall(sel)
1071 return "break"
1072 except:
1073 pass
1074 # If we're strictly before the line containing iomark, recall
1075 # the current line, less a leading prompt, less leading or
1076 # trailing whitespace
1077 if self.text.compare("insert", "<", "iomark linestart"):
1078 # Check if there's a relevant stdin range -- if so, use it
1079 prev = self.text.tag_prevrange("stdin", "insert")
1080 if prev and self.text.compare("insert", "<", prev[1]):
1081 self.recall(self.text.get(prev[0], prev[1]))
1082 return "break"
1083 next = self.text.tag_nextrange("stdin", "insert")
1084 if next and self.text.compare("insert lineend", ">=", next[0]):
1085 self.recall(self.text.get(next[0], next[1]))
1086 return "break"
1087 # No stdin mark -- just get the current line, less any prompt
1088 line = self.text.get("insert linestart", "insert lineend")
1089 last_line_of_prompt = sys.ps1.split('\n')[-1]
1090 if line.startswith(last_line_of_prompt):
1091 line = line[len(last_line_of_prompt):]
1092 self.recall(line)
1093 return "break"
1094 # If we're between the beginning of the line and the iomark, i.e.
1095 # in the prompt area, move to the end of the prompt
1096 if self.text.compare("insert", "<", "iomark"):
1097 self.text.mark_set("insert", "iomark")
1098 # If we're in the current input and there's only whitespace
1099 # beyond the cursor, erase that whitespace first
1100 s = self.text.get("insert", "end-1c")
1101 if s and not s.strip():
1102 self.text.delete("insert", "end-1c")
1103 # If we're in the current input before its last line,
1104 # insert a newline right at the insert point
1105 if self.text.compare("insert", "<", "end-1c linestart"):
1106 self.newline_and_indent_event(event)
1107 return "break"
1108 # We're in the last line; append a newline and submit it
1109 self.text.mark_set("insert", "end-1c")
1110 if self.reading:
1111 self.text.insert("insert", "\n")
1112 self.text.see("insert")
1113 else:
1114 self.newline_and_indent_event(event)
1115 self.text.tag_add("stdin", "iomark", "end-1c")
1116 self.text.update_idletasks()
1117 if self.reading:
1118 self.top.quit() # Break out of recursive mainloop() in raw_input()
1119 else:
1120 self.runit()
1121 return "break"
1122
1123 def recall(self, s):
1124 if self.history:
1125 self.history.recall(s)
1126
1127 def runit(self):
1128 line = self.text.get("iomark", "end-1c")
1129 # Strip off last newline and surrounding whitespace.
1130 # (To allow you to hit return twice to end a statement.)
1131 i = len(line)
1132 while i > 0 and line[i-1] in " \t":
1133 i = i-1
1134 if i > 0 and line[i-1] == "\n":
1135 i = i-1
1136 while i > 0 and line[i-1] in " \t":
1137 i = i-1
1138 line = line[:i]
1139 more = self.interp.runsource(line)
1140
1141 def open_stack_viewer(self, event=None):
1142 if self.interp.rpcclt:
1143 return self.interp.remote_stack_viewer()
1144 try:
1145 sys.last_traceback
1146 except:
1147 tkMessageBox.showerror("No stack trace",
1148 "There is no stack trace yet.\n"
1149 "(sys.last_traceback is not defined)",
1150 master=self.text)
1151 return
1152 from StackViewer import StackBrowser
1153 sv = StackBrowser(self.root, self.flist)
1154
1155 def view_restart_mark(self, event=None):
1156 self.text.see("iomark")
1157 self.text.see("restart")
1158
1159 def restart_shell(self, event=None):
1160 self.interp.restart_subprocess()
1161
1162 def showprompt(self):
1163 self.resetoutput()
1164 try:
1165 s = str(sys.ps1)
1166 except:
1167 s = ""
1168 self.console.write(s)
1169 self.text.mark_set("insert", "end-1c")
1170 self.set_line_and_column()
1171 self.io.reset_undo()
1172
1173 def resetoutput(self):
1174 source = self.text.get("iomark", "end-1c")
1175 if self.history:
1176 self.history.history_store(source)
1177 if self.text.get("end-2c") != "\n":
1178 self.text.insert("end-1c", "\n")
1179 self.text.mark_set("iomark", "end-1c")
1180 self.set_line_and_column()
1181 sys.stdout.softspace = 0
1182
1183 def write(self, s, tags=()):
1184 try:
1185 self.text.mark_gravity("iomark", "right")
1186 OutputWindow.write(self, s, tags, "iomark")
1187 self.text.mark_gravity("iomark", "left")
1188 except:
1189 pass
1190 if self.canceled:
1191 self.canceled = 0
1192 if not use_subprocess:
1193 raise KeyboardInterrupt
1194
1195class PseudoFile:
1196
1197 def __init__(self, shell, tags, encoding=None):
1198 self.shell = shell
1199 self.tags = tags
1200 self.softspace = 0
1201 self.encoding = encoding
1202
1203 def write(self, s):
1204 self.shell.write(s, self.tags)
1205
1206 def writelines(self, l):
1207 map(self.write, l)
1208
1209 def flush(self):
1210 pass
1211
1212 def isatty(self):
1213 return True
1214
1215
1216usage_msg = """\
1217
1218USAGE: idle [-deins] [-t title] [file]*
1219 idle [-dns] [-t title] (-c cmd | -r file) [arg]*
1220 idle [-dns] [-t title] - [arg]*
1221
1222 -h print this help message and exit
1223 -n run IDLE without a subprocess (see Help/IDLE Help for details)
1224
1225The following options will override the IDLE 'settings' configuration:
1226
1227 -e open an edit window
1228 -i open a shell window
1229
1230The following options imply -i and will open a shell:
1231
1232 -c cmd run the command in a shell, or
1233 -r file run script from file
1234
1235 -d enable the debugger
1236 -s run $IDLESTARTUP or $PYTHONSTARTUP before anything else
1237 -t title set title of shell window
1238
1239A default edit window will be bypassed when -c, -r, or - are used.
1240
1241[arg]* are passed to the command (-c) or script (-r) in sys.argv[1:].
1242
1243Examples:
1244
1245idle
1246 Open an edit window or shell depending on IDLE's configuration.
1247
1248idle foo.py foobar.py
1249 Edit the files, also open a shell if configured to start with shell.
1250
1251idle -est "Baz" foo.py
1252 Run $IDLESTARTUP or $PYTHONSTARTUP, edit foo.py, and open a shell
1253 window with the title "Baz".
1254
1255idle -c "import sys; print sys.argv" "foo"
1256 Open a shell window and run the command, passing "-c" in sys.argv[0]
1257 and "foo" in sys.argv[1].
1258
1259idle -d -s -r foo.py "Hello World"
1260 Open a shell window, run a startup script, enable the debugger, and
1261 run foo.py, passing "foo.py" in sys.argv[0] and "Hello World" in
1262 sys.argv[1].
1263
1264echo "import sys; print sys.argv" | idle - "foobar"
1265 Open a shell window, run the script piped in, passing '' in sys.argv[0]
1266 and "foobar" in sys.argv[1].
1267"""
1268
1269def main():
1270 global flist, root, use_subprocess
1271
1272 use_subprocess = True
1273 enable_shell = False
1274 enable_edit = False
1275 debug = False
1276 cmd = None
1277 script = None
1278 startup = False
1279 try:
1280 sys.ps1
1281 except AttributeError:
1282 sys.ps1 = '>>> '
1283 try:
1284 opts, args = getopt.getopt(sys.argv[1:], "c:deihnr:st:")
1285 except getopt.error, msg:
1286 sys.stderr.write("Error: %s\n" % str(msg))
1287 sys.stderr.write(usage_msg)
1288 sys.exit(2)
1289 for o, a in opts:
1290 if o == '-c':
1291 cmd = a
1292 enable_shell = True
1293 if o == '-d':
1294 debug = True
1295 enable_shell = True
1296 if o == '-e':
1297 enable_edit = True
1298 if o == '-h':
1299 sys.stdout.write(usage_msg)
1300 sys.exit()
1301 if o == '-i':
1302 enable_shell = True
1303 if o == '-n':
1304 use_subprocess = False
1305 if o == '-r':
1306 script = a
1307 if os.path.isfile(script):
1308 pass
1309 else:
1310 print "No script file: ", script
1311 sys.exit()
1312 enable_shell = True
1313 if o == '-s':
1314 startup = True
1315 enable_shell = True
1316 if o == '-t':
1317 PyShell.shell_title = a
1318 enable_shell = True
1319 if args and args[0] == '-':
1320 cmd = sys.stdin.read()
1321 enable_shell = True
1322 # process sys.argv and sys.path:
1323 for i in range(len(sys.path)):
1324 sys.path[i] = os.path.abspath(sys.path[i])
1325 if args and args[0] == '-':
1326 sys.argv = [''] + args[1:]
1327 elif cmd:
1328 sys.argv = ['-c'] + args
1329 elif script:
1330 sys.argv = [script] + args
1331 elif args:
1332 enable_edit = True
1333 pathx = []
1334 for filename in args:
1335 pathx.append(os.path.dirname(filename))
1336 for dir in pathx:
1337 dir = os.path.abspath(dir)
1338 if not dir in sys.path:
1339 sys.path.insert(0, dir)
1340 else:
1341 dir = os.getcwd()
1342 if not dir in sys.path:
1343 sys.path.insert(0, dir)
1344 # check the IDLE settings configuration (but command line overrides)
1345 edit_start = idleConf.GetOption('main', 'General',
1346 'editor-on-startup', type='bool')
1347 enable_edit = enable_edit or edit_start
1348 enable_shell = enable_shell or not edit_start
1349 # start editor and/or shell windows:
1350 root = Tk(className="Idle")
1351 fixwordbreaks(root)
1352 root.withdraw()
1353 flist = PyShellFileList(root)
1354 if enable_edit:
1355 if not (cmd or script):
1356 for filename in args:
1357 flist.open(filename)
1358 if not args:
1359 flist.new()
1360 if enable_shell:
1361 if not flist.open_shell():
1362 return # couldn't open shell
1363 shell = flist.pyshell
1364 # handle remaining options:
1365 if debug:
1366 shell.open_debugger()
1367 if startup:
1368 filename = os.environ.get("IDLESTARTUP") or \
1369 os.environ.get("PYTHONSTARTUP")
1370 if filename and os.path.isfile(filename):
1371 shell.interp.execfile(filename)
1372 if shell and cmd or script:
1373 shell.interp.runcommand("""if 1:
1374 import sys as _sys
1375 _sys.argv = %r
1376 del _sys
1377 \n""" % (sys.argv,))
1378 if cmd:
1379 shell.interp.execsource(cmd)
1380 elif script:
1381 shell.interp.prepend_syspath(script)
1382 shell.interp.execfile(script)
1383 root.mainloop()
1384 root.destroy()
1385
1386if __name__ == "__main__":
1387 sys.modules['PyShell'] = sys.modules['__main__']
1388 main()