11import multiprocessing
22import subprocess # nosec B404
33import sys
4+ import traceback
45from io import StringIO
56
67
@@ -16,14 +17,12 @@ def __call__(self):
1617 sys .stdout = StringIO ()
1718 sys .stderr = StringIO ()
1819
19- returncode = 0
2020 try :
2121 exec (self .python_code , {"__name__" : "__main__" }) # nosec B102
22+ returncode = 0
2223 except SystemExit as e : # Handle sys.exit()
2324 returncode = e .code if isinstance (e .code , int ) else 0
24- except Exception : # Capture other exceptions
25- import traceback
26-
25+ except BaseException :
2726 traceback .print_exc ()
2827 returncode = 1
2928 finally :
@@ -32,38 +31,54 @@ def __call__(self):
3231 stderr = sys .stderr .getvalue ()
3332 sys .stdout = old_stdout
3433 sys .stderr = old_stderr
35- self .result_queue .put ((returncode , stdout , stderr ))
34+ try : # noqa: SIM105
35+ self .result_queue .put ((returncode , stdout , stderr ))
36+ except Exception : # nosec B110
37+ # If the queue is broken (e.g., parent gone), best effort logging
38+ pass
3639
3740
3841def run_python_code_safely (python_code , * , timeout = None ):
39- """Replacement for subprocess.run that forces 'spawn' context """
42+ """Run Python code in a spawned subprocess, capturing stdout/stderr/output. """
4043 ctx = multiprocessing .get_context ("spawn" )
41- result_queue = ctx .Queue ()
44+ result_queue = ctx .SimpleQueue ()
4245 process = ctx .Process (target = Worker (python_code , result_queue ))
4346 process .start ()
4447
4548 try :
46- # Wait with timeout support
4749 process .join (timeout )
4850 if process .is_alive ():
4951 process .terminate ()
5052 process .join ()
51- raise subprocess .TimeoutExpired ([sys .executable , "-c" , python_code ], timeout )
53+ return subprocess .CompletedProcess (
54+ args = [sys .executable , "-c" , python_code ],
55+ returncode = - 9 ,
56+ stdout = "" ,
57+ stderr = f"Process timed out after { timeout } seconds and was terminated." ,
58+ )
5259
53- # Get results from queue
5460 if result_queue .empty ():
5561 return subprocess .CompletedProcess (
56- [sys .executable , "-c" , python_code ],
62+ args = [sys .executable , "-c" , python_code ],
5763 returncode = - 999 ,
5864 stdout = "" ,
59- stderr = "Process failed to return results" ,
65+ stderr = "Process exited without returning results. " ,
6066 )
6167
6268 returncode , stdout , stderr = result_queue .get ()
6369 return subprocess .CompletedProcess (
64- [sys .executable , "-c" , python_code ], returncode = returncode , stdout = stdout , stderr = stderr
70+ args = [sys .executable , "-c" , python_code ],
71+ returncode = returncode ,
72+ stdout = stdout ,
73+ stderr = stderr ,
6574 )
75+
6676 finally :
67- # Cleanup if needed
77+ try :
78+ result_queue .close ()
79+ result_queue .join_thread ()
80+ except Exception : # nosec B110
81+ pass
6882 if process .is_alive ():
6983 process .kill ()
84+ process .join ()
0 commit comments