17 from code
import InteractiveInterpreter
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
34 IDENTCHARS
= string
.ascii_letters
+ string
.digits
+ "_"
35 LOCALHOST
= '127.0.0.1'
38 from signal
import SIGTERM
42 # Change warnings module to write to sys.__stderr__
48 def idle_showwarning(message
, category
, filename
, lineno
):
50 file.write(warnings
.formatwarning(message
, category
, filename
, lineno
))
51 warnings
.showwarning
= idle_showwarning
53 def extended_linecache_checkcache(orig_checkcache
=linecache
.checkcache
):
54 """Extend linecache.checkcache to preserve the <pyshell#...> entries
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.
63 cache
= linecache
.cache
65 for filename
in cache
.keys():
66 if filename
[:1] + filename
[-1:] == '<>':
67 save
[filename
] = cache
[filename
]
71 # Patch linecache.checkcache():
72 linecache
.checkcache
= extended_linecache_checkcache
75 class PyShellEditorWindow(EditorWindow
):
76 "Regular text edit window when a shell is present"
78 def __init__(self
, *args
):
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
)
85 self
.breakpointPath
= os
.path
.join(idleConf
.GetUserCfgDir(),
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
,
91 self
.restore_file_breaks()
93 self
.io
.set_filename_change_hook(filename_changed_hook
)
95 rmenu_specs
= [("Set Breakpoint", "<<set-breakpoint-here>>"),
96 ("Clear Breakpoint", "<<clear-breakpoint-here>>")]
98 def set_breakpoint(self
, lineno
):
100 filename
= self
.io
.filename
101 text
.tag_add("BREAK", "%d.0" % lineno
, "%d.0" % (lineno
+1))
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....
112 def set_breakpoint_here(self
, event
=None):
114 filename
= self
.io
.filename
118 lineno
= int(float(text
.index("insert")))
119 self
.set_breakpoint(lineno
)
121 def clear_breakpoint_here(self
, event
=None):
123 filename
= self
.io
.filename
127 lineno
= int(float(text
.index("insert")))
129 self
.breakpoints
.remove(lineno
)
132 text
.tag_remove("BREAK", "insert linestart",\
133 "insert lineend +1char")
135 debug
= self
.flist
.pyshell
.interp
.debugger
136 debug
.clear_breakpoint_here(filename
, lineno
)
140 def clear_file_breaks(self
):
143 filename
= self
.io
.filename
147 self
.breakpoints
= []
148 text
.tag_remove("BREAK", "1.0", END
)
150 debug
= self
.flist
.pyshell
.interp
.debugger
151 debug
.clear_file_breaks(filename
)
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
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
181 lines
= open(self
.breakpointPath
,"r").readlines()
184 new_file
= open(self
.breakpointPath
,"w")
186 if not line
.startswith(filename
+ '='):
188 self
.update_breakpoints()
189 breaks
= self
.breakpoints
191 new_file
.write(filename
+ '=' + str(breaks
) + '\n')
194 def restore_file_breaks(self
):
195 self
.text
.update() # this enables setting "BREAK" tags to be visible
196 filename
= self
.io
.filename
199 if os
.path
.isfile(self
.breakpointPath
):
200 lines
= open(self
.breakpointPath
,"r").readlines()
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
)
207 def update_breakpoints(self
):
208 "Retrieves all the breakpoints in the current window"
210 ranges
= text
.tag_ranges("BREAK")
211 linenumber_list
= self
.ranges_to_linenumbers(ranges
)
212 self
.breakpoints
= linenumber_list
214 def ranges_to_linenumbers(self
, ranges
):
216 for index
in range(0, len(ranges
), 2):
217 lineno
= int(float(ranges
[index
]))
218 end
= int(float(ranges
[index
+1]))
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)
232 "Extend base method - clear breaks when module is closed"
233 self
.clear_file_breaks()
234 EditorWindow
._close
(self
)
237 class PyShellFileList(FileList
):
238 "Extend base class: file list when a shell is present"
240 EditorWindow
= PyShellEditorWindow
244 def open_shell(self
, event
=None):
246 self
.pyshell
.wakeup()
248 self
.pyshell
= PyShell(self
)
253 class ModifiedColorDelegator(ColorDelegator
):
254 "Extend base class: colorizer for the shell window itself"
257 ColorDelegator
.__init
__(self
)
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
)
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"),
276 class ModifiedUndoDelegator(UndoDelegator
):
277 "Extend base class: forbid insert/delete before the I/O mark"
279 def insert(self
, index
, chars
, tags
=None):
281 if self
.delegate
.compare(index
, "<", "iomark"):
286 UndoDelegator
.insert(self
, index
, chars
, tags
)
288 def delete(self
, index1
, index2
=None):
290 if self
.delegate
.compare(index1
, "<", "iomark"):
295 UndoDelegator
.delete(self
, index1
, index2
)
298 class MyRPCClient(rpc
.RPCClient
):
300 def handle_EOF(self
):
301 "Override the base class - just re-raise EOFError"
305 class ModifiedInterpreter(InteractiveInterpreter
):
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()
319 def spawn_subprocess(self
):
320 args
= self
.subprocess_arglist
321 self
.rpcpid
= os
.spawnv(os
.P_NOWAIT
, sys
.executable
, args
)
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`
+")"
333 command
= "__import__('run').main(" + `del_exitf`
+ ")"
334 if sys
.platform
[:3] == 'win' and ' ' in sys
.executable
:
335 # handle embedded space in path by quoting the argument
336 decorated_exec
= '"%s"' % sys
.executable
338 decorated_exec
= sys
.executable
339 return [decorated_exec
] + w
+ ["-c", command
, str(self
.port
)]
341 def start_subprocess(self
):
342 addr
= (LOCALHOST
, self
.port
)
343 # Idle starts listening for connection on localhost
347 self
.rpcclt
= MyRPCClient(addr
)
349 except socket
.error
, err
:
350 print>>sys
.__stderr
__,"IDLE socket error: " + err
[1]\
353 display_port_binding_error()
355 self
.spawn_subprocess()
356 # Accept the connection from the Python execution server
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
)
365 self
.poll_subprocess()
367 def restart_subprocess(self
):
370 self
.restarting
= True
371 # close only the subprocess debugger
372 debug
= self
.getdebugger()
375 # Only close subprocess debugger, don't unregister gui_adap!
376 RemoteDebugger
.close_subprocess_debugger(self
.rpcclt
)
379 # Kill subprocess, spawn a new one, accept connection.
381 self
.unix_terminate()
382 console
= self
.tkconsole
383 was_executing
= console
.executing
384 console
.executing
= False
385 self
.spawn_subprocess()
388 # annotate restart in shell window and mark it
389 console
.text
.delete("iomark", "end-1c")
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")
398 # restart subprocess debugger
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
406 def __request_interrupt(self
):
407 self
.rpcclt
.remotecall("exec", "interrupt_the_server", (), {})
409 def interrupt_subprocess(self
):
410 threading
.Thread(target
=self
.__request
_interrupt
).start()
412 def kill_subprocess(self
):
414 self
.unix_terminate()
415 self
.tkconsole
.executing
= False
418 def unix_terminate(self
):
419 "UNIX: make sure subprocess is terminated and collect status"
420 if hasattr(os
, 'kill'):
422 os
.kill(self
.rpcpid
, SIGTERM
)
424 # process already terminated:
428 os
.waitpid(self
.rpcpid
, 0)
432 def transfer_path(self
):
433 self
.runcommand("""if 1:
437 _msg = 'Use File/Exit or your end-of-file key to quit IDLE'
438 __builtins__.quit = __builtins__.exit = _msg
444 def poll_subprocess(self
):
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
:
456 self
.restart_subprocess()
458 self
.tkconsole
.resetoutput()
459 self
.active_seq
= None
461 console
= self
.tkconsole
.console
464 print >>console
, `what`
465 elif how
== "EXCEPTION":
466 if self
.tkconsole
.getvar("<<toggle-jit-stack-viewer>>"):
467 self
.remote_stack_viewer()
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()
475 if not self
.tkconsole
.closing
:
476 self
.tkconsole
.text
.after(self
.tkconsole
.pollinterval
,
477 self
.poll_subprocess
)
481 def setdebugger(self
, debugger
):
482 self
.debugger
= debugger
484 def getdebugger(self
):
487 def open_remote_stack_viewer(self
):
488 """Initiate the remote stack viewer from a separate thread.
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
497 self
.tkconsole
.text
.after(300, self
.remote_stack_viewer
)
500 def remote_stack_viewer(self
):
501 import RemoteObjectBrowser
502 oid
= self
.rpcclt
.remotequeue("exec", "stackviewer", ("flist",), {})
504 self
.tkconsole
.root
.bell()
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
)
513 # XXX Should GC the remote tree when closing the window
517 def execsource(self
, source
):
518 "Like runsource() but assumes complete exec source"
519 filename
= self
.stuffsource(source
)
520 self
.execfile(filename
, source
)
522 def execfile(self
, filename
, source
=None):
523 "Execute an existing file"
525 source
= open(filename
, "r").read()
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()
538 def runsource(self
, source
):
539 "Extend base class method: Stuff the source in the line cache first"
540 filename
= self
.stuffsource(source
)
542 self
.save_warnings_filters
= warnings
.filters
[:]
543 warnings
.filterwarnings(action
="error", category
=SyntaxWarning)
544 if isinstance(source
, types
.UnicodeType
):
547 source
= source
.encode(IOBinding
.encoding
)
549 self
.tkconsole
.resetoutput()
550 self
.write("Unsupported characters in input")
553 return InteractiveInterpreter
.runsource(self
, source
, filename
)
555 if self
.save_warnings_filters
is not None:
556 warnings
.filters
[:] = self
.save_warnings_filters
557 self
.save_warnings_filters
= None
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
567 def prepend_syspath(self
, filename
):
568 "Prepend sys.path with file's directory if not already included"
569 self
.runcommand("""if 1:
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
579 def showsyntaxerror(self
, filename
=None):
580 """Extend base class method: Add Colorizing
582 Color the offending position instead of printing it and pointing at it
586 text
= self
.tkconsole
.text
587 stuff
= self
.unpackerror()
589 msg
, lineno
, offset
, line
= stuff
591 pos
= "iomark + %d chars" % (offset
-1)
593 pos
= "iomark linestart + %d lines + %d chars" % \
595 text
.tag_add("ERROR", 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
))
603 self
.tkconsole
.resetoutput()
604 InteractiveInterpreter
.showsyntaxerror(self
, filename
)
605 self
.tkconsole
.showprompt()
607 def unpackerror(self
):
608 type, value
, tb
= sys
.exc_info()
609 ok
= type is SyntaxError
612 msg
, (dummy_filename
, lineno
, offset
, line
) = value
618 return msg
, lineno
, offset
, line
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()
630 def checklinecache(self
):
633 if key
[:1] + key
[-1:] != "<>":
636 def display_executing_dialog(self
):
637 tkMessageBox
.showerror(
639 "The Python Shell window is already executing a command; "
640 "please wait until it is finished.",
641 master
=self
.tkconsole
.text
)
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()
650 self
.rpcclt
.remotequeue("exec", "runcode", (code
,), {})
652 exec code
in self
.locals
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
665 self
.tkconsole
.beginexecuting()
667 if not debugger
and self
.rpcclt
is not None:
668 self
.active_seq
= self
.rpcclt
.asyncqueue("exec", "runcode",
671 debugger
.run(code
, self
.locals)
673 exec code
in self
.locals
675 if tkMessageBox
.askyesno(
677 "Do you want to exit altogether?",
679 master
=self
.tkconsole
.text
):
686 if not use_subprocess
:
687 self
.tkconsole
.endexecuting()
690 "Override base class method"
691 self
.tkconsole
.stderr
.write(s
)
693 class PyShell(OutputWindow
):
695 shell_title
= "Python Shell"
698 ColorDelegator
= ModifiedColorDelegator
699 UndoDelegator
= ModifiedUndoDelegator
706 ("options", "_Options"),
707 ("windows", "_Windows"),
712 from IdleHistory
import History
714 def __init__(self
, flist
=None):
717 if ms
[2][0] != "shell":
718 ms
.insert(2, ("shell", "_Shell"))
719 self
.interp
= ModifiedInterpreter(self
)
724 flist
= PyShellFileList(root
)
726 OutputWindow
.__init
__(self
, flist
, None, None)
729 __builtin__
.quit
= __builtin__
.exit
= "To exit, type Ctrl-D."
731 self
.config(usetabs
=1, indentwidth
=8, context_use_ps1
=1)
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
)
745 text
.bind("<<view-restart>>", self
.view_restart_mark
)
746 text
.bind("<<restart-shell>>", self
.restart_shell
)
748 self
.save_stdout
= sys
.stdout
749 self
.save_stderr
= sys
.stderr
750 self
.save_stdin
= sys
.stdin
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
760 self
.history
= self
.History(self
.text
)
762 self
.pollinterval
= 50 # millisec
764 self
.interp
.start_subprocess()
772 def toggle_debugger(self
, event
=None):
774 tkMessageBox
.showerror("Don't debug now",
775 "You can only toggle the debugger when idle",
777 self
.set_debugger_indicator()
780 db
= self
.interp
.getdebugger()
782 self
.close_debugger()
786 def set_debugger_indicator(self
):
787 db
= self
.interp
.getdebugger()
788 self
.setvar("<<toggle-debugger>>", not not db
)
790 def toggle_jit_stack_viewer(self
, event
=None):
791 pass # All we need is the variable
793 def close_debugger(self
):
794 db
= self
.interp
.getdebugger()
796 self
.interp
.setdebugger(None)
798 if self
.interp
.rpcclt
:
799 RemoteDebugger
.close_remote_debugger(self
.interp
.rpcclt
)
801 self
.console
.write("[DEBUG OFF]\n")
804 self
.set_debugger_indicator()
806 def open_debugger(self
):
807 if self
.interp
.rpcclt
:
808 dbg_gui
= RemoteDebugger
.start_remote_debugger(self
.interp
.rpcclt
,
811 dbg_gui
= Debugger
.Debugger(self
)
812 self
.interp
.setdebugger(dbg_gui
)
813 dbg_gui
.load_breakpoints()
814 sys
.ps1
= "[DEBUG ON]\n>>> "
816 self
.set_debugger_indicator()
818 def beginexecuting(self
):
819 "Helper for ModifiedInterpreter"
823 def endexecuting(self
):
824 "Helper for ModifiedInterpreter"
830 "Extend EditorWindow.close()"
832 response
= tkMessageBox
.askokcancel(
834 "The program is still running!\n Do you want to kill it?",
837 if response
== False:
840 # Wait for poll_subprocess() rescheduling to stop
841 self
.text
.after(2 * self
.pollinterval
, self
.close2
)
844 return EditorWindow
.close(self
)
847 "Extend EditorWindow._close(), shut down debugger and execution server"
848 self
.close_debugger()
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
858 self
.flist
.pyshell
= None
860 EditorWindow
._close
(self
)
862 def ispythonsource(self
, filename
):
863 "Override EditorWindow method: never remove the colorizer"
866 def short_title(self
):
867 return self
.shell_title
870 'Type "copyright", "credits" or "license()" for more information.'
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 ****************************************************************
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
))
892 Tkinter
._default
_root
= None
905 line
= self
.text
.get("iomark", "end-1c")
906 if isinstance(line
, unicode):
909 line
= line
.encode(IOBinding
.encoding
)
915 raise KeyboardInterrupt
924 def cancel_callback(self
, event
=None):
926 if self
.text
.compare("sel.first", "!=", "sel.last"):
927 return # Active selection -- always use default binding
930 if not (self
.executing
or self
.reading
):
932 self
.interp
.write("KeyboardInterrupt\n")
939 elif (self
.executing
and self
.interp
.rpcclt
):
940 if self
.interp
.getdebugger():
941 self
.interp
.restart_subprocess()
943 self
.interp
.interrupt_subprocess()
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
:
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")
971 def linefeed_callback(self
, event
):
972 # Insert a linefeed without entering anything (still autoindented)
974 self
.text
.insert("insert", "\n")
975 self
.text
.see("insert")
977 self
.newline_and_indent_event(event
)
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)
986 sel
= self
.text
.get("sel.first", "sel.last")
988 if self
.text
.compare("sel.last", "<=", "iomark"):
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]))
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]))
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
):]
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
)
1027 # We're in the last line; append a newline and submit it
1028 self
.text
.mark_set("insert", "end-1c")
1030 self
.text
.insert("insert", "\n")
1031 self
.text
.see("insert")
1033 self
.newline_and_indent_event(event
)
1034 self
.text
.tag_add("stdin", "iomark", "end-1c")
1035 self
.text
.update_idletasks()
1037 self
.top
.quit() # Break out of recursive mainloop() in raw_input()
1042 def recall(self
, s
):
1044 self
.history
.recall(s
)
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.)
1051 while i
> 0 and line
[i
-1] in " \t":
1053 if i
> 0 and line
[i
-1] == "\n":
1055 while i
> 0 and line
[i
-1] in " \t":
1058 more
= self
.interp
.runsource(line
)
1060 def open_stack_viewer(self
, event
=None):
1061 if self
.interp
.rpcclt
:
1062 return self
.interp
.remote_stack_viewer()
1066 tkMessageBox
.showerror("No stack trace",
1067 "There is no stack trace yet.\n"
1068 "(sys.last_traceback is not defined)",
1071 from StackViewer
import StackBrowser
1072 sv
= StackBrowser(self
.root
, self
.flist
)
1074 def view_restart_mark(self
, event
=None):
1075 self
.text
.see("iomark")
1076 self
.text
.see("restart")
1078 def restart_shell(self
, event
=None):
1079 self
.interp
.restart_subprocess()
1081 def showprompt(self
):
1087 self
.console
.write(s
)
1088 self
.text
.mark_set("insert", "end-1c")
1089 self
.set_line_and_column()
1090 self
.io
.reset_undo()
1092 def resetoutput(self
):
1093 source
= self
.text
.get("iomark", "end-1c")
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
1102 def write(self
, s
, tags
=()):
1104 self
.text
.mark_gravity("iomark", "right")
1105 OutputWindow
.write(self
, s
, tags
, "iomark")
1106 self
.text
.mark_gravity("iomark", "left")
1111 if not use_subprocess
:
1112 raise KeyboardInterrupt
1116 def __init__(self
, shell
, tags
, encoding
=None):
1120 self
.encoding
= encoding
1123 self
.shell
.write(s
, self
.tags
)
1125 def writelines(self
, l
):
1137 USAGE: idle [-deins] [-t title] [file]*
1138 idle [-dns] [-t title] (-c cmd | -r file) [arg]*
1139 idle [-dns] [-t title] - [arg]*
1141 -h print this help message and exit
1142 -n run IDLE without a subprocess (see Help/IDLE Help for details)
1144 The following options will override the IDLE 'settings' configuration:
1146 -e open an edit window
1147 -i open a shell window
1149 The following options imply -i and will open a shell:
1151 -c cmd run the command in a shell, or
1152 -r file run script from file
1154 -d enable the debugger
1155 -s run $IDLESTARTUP or $PYTHONSTARTUP before anything else
1156 -t title set title of shell window
1158 A default edit window will be bypassed when -c, -r, or - are used.
1160 [arg]* are passed to the command (-c) or script (-r) in sys.argv[1:].
1165 Open an edit window or shell depending on IDLE's configuration.
1167 idle foo.py foobar.py
1168 Edit the files, also open a shell if configured to start with shell.
1170 idle -est "Baz" foo.py
1171 Run $IDLESTARTUP or $PYTHONSTARTUP, edit foo.py, and open a shell
1172 window with the title "Baz".
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].
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
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].
1189 global flist
, root
, use_subprocess
1191 use_subprocess
= True
1192 enable_shell
= False
1200 except AttributeError:
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
)
1218 sys
.stdout
.write(usage_msg
)
1223 use_subprocess
= False
1226 if os
.path
.isfile(script
):
1229 print "No script file: ", script
1236 PyShell
.shell_title
= a
1238 if args
and args
[0] == '-':
1239 cmd
= sys
.stdin
.read()
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:]
1247 sys
.argv
= ['-c'] + args
1249 sys
.argv
= [script
] + args
1253 for filename
in args
:
1254 pathx
.append(os
.path
.dirname(filename
))
1256 dir = os
.path
.abspath(dir)
1257 if not dir in sys
.path
:
1258 sys
.path
.insert(0, dir)
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")
1272 flist
= PyShellFileList(root
)
1274 if not (cmd
or script
):
1275 for filename
in args
:
1276 flist
.open(filename
)
1282 flist
.pyshell
= PyShell(flist
)
1283 flist
.pyshell
.begin()
1284 shell
= flist
.pyshell
1285 # handle remaining options:
1287 shell
.open_debugger()
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
)
1294 shell
.interp
.runcommand("""if 1:
1300 shell
.interp
.execsource(cmd
)
1302 shell
.interp
.prepend_syspath(script
)
1303 shell
.interp
.execfile(script
)
1308 def display_port_binding_error():
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:
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
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
1325 if __name__
== "__main__":
1326 sys
.modules
['PyShell'] = sys
.modules
['__main__']