Execute a Python script. Args: script_path: Path to the script to execute script_args: Arguments to pass to the script cwd: Current working directory for path resolution Raises: TargetError: If script execution fails
(script_path: str, script_args: List[str], cwd: str)
| 150 | |
| 151 | |
| 152 | def _execute_script(script_path: str, script_args: List[str], cwd: str) -> None: |
| 153 | """ |
| 154 | Execute a Python script. |
| 155 | |
| 156 | Args: |
| 157 | script_path: Path to the script to execute |
| 158 | script_args: Arguments to pass to the script |
| 159 | cwd: Current working directory for path resolution |
| 160 | |
| 161 | Raises: |
| 162 | TargetError: If script execution fails |
| 163 | """ |
| 164 | # Make script path absolute if it isn't already |
| 165 | if not os.path.isabs(script_path): |
| 166 | script_path = os.path.join(cwd, script_path) |
| 167 | |
| 168 | if not os.path.isfile(script_path): |
| 169 | raise TargetError(f"Script not found: {script_path}") |
| 170 | |
| 171 | # Replace sys.argv to match original script call |
| 172 | sys.argv = [script_path] + script_args |
| 173 | |
| 174 | try: |
| 175 | with open(script_path, 'rb') as f: |
| 176 | source_code = f.read() |
| 177 | |
| 178 | except FileNotFoundError as e: |
| 179 | raise TargetError(f"Script file not found: {script_path}") from e |
| 180 | except PermissionError as e: |
| 181 | raise TargetError(f"Permission denied reading script: {script_path}") from e |
| 182 | |
| 183 | main_module = types.ModuleType("__main__") |
| 184 | main_module.__file__ = script_path |
| 185 | main_module.__builtins__ = __builtins__ |
| 186 | # gh-140729: Create a __mp_main__ module to allow pickling |
| 187 | sys.modules['__main__'] = sys.modules['__mp_main__'] = main_module |
| 188 | |
| 189 | try: |
| 190 | code = compile(source_code, script_path, 'exec', module='__main__') |
| 191 | except SyntaxError as e: |
| 192 | raise TargetError(f"Syntax error in script {script_path}: {e}") from e |
| 193 | |
| 194 | # Execute the script - let exceptions propagate naturally so Python |
| 195 | # prints the full traceback to stderr |
| 196 | exec(code, main_module.__dict__) |
| 197 | |
| 198 | |
| 199 | def main() -> NoReturn: |