@@ -56,14 +56,16 @@ def __call__(self):
56
56
pass
57
57
58
58
59
- def run_in_spawned_child_process (func , * , args = None , kwargs = None , timeout = None ):
59
+ def run_in_spawned_child_process (func , * , args = None , kwargs = None , timeout = None , rethrow = False ):
60
60
"""Run `func` in a spawned child process, capturing stdout/stderr.
61
61
62
62
The provided `func` must be defined at the top level of a module, and must
63
63
be importable in the spawned child process. Lambdas, closures, or interactively
64
64
defined functions (e.g., in Jupyter notebooks) will not work.
65
- """
66
65
66
+ If `rethrow=True` and the child process exits with a nonzero code,
67
+ raises ChildProcessError with the captured stderr.
68
+ """
67
69
ctx = multiprocessing .get_context ("spawn" )
68
70
result_queue = ctx .Queue ()
69
71
process = ctx .Process (target = Worker (result_queue , func , args , kwargs ))
@@ -74,26 +76,35 @@ def run_in_spawned_child_process(func, *, args=None, kwargs=None, timeout=None):
74
76
if process .is_alive ():
75
77
process .terminate ()
76
78
process .join ()
77
- return CompletedProcess (
79
+ result = CompletedProcess (
78
80
returncode = PROCESS_KILLED ,
79
81
stdout = "" ,
80
82
stderr = f"Process timed out after { timeout } seconds and was terminated." ,
81
83
)
82
-
83
- try :
84
- returncode , stdout , stderr = result_queue .get (timeout = 1.0 )
85
- except (queue .Empty , EOFError ):
86
- return CompletedProcess (
87
- returncode = PROCESS_NO_RESULT ,
88
- stdout = "" ,
89
- stderr = "Process exited or crashed before returning results." ,
84
+ else :
85
+ try :
86
+ returncode , stdout , stderr = result_queue .get (timeout = 1.0 )
87
+ except (queue .Empty , EOFError ):
88
+ result = CompletedProcess (
89
+ returncode = PROCESS_NO_RESULT ,
90
+ stdout = "" ,
91
+ stderr = "Process exited or crashed before returning results." ,
92
+ )
93
+ else :
94
+ result = CompletedProcess (
95
+ returncode = returncode ,
96
+ stdout = stdout ,
97
+ stderr = stderr ,
98
+ )
99
+
100
+ if rethrow and result .returncode != 0 :
101
+ raise ChildProcessError (
102
+ f"Child process exited with code { result .returncode } .\n "
103
+ f"--- stderr-from-child-process ---\n { result .stderr } "
104
+ "<end-of-stderr-from-child-process>\n "
90
105
)
91
106
92
- return CompletedProcess (
93
- returncode = returncode ,
94
- stdout = stdout ,
95
- stderr = stderr ,
96
- )
107
+ return result
97
108
98
109
finally :
99
110
try :
0 commit comments