PyXR

c:\python24\lib \ idlelib \ ScriptBinding.py



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
SourceForge.net Logo