From 85a0df45244cb90834b6a02a3c142f154dc213d7 Mon Sep 17 00:00:00 2001 From: Hoppy Date: Wed, 17 Dec 2025 16:35:53 +0100 Subject: [PATCH] util/helper: add stderr param to ProcessWrapper.check_output() Allow separation of stderr from the output. For example, stderr can be ignored by redirecting it to subprocess.DEVNULL or prevent capturing by passing None, similar to how subprocess handles it. Signed-off-by: Hoppy [bst: use default similar to subprocess: subprocess.STDOUT means merging stdout and stderr, None means no capturing; raise on unsupported stderr values] Signed-off-by: Bastian Krause --- labgrid/util/helper.py | 11 ++++++++--- tests/test_powerdriver.py | 13 ++++++------- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/labgrid/util/helper.py b/labgrid/util/helper.py index 93b98b050..139615640 100644 --- a/labgrid/util/helper.py +++ b/labgrid/util/helper.py @@ -41,8 +41,14 @@ class ProcessWrapper: loglevel = logging.INFO @step(args=['command'], result=True, tag='process') - def check_output(self, command, *, print_on_silent_log=False, input=None, stdin=None, timeout=None): # pylint: disable=redefined-builtin + def check_output( + self, command, *, print_on_silent_log=False, input=None, stdin=None, stderr=subprocess.STDOUT, timeout=None + ): # pylint: disable=redefined-builtin """Run a command and supply the output to callback functions""" + + if stderr not in (None, subprocess.STDOUT, subprocess.DEVNULL): + raise NotImplementedError(f"{stderr=} not supported") + logger = logging.getLogger("Process") res = [] mfd, sfd = pty.openpty() @@ -59,8 +65,7 @@ def check_output(self, command, *, print_on_silent_log=False, input=None, stdin= elif stdin is not None: kwargs['stdin'] = stdin - process = subprocess.Popen(command, stderr=sfd, - stdout=sfd, bufsize=0, **kwargs) + process = subprocess.Popen(command, stderr=stderr, stdout=sfd, bufsize=0, **kwargs) logger.log(ProcessWrapper.loglevel, "[%d] command: %s", process.pid, " ".join(command)) diff --git a/tests/test_powerdriver.py b/tests/test_powerdriver.py index 8926333c6..d7076d944 100644 --- a/tests/test_powerdriver.py +++ b/tests/test_powerdriver.py @@ -1,3 +1,4 @@ +import subprocess from urllib.parse import urlparse import pytest @@ -81,7 +82,7 @@ def test_on(self, target, mocker): d.on() popen.assert_called_once_with(['set', '-1', 'foo-board'], bufsize=0, - stderr=2, stdout=2) + stderr=subprocess.STDOUT, stdout=2) def test_off(self, target, mocker): pty = mocker.patch('pty.openpty') @@ -107,7 +108,7 @@ def test_off(self, target, mocker): d.off() popen.assert_called_once_with(['set', '-0', 'foo-board'], bufsize=0, - stderr=2, stdout=2) + stderr=subprocess.STDOUT, stdout=2) def test_cycle(self, target, mocker): pty = mocker.patch('pty.openpty') @@ -135,10 +136,8 @@ def test_cycle(self, target, mocker): d.cycle() assert popen.call_args_list == [ - mocker.call(['set', '-0', 'foo-board'], bufsize=0, stderr=2, - stdout=2), - mocker.call(['set', '-1', 'foo-board'], bufsize=0, stderr=2, - stdout=2), + mocker.call(['set', '-0', 'foo-board'], bufsize=0, stderr=subprocess.STDOUT, stdout=2), + mocker.call(['set', '-1', 'foo-board'], bufsize=0, stderr=subprocess.STDOUT, stdout=2), ] m_sleep.assert_called_once_with(2.0) @@ -171,7 +170,7 @@ def test_cycle_explicit(self, target, mocker): d.cycle() popen.assert_called_once_with(['set', '-c', 'foo-board'], bufsize=0, - stderr=2, stdout=2) + stderr=subprocess.STDOUT, stdout=2) m_sleep.assert_not_called() class TestNetworkPowerDriver: