0001 """Extension to execute code outside the Python shell window. 0002 0003 This adds the following commands: 0004 0005 - Check module does a full syntax check of the current module. 0006 It also runs the tabnanny to catch any inconsistent tabs. 0007 0008 - Run module executes the module's code in the __main__ namespace. The window 0009 must have been saved previously. The module is added to sys.modules, and is 0010 also added to the __main__ namespace. 0011 0012 XXX GvR Redesign this interface (yet again) as follows: 0013 0014 - Present a dialog box for ``Run Module'' 0015 0016 - Allow specify command line arguments in the dialog box 0017 0018 """ 0019 0020 import os 0021 import re 0022 import string 0023 import tabnanny 0024 import tokenize 0025 import tkMessageBox 0026 import PyShell 0027 0028 from configHandler import idleConf 0029 0030 IDENTCHARS = string.ascii_letters + string.digits + "_" 0031 0032 indent_message = """Error: Inconsistent indentation detected! 0033 0034 This means that either: 0035 0036 1) your indentation is outright incorrect (easy to fix), or 0037 0038 2) your indentation mixes tabs and spaces in a way that depends on \ 0039 how many spaces a tab is worth. 0040 0041 To fix case 2, change all tabs to spaces by using Select All followed \ 0042 by Untabify Region (both in the Edit menu).""" 0043 0044 0045 class ScriptBinding: 0046 0047 menudefs = [ 0048 ('run', [None, 0049 ('Check Module', '<<check-module>>'), 0050 ('Run Module', '<<run-module>>'), ]), ] 0051 0052 def __init__(self, editwin): 0053 self.editwin = editwin 0054 # Provide instance variables referenced by Debugger 0055 # XXX This should be done differently 0056 self.flist = self.editwin.flist 0057 self.root = self.flist.root 0058 0059 def check_module_event(self, event): 0060 filename = self.getfilename() 0061 if not filename: 0062 return 0063 if not self.tabnanny(filename): 0064 return 0065 self.checksyntax(filename) 0066 0067 def tabnanny(self, filename): 0068 f = open(filename, 'r') 0069 try: 0070 tabnanny.process_tokens(tokenize.generate_tokens(f.readline)) 0071 except tokenize.TokenError, msg: 0072 msgtxt, (lineno, start) = msg 0073 self.editwin.gotoline(lineno) 0074 self.errorbox("Tabnanny Tokenizing Error", 0075 "Token Error: %s" % msgtxt) 0076 return False 0077 except tabnanny.NannyNag, nag: 0078 # The error messages from tabnanny are too confusing... 0079 self.editwin.gotoline(nag.get_lineno()) 0080 self.errorbox("Tab/space error", indent_message) 0081 return False 0082 return True 0083 0084 def checksyntax(self, filename): 0085 self.shell = shell = self.flist.open_shell() 0086 saved_stream = shell.get_warning_stream() 0087 shell.set_warning_stream(shell.stderr) 0088 f = open(filename, 'r') 0089 source = f.read() 0090 f.close() 0091 if '\r' in source: 0092 source = re.sub(r"\r\n", "\n", source) 0093 if source and source[-1] != '\n': 0094 source = source + '\n' 0095 text = self.editwin.text 0096 text.tag_remove("ERROR", "1.0", "end") 0097 try: 0098 try: 0099 # If successful, return the compiled code 0100 return compile(source, filename, "exec") 0101 except (SyntaxError, OverflowError), err: 0102 try: 0103 msg, (errorfilename, lineno, offset, line) = err 0104 if not errorfilename: 0105 err.args = msg, (filename, lineno, offset, line) 0106 err.filename = filename 0107 self.colorize_syntax_error(msg, lineno, offset) 0108 except: 0109 msg = "*** " + str(err) 0110 self.errorbox("Syntax error", 0111 "There's an error in your program:\n" + msg) 0112 return False 0113 finally: 0114 shell.set_warning_stream(saved_stream) 0115 0116 def colorize_syntax_error(self, msg, lineno, offset): 0117 text = self.editwin.text 0118 pos = "0.0 + %d lines + %d chars" % (lineno-1, offset-1) 0119 text.tag_add("ERROR", pos) 0120 char = text.get(pos) 0121 if char and char in IDENTCHARS: 0122 text.tag_add("ERROR", pos + " wordstart", pos) 0123 if '\n' == text.get(pos): # error at line end 0124 text.mark_set("insert", pos) 0125 else: 0126 text.mark_set("insert", pos + "+1c") 0127 text.see(pos) 0128 0129 def run_module_event(self, event): 0130 """Run the module after setting up the environment. 0131 0132 First check the syntax. If OK, make sure the shell is active and 0133 then transfer the arguments, set the run environment's working 0134 directory to the directory of the module being executed and also 0135 add that directory to its sys.path if not already included. 0136 0137 """ 0138 filename = self.getfilename() 0139 if not filename: 0140 return 0141 code = self.checksyntax(filename) 0142 if not code: 0143 return 0144 shell = self.shell 0145 interp = shell.interp 0146 if PyShell.use_subprocess: 0147 shell.restart_shell() 0148 dirname = os.path.dirname(filename) 0149 # XXX Too often this discards arguments the user just set... 0150 interp.runcommand("""if 1: 0151 _filename = %r 0152 import sys as _sys 0153 from os.path import basename as _basename 0154 if (not _sys.argv or 0155 _basename(_sys.argv[0]) != _basename(_filename)): 0156 _sys.argv = [_filename] 0157 import os as _os 0158 _os.chdir(%r) 0159 del _filename, _sys, _basename, _os 0160 \n""" % (filename, dirname)) 0161 interp.prepend_syspath(filename) 0162 # XXX KBK 03Jul04 When run w/o subprocess, runtime warnings still 0163 # go to __stderr__. With subprocess, they go to the shell. 0164 # Need to change streams in PyShell.ModifiedInterpreter. 0165 interp.runcode(code) 0166 0167 def getfilename(self): 0168 """Get source filename. If not saved, offer to save (or create) file 0169 0170 The debugger requires a source file. Make sure there is one, and that 0171 the current version of the source buffer has been saved. If the user 0172 declines to save or cancels the Save As dialog, return None. 0173 0174 If the user has configured IDLE for Autosave, the file will be 0175 silently saved if it already exists and is dirty. 0176 0177 """ 0178 filename = self.editwin.io.filename 0179 if not self.editwin.get_saved(): 0180 autosave = idleConf.GetOption('main', 'General', 0181 'autosave', type='bool') 0182 if autosave and filename: 0183 self.editwin.io.save(None) 0184 else: 0185 reply = self.ask_save_dialog() 0186 self.editwin.text.focus_set() 0187 if reply == "ok": 0188 self.editwin.io.save(None) 0189 filename = self.editwin.io.filename 0190 else: 0191 filename = None 0192 return filename 0193 0194 def ask_save_dialog(self): 0195 msg = "Source Must Be Saved\n" + 5*' ' + "OK to Save?" 0196 mb = tkMessageBox.Message(title="Save Before Run or Check", 0197 message=msg, 0198 icon=tkMessageBox.QUESTION, 0199 type=tkMessageBox.OKCANCEL, 0200 default=tkMessageBox.OK, 0201 master=self.editwin.text) 0202 return mb.show() 0203 0204 def errorbox(self, title, message): 0205 # XXX This should really be a function of EditorWindow... 0206 tkMessageBox.showerror(title, message, master=self.editwin.text) 0207 self.editwin.text.focus_set() 0208
Generated by PyXR 0.9.4