From bfc6295f3c3aceaba8eace2f2014a9ee346eca4e Mon Sep 17 00:00:00 2001 From: Frederik Zahle Date: Thu, 23 Mar 2023 05:56:16 +0100 Subject: [PATCH] remove stdout=subprocess.PIPE from env._call, which can cause poetry install to hang (#7699) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Randy Döring <30527984+radoering@users.noreply.github.com> (cherry picked from commit fa5543a639e76d14e7262572ea6b06fe099c0f46) --- src/poetry/utils/env.py | 5 ++--- tests/utils/test_env.py | 26 ++++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/src/poetry/utils/env.py b/src/poetry/utils/env.py index d5755d152c3..aa4d58bf223 100644 --- a/src/poetry/utils/env.py +++ b/src/poetry/utils/env.py @@ -1537,9 +1537,8 @@ def _run(self, cmd: list[str], **kwargs: Any) -> int | str: **kwargs, ).stdout elif call: - return subprocess.call( - cmd, stdout=subprocess.PIPE, stderr=stderr, env=env, **kwargs - ) + assert stderr != subprocess.PIPE + return subprocess.call(cmd, stderr=stderr, env=env, **kwargs) else: output = subprocess.check_output(cmd, stderr=stderr, env=env, **kwargs) except CalledProcessError as e: diff --git a/tests/utils/test_env.py b/tests/utils/test_env.py index eb7b2ec59eb..07823d4fb55 100644 --- a/tests/utils/test_env.py +++ b/tests/utils/test_env.py @@ -5,6 +5,7 @@ import sys from pathlib import Path +from threading import Thread from typing import TYPE_CHECKING from typing import Any @@ -1009,6 +1010,31 @@ def test_check_output_with_called_process_error( assert "some error" in str(error.value) +@pytest.mark.parametrize("out", ["sys.stdout", "sys.stderr"]) +def test_call_does_not_block_on_full_pipe( + tmp_path: Path, tmp_venv: VirtualEnv, out: str +): + """see https://github.com/python-poetry/poetry/issues/7698""" + script = tmp_path / "script.py" + script.write_text( + f"""\ +import sys +for i in range(10000): + print('just print a lot of text to fill the buffer', file={out}) +""" + ) + + def target(result: list[int]) -> None: + result.append(tmp_venv.run("python", str(script), call=True)) + + results = [] + # use a separate thread, so that the test does not block in case of error + thread = Thread(target=target, args=(results,)) + thread.start() + thread.join(1) # must not block + assert results and results[0] == 0 + + def test_run_python_script_called_process_error( tmp_dir: str, tmp_venv: VirtualEnv, mocker: MockerFixture ):