mirror of
				https://github.com/python/cpython.git
				synced 2025-11-04 11:49:12 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			169 lines
		
	
	
	
		
			5.4 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			169 lines
		
	
	
	
		
			5.4 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
"""Extension to execute code outside the Python shell window.
 | 
						|
 | 
						|
This adds the following commands (to the Edit menu, until there's a
 | 
						|
separate Python menu):
 | 
						|
 | 
						|
- Check module (Alt-F5) does a full syntax check of the current module.
 | 
						|
It also runs the tabnanny to catch any inconsistent tabs.
 | 
						|
 | 
						|
- Import module (F5) is equivalent to either import or reload of the
 | 
						|
current module.  The window must have been saved previously. The
 | 
						|
module is added to sys.modules, and is also added to the __main__
 | 
						|
namespace.  Output goes to the shell window.
 | 
						|
 | 
						|
- Run module (Control-F5) does the same but executes the module's
 | 
						|
code in the __main__ namespace.
 | 
						|
 | 
						|
"""
 | 
						|
 | 
						|
import sys
 | 
						|
import os
 | 
						|
import imp
 | 
						|
import tkMessageBox
 | 
						|
 | 
						|
indent_message = """Error: Inconsistent indentation detected!
 | 
						|
 | 
						|
This means that either:
 | 
						|
 | 
						|
(1) your indentation is outright incorrect (easy to fix), or
 | 
						|
 | 
						|
(2) your indentation mixes tabs and spaces in a way that depends on \
 | 
						|
how many spaces a tab is worth.
 | 
						|
 | 
						|
To fix case 2, change all tabs to spaces by using Select All followed \
 | 
						|
by Untabify Region (both in the Edit menu)."""
 | 
						|
 | 
						|
class ScriptBinding:
 | 
						|
    
 | 
						|
    keydefs = {
 | 
						|
        '<<check-module>>': ['<Alt-F5>', '<Meta-F5>'],
 | 
						|
        '<<import-module>>': ['<F5>'],
 | 
						|
        '<<run-script>>': ['<Control-F5>'],
 | 
						|
    }
 | 
						|
    
 | 
						|
    menudefs = [
 | 
						|
        ('edit', [None,
 | 
						|
                  ('Check module', '<<check-module>>'),
 | 
						|
                  ('Import module', '<<import-module>>'),
 | 
						|
                  ('Run script', '<<run-script>>'),
 | 
						|
                 ]
 | 
						|
        ),
 | 
						|
    ]
 | 
						|
 | 
						|
    def __init__(self, editwin):
 | 
						|
        self.editwin = editwin
 | 
						|
        # Provide instance variables referenced by Debugger
 | 
						|
        # XXX This should be done differently
 | 
						|
        self.flist = self.editwin.flist
 | 
						|
        self.root = self.flist.root
 | 
						|
 | 
						|
    def check_module_event(self, event):
 | 
						|
        filename = self.getfilename()
 | 
						|
        if not filename:
 | 
						|
            return
 | 
						|
        if not self.tabnanny(filename):
 | 
						|
            return
 | 
						|
        if not self.checksyntax(filename):
 | 
						|
            return
 | 
						|
 | 
						|
    def tabnanny(self, filename):
 | 
						|
        import tabnanny
 | 
						|
        import tokenize
 | 
						|
        tabnanny.reset_globals()
 | 
						|
        f = open(filename, 'r')
 | 
						|
        try:
 | 
						|
            tokenize.tokenize(f.readline, tabnanny.tokeneater)
 | 
						|
        except tokenize.TokenError, msg:
 | 
						|
            self.errorbox("Token error",
 | 
						|
                          "Token error:\n%s" % str(msg))
 | 
						|
            return 0
 | 
						|
        except tabnanny.NannyNag, nag:
 | 
						|
            # The error messages from tabnanny are too confusing...
 | 
						|
            self.editwin.gotoline(nag.get_lineno())
 | 
						|
            self.errorbox("Tab/space error", indent_message)
 | 
						|
            return 0
 | 
						|
        return 1
 | 
						|
 | 
						|
    def checksyntax(self, filename):
 | 
						|
        f = open(filename, 'r')
 | 
						|
        source = f.read()
 | 
						|
        f.close()
 | 
						|
        if '\r' in source:
 | 
						|
            import re
 | 
						|
            source = re.sub(r"\r\n", "\n", source)
 | 
						|
        if source and source[-1] != '\n':
 | 
						|
            source = source + '\n'
 | 
						|
        try:
 | 
						|
            compile(source, filename, "exec")
 | 
						|
        except (SyntaxError, OverflowError), err:
 | 
						|
            try:
 | 
						|
                msg, (errorfilename, lineno, offset, line) = err
 | 
						|
                if not errorfilename:
 | 
						|
                    err.args = msg, (filename, lineno, offset, line)
 | 
						|
                    err.filename = filename
 | 
						|
            except:
 | 
						|
                lineno = None
 | 
						|
                msg = "*** " + str(err)
 | 
						|
            if lineno:
 | 
						|
                self.editwin.gotoline(lineno)
 | 
						|
            self.errorbox("Syntax error",
 | 
						|
                          "There's an error in your program:\n" + msg)
 | 
						|
        return 1
 | 
						|
 | 
						|
    def import_module_event(self, event):
 | 
						|
        filename = self.getfilename()
 | 
						|
        if not filename:
 | 
						|
            return
 | 
						|
 | 
						|
        modname, ext = os.path.splitext(os.path.basename(filename))
 | 
						|
        if sys.modules.has_key(modname):
 | 
						|
            mod = sys.modules[modname]
 | 
						|
        else:
 | 
						|
            mod = imp.new_module(modname)
 | 
						|
            sys.modules[modname] = mod
 | 
						|
        mod.__file__ = filename
 | 
						|
        setattr(sys.modules['__main__'], modname, mod)
 | 
						|
 | 
						|
        dir = os.path.dirname(filename)
 | 
						|
        dir = os.path.normpath(os.path.abspath(dir))
 | 
						|
        if dir not in sys.path:
 | 
						|
            sys.path.insert(0, dir)
 | 
						|
 | 
						|
        flist = self.editwin.flist
 | 
						|
        shell = flist.open_shell()
 | 
						|
        interp = shell.interp
 | 
						|
        interp.runcode("reload(%s)" % modname)
 | 
						|
 | 
						|
    def run_script_event(self, event):
 | 
						|
        filename = self.getfilename()
 | 
						|
        if not filename:
 | 
						|
            return
 | 
						|
 | 
						|
        flist = self.editwin.flist
 | 
						|
        shell = flist.open_shell()
 | 
						|
        interp = shell.interp
 | 
						|
        if (not sys.argv or
 | 
						|
            os.path.basename(sys.argv[0]) != os.path.basename(filename)):
 | 
						|
            # XXX Too often this discards arguments the user just set...
 | 
						|
            sys.argv = [filename]
 | 
						|
        interp.execfile(filename)
 | 
						|
 | 
						|
    def getfilename(self):
 | 
						|
        # Logic to make sure we have a saved filename
 | 
						|
        # XXX Better logic would offer to save!
 | 
						|
        if not self.editwin.get_saved():
 | 
						|
            self.errorbox("Not saved",
 | 
						|
                          "Please save first!")
 | 
						|
            self.editwin.text.focus_set()
 | 
						|
            return
 | 
						|
        filename = self.editwin.io.filename
 | 
						|
        if not filename:
 | 
						|
            self.errorbox("No file name",
 | 
						|
                          "This window has no file name")
 | 
						|
            return
 | 
						|
        return filename
 | 
						|
 | 
						|
    def errorbox(self, title, message):
 | 
						|
        # XXX This should really be a function of EditorWindow...
 | 
						|
        tkMessageBox.showerror(title, message, master=self.editwin.text)
 | 
						|
        self.editwin.text.focus_set()
 |