CLI: fix line buffering with Python 3 (#528) #537
Merged
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
When the code was ported to Python 3, we switched to sys.stdout.buffer and sys.stderr.buffer that use BufferedWriter (bytes) for printing outputs. However, this method doesn't work great for line buffering, which is used a lot by clush and clubak.
Switch back to sys.stdout and sys.stderr, as TextIOWrapper objects, which take strings and benefit from automatic line buffering. If stdout (or stderr) is not a tty, we reconfigure it (only once) to force line buffering. Indeed, clush and clubak might be piped to other tools (like pv) that expects each line to be flushed.
Key points of this patch:
write() to stdout/stderr now takes a string and the Display class is in charge of performing the needed bytes-to-string decoding
any non-printable character will be decoded to U+FFFD thanks to
errors='replace'
; U+FFFD is the official REPLACEMENT CHARACTER (this is now tested in CLIDisplayTest.py)when the Display object is initialized, we make sure stdout/stderr are configured with line buffering enabled
the print methods from Display like print_line(), print_line_error() and _print_content() still take bytes as argument. Buffers are still mainly handled as bytes internally (by MsgTreeElem).
most CLI tests remain unchanged for now: they capture the output (now as string) and compare against expected bytes, but proper encoding is done by TLib in CLI_main(). In the future, we could convert all tests from using bytes to string to make it easier.
Fixes #528.