0 | 0 |
from __future__ import annotations
|
1 | 1 |
|
2 | 2 |
import codecs
|
3 | |
import functools
|
4 | 3 |
import io
|
5 | 4 |
import logging
|
6 | 5 |
import os
|
|
13 | 12 |
import warnings
|
14 | 13 |
from multiprocessing import Pipe
|
15 | 14 |
from threading import Thread
|
|
15 |
from typing import Callable, Optional
|
16 | 16 |
|
17 | 17 |
#
|
18 | 18 |
# run() - A function to synchronously run an external process, supporting
|
|
299 | 299 |
return command
|
300 | 300 |
|
301 | 301 |
|
302 | |
def _deprecate_argument_calling(f):
|
303 | |
@functools.wraps(f)
|
304 | |
def wrapper(*args, **kwargs):
|
305 | |
if len(args) > 1:
|
306 | |
warnings.warn(
|
307 | |
"Calling procrunner.run() with unnamed arguments (apart from "
|
308 | |
"the command) is deprecated. Use keyword arguments instead.",
|
309 | |
DeprecationWarning,
|
310 | |
stacklevel=2,
|
311 | |
)
|
312 | |
return f(*args, **kwargs)
|
313 | |
|
314 | |
return wrapper
|
315 | |
|
316 | |
|
317 | |
@_deprecate_argument_calling
|
318 | 302 |
def run(
|
319 | 303 |
command,
|
320 | |
timeout=None,
|
|
304 |
*,
|
|
305 |
timeout: Optional[float] = None,
|
321 | 306 |
debug=None,
|
322 | |
stdin=None,
|
323 | |
print_stdout=True,
|
324 | |
print_stderr=True,
|
325 | |
callback_stdout=None,
|
326 | |
callback_stderr=None,
|
327 | |
environment=None,
|
328 | |
environment_override=None,
|
329 | |
win32resolve=True,
|
330 | |
working_directory=None,
|
331 | |
raise_timeout_exception=False,
|
|
307 |
stdin: Optional[bytes] = None,
|
|
308 |
print_stdout: bool = True,
|
|
309 |
print_stderr: bool = True,
|
|
310 |
callback_stdout: Optional[Callable] = None,
|
|
311 |
callback_stderr: Optional[Callable] = None,
|
|
312 |
environment: Optional[dict[str, str]] = None,
|
|
313 |
environment_override: Optional[dict[str, str]] = None,
|
|
314 |
win32resolve: bool = True,
|
|
315 |
working_directory: Optional[str] = None,
|
|
316 |
raise_timeout_exception: bool = False,
|
332 | 317 |
) -> subprocess.CompletedProcess:
|
333 | 318 |
"""
|
334 | 319 |
Run an external process.
|
|
436 | 421 |
if stdin is not None:
|
437 | 422 |
notifyee, notifier = Pipe(False)
|
438 | 423 |
thread_pipe_pool.append(notifyee)
|
439 | |
stdin = _NonBlockingStreamWriter(
|
|
424 |
_NonBlockingStreamWriter(
|
440 | 425 |
p.stdin, data=stdin, debug=debug, notify=notifier.close
|
441 | 426 |
)
|
442 | 427 |
|
|
530 | 515 |
"Process ended after %.1f seconds with exit code %d", runtime, p.returncode
|
531 | 516 |
)
|
532 | 517 |
|
533 | |
stdout = stdout.get_output()
|
534 | |
stderr = stderr.get_output()
|
535 | |
|
536 | |
if timeout_encountered and raise_timeout_exception:
|
|
518 |
output_stdout = stdout.get_output()
|
|
519 |
output_stderr = stderr.get_output()
|
|
520 |
|
|
521 |
if timeout is not None and timeout_encountered and raise_timeout_exception:
|
537 | 522 |
raise subprocess.TimeoutExpired(
|
538 | |
cmd=command, timeout=timeout, output=stdout, stderr=stderr
|
|
523 |
cmd=command, timeout=timeout, output=output_stdout, stderr=output_stderr
|
539 | 524 |
)
|
540 | 525 |
|
541 | 526 |
return subprocess.CompletedProcess(
|
542 | |
args=command, returncode=p.returncode, stdout=stdout, stderr=stderr
|
|
527 |
args=command,
|
|
528 |
returncode=p.returncode,
|
|
529 |
stdout=output_stdout,
|
|
530 |
stderr=output_stderr,
|
543 | 531 |
)
|