From 7c3de7669275d51fd0bae5fa1b52b245078cb1ee Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Tue, 30 Aug 2022 01:01:32 +0200 Subject: [PATCH] tools: idf.py: use actual sys.stdout instead of the memoized one This fixes the issue with build output not being colorized on Windows, while the hints messages are colorized. The issue occurred because sys.stdout and sys.stderr get overridden by colorama.init() at runtime, but the default argument output_stream=sys.stdout holds the reference to the"original" sys.stdout. colorama.init() (which, by the way, gets called via a curious chain of imports, via idf_component_tools.manifest and tqdm package) overrides standard streams, on Windows only. The overridden streams contain logic to convert ANSI color codes into Windows Console API calls to colorize the text. Since read_and_write_stream function used the default value of output_stream evaluated at module loading time, it was using the original sys.stdout, not the one overridden by colorama. One extra note is that while this does fix the coloring issue, the solution is a bit fragile, as it relies on one of the following (on Windows): - colorama.init() is called (this can change if idf-component-manager stops importing tqdm) - Sufficiently new version of Windows 10 is used, and ANSI color codes support is enabled in the Registry. --- tools/idf_py_actions/tools.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/idf_py_actions/tools.py b/tools/idf_py_actions/tools.py index 9a8e735aea..8ce496298a 100644 --- a/tools/idf_py_actions/tools.py +++ b/tools/idf_py_actions/tools.py @@ -222,12 +222,12 @@ class RunTool: if p.stderr and p.stdout: # it only to avoid None type in p.std await asyncio.gather( self.read_and_write_stream(p.stderr, stderr_output_file, sys.stderr), - self.read_and_write_stream(p.stdout, stdout_output_file)) + self.read_and_write_stream(p.stdout, stdout_output_file, sys.stdout)) await p.wait() # added for avoiding None returncode return p, stderr_output_file, stdout_output_file async def read_and_write_stream(self, input_stream: asyncio.StreamReader, output_filename: str, - output_stream: TextIO=sys.stdout) -> None: + output_stream: TextIO) -> None: """read the output of the `input_stream` and then write it into `output_filename` and `output_stream`""" def delete_ansi_escape(text: str) -> str: ansi_escape = re.compile(r'\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])')