annotate CSP2/CSP2_env/env-d9b9114564458d9d-741b3de822f2aaca6c6caa4325c4afce/lib/python3.8/idlelib/runscript.py @ 68:5028fdace37b

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