source: python/trunk/Lib/idlelib/PyShell.py@ 611

Last change on this file since 611 was 391, checked in by dmik, 11 years ago

python: Merge vendor 2.7.6 to trunk.

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