home *** CD-ROM | disk | FTP | other *** search
/ PC World 2005 June / PCWorld_2005-06_cd.bin / software / vyzkuste / firewally / firewally.exe / framework-2.3.exe / PyShell.py < prev    next >
Text File  |  2003-12-30  |  46KB  |  1,328 lines

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