Add typing to OutputWrapper and fix string mismatch issues.

Review Request #13035 — Created May 10, 2023 and submitted — Latest diff uploaded




OutputWrapper's design led to easy-to-introduce string mismatch
issues, which could cause crashes or data corruption. This is because it
was meant to be used with either a Unicode or byte string buffer, and
calls to .write() failed to handle all cases of mismatches.

This change fixes this all through a combination of type hints and
smarter string conversions.

OutputWrapper is now a generic, available in OutputWrapper[bytes] or
OutputWrapper[str] form. The form used dictates the type of upstream
buffer this can work with, and the types of string values allowd when

To protect against bad calls, we now use force_bytes() or
force_unicode(), depending on the type. This happens automatically for
all writes. This also allows us to simplify all the internal logic.

Since OutputWrapper.write() defaults to using a newline as the end
value, and we can't hard-code a string type here, we now use a wrapping
object that symbolizes a newline. The prior hard-coded default is likely
why the write() logic was the way it was before.

Unit tests have been added for the class testing both bytes and str

Unit tests pass.

Tested command output from a few different commands, utilizing both
Unicode and byte streams. Didn't encounter any issues.