Mercurial > repos > rliterman > csp2
comparison CSP2/CSP2_env/env-d9b9114564458d9d-741b3de822f2aaca6c6caa4325c4afce/lib/python3.8/idlelib/runscript.py @ 69:33d812a61356
planemo upload commit 2e9511a184a1ca667c7be0c6321a36dc4e3d116d
author | jpayne |
---|---|
date | Tue, 18 Mar 2025 17:55:14 -0400 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
67:0e9998148a16 | 69:33d812a61356 |
---|---|
1 """Execute code from an editor. | |
2 | |
3 Check module: do a full syntax check of the current module. | |
4 Also run the tabnanny to catch any inconsistent tabs. | |
5 | |
6 Run module: also execute the module's code in the __main__ namespace. | |
7 The window must have been saved previously. The module is added to | |
8 sys.modules, and is also added to the __main__ namespace. | |
9 | |
10 TODO: Specify command line arguments in a dialog box. | |
11 """ | |
12 import os | |
13 import tabnanny | |
14 import tokenize | |
15 | |
16 import tkinter.messagebox as tkMessageBox | |
17 | |
18 from idlelib.config import idleConf | |
19 from idlelib import macosx | |
20 from idlelib import pyshell | |
21 from idlelib.query import CustomRun | |
22 from idlelib import outwin | |
23 | |
24 indent_message = """Error: Inconsistent indentation detected! | |
25 | |
26 1) Your indentation is outright incorrect (easy to fix), OR | |
27 | |
28 2) Your indentation mixes tabs and spaces. | |
29 | |
30 To fix case 2, change all tabs to spaces by using Edit->Select All followed \ | |
31 by Format->Untabify Region and specify the number of columns used by each tab. | |
32 """ | |
33 | |
34 | |
35 class ScriptBinding: | |
36 | |
37 def __init__(self, editwin): | |
38 self.editwin = editwin | |
39 # Provide instance variables referenced by debugger | |
40 # XXX This should be done differently | |
41 self.flist = self.editwin.flist | |
42 self.root = self.editwin.root | |
43 # cli_args is list of strings that extends sys.argv | |
44 self.cli_args = [] | |
45 | |
46 if macosx.isCocoaTk(): | |
47 self.editwin.text_frame.bind('<<run-module-event-2>>', self._run_module_event) | |
48 | |
49 def check_module_event(self, event): | |
50 if isinstance(self.editwin, outwin.OutputWindow): | |
51 self.editwin.text.bell() | |
52 return 'break' | |
53 filename = self.getfilename() | |
54 if not filename: | |
55 return 'break' | |
56 if not self.checksyntax(filename): | |
57 return 'break' | |
58 if not self.tabnanny(filename): | |
59 return 'break' | |
60 return "break" | |
61 | |
62 def tabnanny(self, filename): | |
63 # XXX: tabnanny should work on binary files as well | |
64 with tokenize.open(filename) as f: | |
65 try: | |
66 tabnanny.process_tokens(tokenize.generate_tokens(f.readline)) | |
67 except tokenize.TokenError as msg: | |
68 msgtxt, (lineno, start) = msg.args | |
69 self.editwin.gotoline(lineno) | |
70 self.errorbox("Tabnanny Tokenizing Error", | |
71 "Token Error: %s" % msgtxt) | |
72 return False | |
73 except tabnanny.NannyNag as nag: | |
74 # The error messages from tabnanny are too confusing... | |
75 self.editwin.gotoline(nag.get_lineno()) | |
76 self.errorbox("Tab/space error", indent_message) | |
77 return False | |
78 return True | |
79 | |
80 def checksyntax(self, filename): | |
81 self.shell = shell = self.flist.open_shell() | |
82 saved_stream = shell.get_warning_stream() | |
83 shell.set_warning_stream(shell.stderr) | |
84 with open(filename, 'rb') as f: | |
85 source = f.read() | |
86 if b'\r' in source: | |
87 source = source.replace(b'\r\n', b'\n') | |
88 source = source.replace(b'\r', b'\n') | |
89 if source and source[-1] != ord(b'\n'): | |
90 source = source + b'\n' | |
91 editwin = self.editwin | |
92 text = editwin.text | |
93 text.tag_remove("ERROR", "1.0", "end") | |
94 try: | |
95 # If successful, return the compiled code | |
96 return compile(source, filename, "exec") | |
97 except (SyntaxError, OverflowError, ValueError) as value: | |
98 msg = getattr(value, 'msg', '') or value or "<no detail available>" | |
99 lineno = getattr(value, 'lineno', '') or 1 | |
100 offset = getattr(value, 'offset', '') or 0 | |
101 if offset == 0: | |
102 lineno += 1 #mark end of offending line | |
103 pos = "0.0 + %d lines + %d chars" % (lineno-1, offset-1) | |
104 editwin.colorize_syntax_error(text, pos) | |
105 self.errorbox("SyntaxError", "%-20s" % msg) | |
106 return False | |
107 finally: | |
108 shell.set_warning_stream(saved_stream) | |
109 | |
110 def run_module_event(self, event): | |
111 if macosx.isCocoaTk(): | |
112 # Tk-Cocoa in MacOSX is broken until at least | |
113 # Tk 8.5.9, and without this rather | |
114 # crude workaround IDLE would hang when a user | |
115 # tries to run a module using the keyboard shortcut | |
116 # (the menu item works fine). | |
117 self.editwin.text_frame.after(200, | |
118 lambda: self.editwin.text_frame.event_generate( | |
119 '<<run-module-event-2>>')) | |
120 return 'break' | |
121 else: | |
122 return self._run_module_event(event) | |
123 | |
124 def run_custom_event(self, event): | |
125 return self._run_module_event(event, customize=True) | |
126 | |
127 def _run_module_event(self, event, *, customize=False): | |
128 """Run the module after setting up the environment. | |
129 | |
130 First check the syntax. Next get customization. If OK, make | |
131 sure the shell is active and then transfer the arguments, set | |
132 the run environment's working directory to the directory of the | |
133 module being executed and also add that directory to its | |
134 sys.path if not already included. | |
135 """ | |
136 if isinstance(self.editwin, outwin.OutputWindow): | |
137 self.editwin.text.bell() | |
138 return 'break' | |
139 filename = self.getfilename() | |
140 if not filename: | |
141 return 'break' | |
142 code = self.checksyntax(filename) | |
143 if not code: | |
144 return 'break' | |
145 if not self.tabnanny(filename): | |
146 return 'break' | |
147 if customize: | |
148 title = f"Customize {self.editwin.short_title()} Run" | |
149 run_args = CustomRun(self.shell.text, title, | |
150 cli_args=self.cli_args).result | |
151 if not run_args: # User cancelled. | |
152 return 'break' | |
153 self.cli_args, restart = run_args if customize else ([], True) | |
154 interp = self.shell.interp | |
155 if pyshell.use_subprocess and restart: | |
156 interp.restart_subprocess( | |
157 with_cwd=False, filename=filename) | |
158 dirname = os.path.dirname(filename) | |
159 argv = [filename] | |
160 if self.cli_args: | |
161 argv += self.cli_args | |
162 interp.runcommand(f"""if 1: | |
163 __file__ = {filename!r} | |
164 import sys as _sys | |
165 from os.path import basename as _basename | |
166 argv = {argv!r} | |
167 if (not _sys.argv or | |
168 _basename(_sys.argv[0]) != _basename(__file__) or | |
169 len(argv) > 1): | |
170 _sys.argv = argv | |
171 import os as _os | |
172 _os.chdir({dirname!r}) | |
173 del _sys, argv, _basename, _os | |
174 \n""") | |
175 interp.prepend_syspath(filename) | |
176 # XXX KBK 03Jul04 When run w/o subprocess, runtime warnings still | |
177 # go to __stderr__. With subprocess, they go to the shell. | |
178 # Need to change streams in pyshell.ModifiedInterpreter. | |
179 interp.runcode(code) | |
180 return 'break' | |
181 | |
182 def getfilename(self): | |
183 """Get source filename. If not saved, offer to save (or create) file | |
184 | |
185 The debugger requires a source file. Make sure there is one, and that | |
186 the current version of the source buffer has been saved. If the user | |
187 declines to save or cancels the Save As dialog, return None. | |
188 | |
189 If the user has configured IDLE for Autosave, the file will be | |
190 silently saved if it already exists and is dirty. | |
191 | |
192 """ | |
193 filename = self.editwin.io.filename | |
194 if not self.editwin.get_saved(): | |
195 autosave = idleConf.GetOption('main', 'General', | |
196 'autosave', type='bool') | |
197 if autosave and filename: | |
198 self.editwin.io.save(None) | |
199 else: | |
200 confirm = self.ask_save_dialog() | |
201 self.editwin.text.focus_set() | |
202 if confirm: | |
203 self.editwin.io.save(None) | |
204 filename = self.editwin.io.filename | |
205 else: | |
206 filename = None | |
207 return filename | |
208 | |
209 def ask_save_dialog(self): | |
210 msg = "Source Must Be Saved\n" + 5*' ' + "OK to Save?" | |
211 confirm = tkMessageBox.askokcancel(title="Save Before Run or Check", | |
212 message=msg, | |
213 default=tkMessageBox.OK, | |
214 parent=self.editwin.text) | |
215 return confirm | |
216 | |
217 def errorbox(self, title, message): | |
218 # XXX This should really be a function of EditorWindow... | |
219 tkMessageBox.showerror(title, message, parent=self.editwin.text) | |
220 self.editwin.text.focus_set() | |
221 | |
222 | |
223 if __name__ == "__main__": | |
224 from unittest import main | |
225 main('idlelib.idle_test.test_runscript', verbosity=2,) |