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