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