From 5924cfb338c10e7271e275c2ea8f1198cbaa07a9 Mon Sep 17 00:00:00 2001 From: Bjorn Neergaard Date: Tue, 6 Sep 2022 13:37:06 -0600 Subject: [PATCH] fix: write to stderr in utils.env This is a quick fix to avoid polluting stdout unexpectedly when Poetry's environment management comes into play. It's apparent from how much the complexity of this file has grown that this needs to be refactored moderately, as well as each major class deserving its own source file. Future work should also include a rethink of how IO objects are passed around the codebase, how we reason about verbosity at a function level, and how code is re-used -- one command may wish to output to stdout, but if that code is reused by another command, the calculus of what is command output and what is informative (or even needs to be hidden/shown based on verbosity level) changes. Work on output would likely have to be fairly comprehensive and invasive, but things have grown complex enough that a top-down design pass is likely the best route. Regardless, this is a simple change today, and low risk. Resolves #6427. --- src/poetry/utils/env.py | 28 ++++++++++++++------------ tests/console/commands/env/test_use.py | 22 +++++++++----------- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/src/poetry/utils/env.py b/src/poetry/utils/env.py index afc1e7581a1..6bf07e92c2a 100644 --- a/src/poetry/utils/env.py +++ b/src/poetry/utils/env.py @@ -536,15 +536,15 @@ def _detect_active_python(self, io: IO) -> str | None: executable = None try: - io.write_line( + io.write_error_line( "Trying to detect current active python executable as specified in the" " config.", verbosity=Verbosity.VERBOSE, ) executable = self._full_python_path("python") - io.write_line(f"Found: {executable}", verbosity=Verbosity.VERBOSE) + io.write_error_line(f"Found: {executable}", verbosity=Verbosity.VERBOSE) except CalledProcessError: - io.write_line( + io.write_error_line( "Unable to detect the current active python executable. Falling back to" " default.", verbosity=Verbosity.VERBOSE, @@ -651,7 +651,9 @@ def deactivate(self, io: IO) -> None: env = envs.get(name) if env is not None: venv = venv_path / f"{name}-py{env['minor']}" - io.write_line(f"Deactivating virtualenv: {venv}") + io.write_error_line( + f"Deactivating virtualenv: {venv}" + ) del envs[name] envs_file.write(envs) @@ -911,7 +913,7 @@ def create_venv( python = "python" + python_to_try if io.is_debug(): - io.write_line(f"Trying {python}") + io.write_error_line(f"Trying {python}") try: python_patch = decode( @@ -930,7 +932,7 @@ def create_venv( continue if supported_python.allows(Version.parse(python_patch)): - io.write_line(f"Using {python} ({python_patch})") + io.write_error_line(f"Using {python} ({python_patch})") executable = python python_minor = ".".join(python_patch.split(".")[:2]) break @@ -955,7 +957,7 @@ def create_venv( if not venv.exists(): if create_venv is False: - io.write_line( + io.write_error_line( "" "Skipping virtualenv creation, " "as specified in config file." @@ -964,7 +966,7 @@ def create_venv( return self.get_system_env() - io.write_line( + io.write_error_line( f"Creating virtualenv {name} in" f" {venv_path if not WINDOWS else get_real_windows_path(venv_path)!s}" ) @@ -976,11 +978,11 @@ def create_venv( f"The virtual environment found in {env.path} seems to" " be broken." ) - io.write_line(f"Recreating virtualenv {name} in {venv!s}") + io.write_error_line(f"Recreating virtualenv {name} in {venv!s}") self.remove_venv(venv) create_venv = True elif io.is_very_verbose(): - io.write_line(f"Virtualenv {name} already exists.") + io.write_error_line(f"Virtualenv {name} already exists.") if create_venv: self.build_venv( @@ -1917,14 +1919,14 @@ def build_environment( if io: if not overwrite: - io.write_line("") + io.write_error_line("") requires = [ f"{requirement}" for requirement in poetry.pyproject.build_system.requires ] - io.overwrite( + io.overwrite_error( "Preparing build environment with build-system requirements" f" {', '.join(requires)}" ) @@ -1938,7 +1940,7 @@ def build_environment( if overwrite: assert io is not None - io.write_line("") + io.write_error_line("") yield venv else: diff --git a/tests/console/commands/env/test_use.py b/tests/console/commands/env/test_use.py index e328773616f..3f4095a18f9 100644 --- a/tests/console/commands/env/test_use.py +++ b/tests/console/commands/env/test_use.py @@ -86,12 +86,11 @@ def test_activate_activates_non_existing_virtualenv_no_envs_file( assert envs[venv_name]["minor"] == "3.7" assert envs[venv_name]["patch"] == "3.7.1" - expected = f"""\ -Creating virtualenv {venv_py37.name} in {venv_py37.parent} -Using virtualenv: {venv_py37} -""" - - assert tester.io.fetch_output() == expected + assert ( + tester.io.fetch_error() + == f"Creating virtualenv {venv_py37.name} in {venv_py37.parent}\n" + ) + assert tester.io.fetch_output() == f"Using virtualenv: {venv_py37}\n" def test_get_prefers_explicitly_activated_virtualenvs_over_env_var( @@ -149,9 +148,8 @@ def test_get_prefers_explicitly_activated_non_existing_virtualenvs_over_env_var( tester.execute(python_minor) - expected = f"""\ -Creating virtualenv {venv_dir.name} in {venv_dir.parent} -Using virtualenv: {venv_dir} -""" - - assert tester.io.fetch_output() == expected + assert ( + tester.io.fetch_error() + == f"Creating virtualenv {venv_dir.name} in {venv_dir.parent}\n" + ) + assert tester.io.fetch_output() == f"Using virtualenv: {venv_dir}\n"