From 39f04ad2c9fdcb5e15bb57f7c5d8ae524a99613a Mon Sep 17 00:00:00 2001 From: "Mollenkopf, Fabian (RDSS-RI)" <163862607+LeMollinger@users.noreply.github.com> Date: Thu, 10 Sep 2026 15:02:15 +0200 Subject: [PATCH 1/2] fix: report stderr as None when it is merged into stdout --- src/py_app_dev/core/subprocess.py | 8 ++++++-- tests/test_subprocess.py | 19 +++++++++++++++++++ 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/src/py_app_dev/core/subprocess.py b/src/py_app_dev/core/subprocess.py index 8e7f551..bb1544f 100644 --- a/src/py_app_dev/core/subprocess.py +++ b/src/py_app_dev/core/subprocess.py @@ -24,6 +24,10 @@ class SubprocessExecutor: """ Execute a command in a subprocess. + stderr is merged into stdout, so the progress lines and the error lines of the command stay in + chronological order. The returned CompletedProcess therefore has stderr set to None ("not + captured", as in the standard library). Read all output from stdout. + Args: ---- capture_output: If True, the output of the command will be captured. @@ -96,11 +100,11 @@ def _finalize_process( pipe.close() def execute(self, handle_errors: bool = True) -> subprocess.CompletedProcess[Any] | None: - """Execute the command and return the CompletedProcess object if handle_errors is False.""" + """Execute the command and return the CompletedProcess object if handle_errors is False (stdout holds the merged output, stderr is always None).""" start_time = time.monotonic() completed_process: subprocess.CompletedProcess[Any] | None = None stdout = "" - stderr = "" + stderr: str | None = None self.logger.info(f"Running command: {self.command_str}") cwd_path = (self.current_working_directory or Path.cwd()).as_posix() process: subprocess.Popen[str] | None = None diff --git a/tests/test_subprocess.py b/tests/test_subprocess.py index 37560d2..4a89d63 100644 --- a/tests/test_subprocess.py +++ b/tests/test_subprocess.py @@ -71,6 +71,25 @@ def test_command_execution_scenarios(command: list[str | Path], exp_stdout: str, assert result.returncode == exp_returncode +@pytest.mark.parametrize( + "capture_output, print_output, exp_stdout", + [ + (True, True, "boom"), + (True, False, "boom"), + (False, True, ""), + ], +) +def test_stderr_is_none_because_it_is_merged_into_stdout(capture_output: bool, print_output: bool, exp_stdout: str) -> None: + result = SubprocessExecutor( + ["python", "-c", "import sys; sys.stderr.write('boom')"], + capture_output=capture_output, + print_output=print_output, + ).execute(handle_errors=False) + assert result is not None + assert result.stdout == exp_stdout + assert result.stderr is None + + @pytest.mark.skipif(platform.system() != "Windows", reason="Junction creation test is Windows-specific") def test_junction_creation(tmp_path: Path) -> None: test_path = tmp_path / "test" From 762a451847ee2a81169de9a4f4845ff2c7d3fdd2 Mon Sep 17 00:00:00 2001 From: "Mollenkopf, Fabian (RDSS-RI)" <163862607+LeMollinger@users.noreply.github.com> Date: Thu, 10 Sep 2026 15:34:28 +0200 Subject: [PATCH 2/2] fix: quote python_version in pypeline.yaml --- pypeline.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pypeline.yaml b/pypeline.yaml index 83df045..3ef38b0 100644 --- a/pypeline.yaml +++ b/pypeline.yaml @@ -9,7 +9,7 @@ pipeline: module: pypeline.steps.create_venv config: package_manager: uv>=0 - python_version: 3.13 + python_version: "3.13" - step: PreCommit run: pre-commit run --all-files - step: PyTest