Use full package paths in imports.
[python/dscho.git] / Tools / idle / ScriptBinding.py
blob19a20b259d4e0bd876a4a134129c3c4422363a78
1 """Extension to execute code outside the Python shell window.
3 This adds the following commands (to the Edit menu, until there's a
4 separate Python menu):
6 - Check module (Alt-F5) does a full syntax check of the current module.
7 It also runs the tabnanny to catch any inconsistent tabs.
9 - Import module (F5) is equivalent to either import or reload of the
10 current module. The window must have been saved previously. The
11 module is added to sys.modules, and is also added to the __main__
12 namespace. Output goes to the shell window.
14 - Run module (Control-F5) does the same but executes the module's
15 code in the __main__ namespace.
17 """
19 import sys
20 import os
21 import imp
22 import tkMessageBox
24 indent_message = """Error: Inconsistent indentation detected!
26 This means that either:
28 (1) your indentation is outright incorrect (easy to fix), or
30 (2) your indentation mixes tabs and spaces in a way that depends on \
31 how many spaces a tab is worth.
33 To fix case 2, change all tabs to spaces by using Select All followed \
34 by Untabify Region (both in the Edit menu)."""
36 class ScriptBinding:
38 keydefs = {
39 '<<check-module>>': ['<Alt-F5>', '<Meta-F5>'],
40 '<<import-module>>': ['<F5>'],
41 '<<run-script>>': ['<Control-F5>'],
44 menudefs = [
45 ('edit', [None,
46 ('Check module', '<<check-module>>'),
47 ('Import module', '<<import-module>>'),
48 ('Run script', '<<run-script>>'),
53 def __init__(self, editwin):
54 if not editwin.runnable:
55 self.menudefs = []
56 self.keydefs = {}
57 self.editwin = editwin
58 # Provide instance variables referenced by Debugger
59 # XXX This should be done differently
60 self.flist = self.editwin.flist
61 self.root = self.flist.root
63 def check_module_event(self, event):
64 filename = self.getfilename()
65 if not filename:
66 return
67 if not self.tabnanny(filename):
68 return
69 if not self.checksyntax(filename):
70 return
72 def tabnanny(self, filename):
73 import tabnanny
74 import tokenize
75 f = open(filename, 'r')
76 try:
77 tabnanny.process_tokens(tokenize.generate_tokens(f.readline))
78 except tokenize.TokenError, msg:
79 self.errorbox("Token error",
80 "Token error:\n%s" % str(msg))
81 return 0
82 except tabnanny.NannyNag, nag:
83 # The error messages from tabnanny are too confusing...
84 self.editwin.gotoline(nag.get_lineno())
85 self.errorbox("Tab/space error", indent_message)
86 return 0
87 return 1
89 def checksyntax(self, filename):
90 f = open(filename, 'r')
91 source = f.read()
92 f.close()
93 if '\r' in source:
94 import re
95 source = re.sub(r"\r\n", "\n", source)
96 if source and source[-1] != '\n':
97 source = source + '\n'
98 try:
99 compile(source, filename, "exec")
100 except (SyntaxError, OverflowError), err:
101 try:
102 msg, (errorfilename, lineno, offset, line) = err
103 if not errorfilename:
104 err.args = msg, (filename, lineno, offset, line)
105 err.filename = filename
106 except:
107 lineno = None
108 msg = "*** " + str(err)
109 if lineno:
110 self.editwin.gotoline(lineno)
111 self.errorbox("Syntax error",
112 "There's an error in your program:\n" + msg)
113 return 1
115 def import_module_event(self, event):
116 filename = self.getfilename()
117 if not filename:
118 return
120 modname, ext = os.path.splitext(os.path.basename(filename))
121 if sys.modules.has_key(modname):
122 mod = sys.modules[modname]
123 else:
124 mod = imp.new_module(modname)
125 sys.modules[modname] = mod
126 mod.__file__ = filename
127 setattr(sys.modules['__main__'], modname, mod)
129 dir = os.path.dirname(filename)
130 dir = os.path.normpath(os.path.abspath(dir))
131 if dir not in sys.path:
132 sys.path.insert(0, dir)
134 flist = self.editwin.flist
135 shell = flist.open_shell()
136 interp = shell.interp
137 interp.runcode("reload(%s)" % modname)
139 def run_script_event(self, event):
140 filename = self.getfilename()
141 if not filename:
142 return
144 flist = self.editwin.flist
145 shell = flist.open_shell()
146 interp = shell.interp
147 if (not sys.argv or
148 os.path.basename(sys.argv[0]) != os.path.basename(filename)):
149 # XXX Too often this discards arguments the user just set...
150 sys.argv = [filename]
151 interp.execfile(filename)
153 def getfilename(self):
154 # Logic to make sure we have a saved filename
155 # XXX Better logic would offer to save!
156 if not self.editwin.get_saved():
157 name = (self.editwin.short_title() or
158 self.editwin.long_title() or
159 "Untitled")
160 self.errorbox("Not saved",
161 "The buffer for %s is not saved.\n" % name +
162 "Please save it first!")
163 self.editwin.text.focus_set()
164 return
165 filename = self.editwin.io.filename
166 if not filename:
167 self.errorbox("No file name",
168 "This window has no file name")
169 return
170 return filename
172 def errorbox(self, title, message):
173 # XXX This should really be a function of EditorWindow...
174 tkMessageBox.showerror(title, message, master=self.editwin.text)
175 self.editwin.text.focus_set()