Skip to content

Commit 6ca16b7

Browse files
committed
Allow stdin=subprocess.DEVNULL
The current default is to connect through the existing stdin to the subprocess, and there is no way to explicitly close the subprocess stdin. Allow stdin=subprocess.DEVNULL for this.
1 parent c765276 commit 6ca16b7

File tree

3 files changed

+25
-3
lines changed

3 files changed

+25
-3
lines changed

HISTORY.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ History
1616
(previously deprecated in `#62 <https://github.com/DiamondLightSource/python-procrunner/pull/62>`_)
1717
* The run() function no longer accepts a 'debug' argument
1818
(previously deprecated in `#63 <https://github.com/DiamondLightSource/python-procrunner/pull/63>`_)
19+
* The run() function now understands stdin=subprocess.DEVNULL to close the subprocess stdin,
20+
rather than to connect through the existing stdin, which is the current default
1921

2022
2.3.1 (2021-10-25)
2123
------------------

src/procrunner/__init__.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
import warnings
1414
from multiprocessing import Pipe
1515
from threading import Thread
16-
from typing import Any, Callable, Optional
16+
from typing import Any, Callable, Optional, Union
1717

1818
#
1919
# run() - A function to synchronously run an external process, supporting
@@ -304,7 +304,7 @@ def run(
304304
command,
305305
*,
306306
timeout: Optional[float] = None,
307-
stdin: Optional[bytes] = None,
307+
stdin: Optional[Union[bytes, int]] = None,
308308
print_stdout: bool = True,
309309
print_stderr: bool = True,
310310
callback_stdout: Optional[Callable] = None,
@@ -323,7 +323,8 @@ def run(
323323
324324
:param array command: Command line to be run, specified as array.
325325
:param timeout: Terminate program execution after this many seconds.
326-
:param stdin: Optional bytestring that is passed to command stdin.
326+
:param stdin: Optional bytestring that is passed to command stdin,
327+
or subprocess.DEVNULL to disable stdin.
327328
:param boolean print_stdout: Pass stdout through to sys.stdout.
328329
:param boolean print_stderr: Pass stderr through to sys.stderr.
329330
:param callback_stdout: Optional function which is called for each
@@ -348,6 +349,12 @@ def run(
348349

349350
if stdin is None:
350351
stdin_pipe = None
352+
elif isinstance(stdin, int):
353+
assert (
354+
stdin == subprocess.DEVNULL
355+
), "stdin argument only allows subprocess.DEVNULL as numeric argument"
356+
stdin_pipe = subprocess.DEVNULL
357+
stdin = None
351358
else:
352359
assert sys.platform != "win32", "stdin argument not supported on Windows"
353360
stdin_pipe = subprocess.PIPE

tests/test_procrunner_system.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,19 @@ def test_simple_command_invocation():
2323
assert result.stderr == b""
2424

2525

26+
def test_simple_command_invocation_with_closed_stdin():
27+
if os.name == "nt":
28+
command = ["cmd.exe", "/c", "echo", "hello"]
29+
else:
30+
command = ["echo", "hello"]
31+
32+
result = procrunner.run(command, stdin=subprocess.DEVNULL)
33+
34+
assert result.returncode == 0
35+
assert result.stdout == b"hello" + os.linesep.encode("utf-8")
36+
assert result.stderr == b""
37+
38+
2639
def test_decode_invalid_utf8_input(capsys):
2740
test_string = b"test\xa0string\n"
2841
if os.name == "nt":

0 commit comments

Comments
 (0)