13
13
import os
14
14
import subprocess
15
15
import sys
16
- from typing import Optional , Protocol , Union
16
+ from typing import (
17
+ IO ,
18
+ Any ,
19
+ Callable ,
20
+ Iterable ,
21
+ Mapping ,
22
+ Optional ,
23
+ Protocol ,
24
+ Sequence ,
25
+ Union ,
26
+ )
27
+
28
+ from typing_extensions import TypeAlias
17
29
18
30
from .. import exc
19
31
from ..types import StrOrBytesPath
@@ -143,28 +155,65 @@ def __call__(self, output: Union[str, bytes], timestamp: datetime.datetime):
143
155
...
144
156
145
157
158
+ if sys .platform == "win32" :
159
+ _ENV : TypeAlias = Mapping [str , str ]
160
+ else :
161
+ _ENV : TypeAlias = Union [
162
+ Mapping [bytes , StrOrBytesPath ], Mapping [str , StrOrBytesPath ]
163
+ ]
164
+
165
+ _CMD = Union [StrOrBytesPath , Sequence [StrOrBytesPath ]]
166
+ _FILE : TypeAlias = Optional [Union [int , IO [Any ]]]
167
+
168
+
146
169
def run (
147
- cmd : Union [str , list [str ]],
170
+ args : _CMD ,
171
+ bufsize : int = - 1 ,
172
+ executable : Optional [StrOrBytesPath ] = None ,
173
+ stdin : Optional [_FILE ] = None ,
174
+ stdout : Optional [_FILE ] = None ,
175
+ stderr : Optional [_FILE ] = None ,
176
+ preexec_fn : Optional [Callable [[], Any ]] = None ,
177
+ close_fds : bool = True ,
148
178
shell : bool = False ,
149
179
cwd : Optional [StrOrBytesPath ] = None ,
180
+ env : Optional [_ENV ] = None ,
181
+ universal_newlines : Optional [bool ] = None ,
182
+ startupinfo : Optional [Any ] = None ,
183
+ creationflags : int = 0 ,
184
+ restore_signals : bool = True ,
185
+ start_new_session : bool = False ,
186
+ pass_fds : Any = (),
187
+ * ,
188
+ text : Optional [bool ] = None ,
189
+ encoding : Optional [str ] = None ,
190
+ errors : Optional [str ] = None ,
191
+ user : Optional [Union [str , int ]] = None ,
192
+ group : Optional [Union [str , int ]] = None ,
193
+ extra_groups : Optional [Iterable [Union [str , int ]]] = None ,
194
+ umask : int = - 1 ,
195
+ # Not until sys.version_info >= (3, 10)
196
+ # pipesize: int = -1,
197
+ # custom
150
198
log_in_real_time : bool = True ,
151
199
check_returncode : bool = True ,
152
200
callback : Optional [ProgressCallbackProtocol ] = None ,
153
201
):
154
- """Run 'cmd' in a shell and return the combined contents of stdout and
155
- stderr (Blocking). Throws an exception if the command exits non-zero.
202
+ """Run 'args' in a shell and return the combined contents of stdout and
203
+ stderr (Blocking). Throws an exception if the command exits non-zero.
204
+
205
+ Keyword arguments are passthrough to {class}`subprocess.Popen`.
156
206
157
207
Parameters
158
208
----------
159
- cmd : list or str, or single str, if shell=True
209
+ args : list or str, or single str, if shell=True
160
210
the command to run
161
211
162
212
shell : boolean
163
213
boolean indicating whether we are using advanced shell
164
214
features. Use only when absolutely necessary, since this allows a lot
165
215
more freedom which could be exploited by malicious code. See the
166
- warning here:
167
- http://docs.python.org/library/subprocess.html#popen-constructor
216
+ warning here: http://docs.python.org/library/subprocess.html#popen-constructor
168
217
169
218
cwd : str
170
219
dir command is run from. Defaults to ``path``.
@@ -187,11 +236,30 @@ def progress_cb(output, timestamp):
187
236
run(['git', 'pull'], callback=progress_cb)
188
237
"""
189
238
proc = subprocess .Popen (
190
- cmd ,
239
+ args ,
240
+ bufsize = bufsize ,
241
+ executable = executable ,
242
+ stdin = stdin ,
243
+ stdout = stdout or subprocess .PIPE ,
244
+ stderr = stderr or subprocess .PIPE ,
245
+ preexec_fn = preexec_fn ,
246
+ close_fds = close_fds ,
191
247
shell = shell ,
192
- stderr = subprocess .PIPE ,
193
- stdout = subprocess .PIPE ,
194
248
cwd = cwd ,
249
+ env = env ,
250
+ universal_newlines = universal_newlines ,
251
+ startupinfo = startupinfo ,
252
+ creationflags = creationflags ,
253
+ restore_signals = restore_signals ,
254
+ start_new_session = start_new_session ,
255
+ pass_fds = pass_fds ,
256
+ text = text ,
257
+ encoding = encoding ,
258
+ errors = errors ,
259
+ user = user ,
260
+ group = group ,
261
+ extra_groups = extra_groups ,
262
+ umask = umask ,
195
263
)
196
264
197
265
all_output = []
@@ -216,5 +284,5 @@ def progress_cb(output, timestamp):
216
284
all_output = console_to_str (b"" .join (stderr_lines ))
217
285
output = "" .join (all_output )
218
286
if code != 0 and check_returncode :
219
- raise exc .CommandError (output = output , returncode = code , cmd = cmd )
287
+ raise exc .CommandError (output = output , returncode = code , cmd = args )
220
288
return output
0 commit comments