I am trying to pipe Node.js output to preatty-pino
node .\dist\GameNode.js | pino-pretty
running this in the CMD I get my formated output but running it inside a powershell I get nothing.
I read that Powershell is using objects when piping, so I tried
node .\dist\GameNode.js | Out-String -Stream | pino-pretty
But this also does not work.
Why does it work inside CMD but not inside Powershell ?
Thanks :)
Note: The specific pino-pretty problem described in the question is not resolved by the information below. Lukas (the OP) has filed a bug report here.
It's surprising that you get nothing, but the fundamental difference is:
cmd.exe's pipeline conducts raw data, i.e. byte streams (which a given program receiving the data may or may not itself interpret as text).
PowerShell's pipeline, when talking to external programs, conducts only text (strings), which has two implications:
On piping data to an external program, text must be encoded, which happens based on the character encoding stored in preference variable $OutputEncoding.
On receiving data from an external program, data must be decoded, which happens based on the character encoding stored in [Console]::OutputEncoding, which by default is the system's OEM code page, as reflected in chcp.
This decoding happens invariably, irrespective of whether the data is then further processed in PowerShell or passed on to another external program.
This sometimes problematic lack of ability to send raw data through PowerShell's pipeline even between two external programs is discussed in this answer.
The only exception is if external-program output is neither captured, sent on through the pipeline, nor redirected to a file: in that case, the data prints straight to the console (terminal), but only in a local console (when using PowerShell remoting to interact with a remote machine, decoding is again invariably involved).
This direct-to-display printing can sometimes hide encoding problems, because some programs, notably python, use full Unicode support situationally in that case; that is, the output may print fine, but when you try to process it further, encoding problems can surface.
A simple way to force decoding is to enclose the call in (...); e.g.,
python -c "print('eé')" prints fine, but
(python -c "print('eé'))" surfaces an encoding problem; see the bottom section for more information
While console applications traditionally use the active OEM code page for character encoding and decoding, Node.js always uses UTF-8.
Therefore, in order for PowerShell to communicate properly with Node.js programs, you must (temporarily) set the following first:
$OutputEncoding = [Console]::OutputEncoding = [System.Text.UTF8Encoding]::new()
If you want to fundamentally switch to UTF-8, either system-wide (which has far-reaching consequences) or only for PowerShell console windows, see this answer.
As an aside: an intermediate Out-String -Stream pipeline segment is never needed for relaying an external program's output - it is effectively (a costly) no-op, because streaming stdout output line by line is what PowerShell does by default. In other words: it is not surprising that it made no difference in your case.
Optional reading: Convenience function Invoke-WithEncoding and diagnostic function Debug-NativeInOutput for ad-hoc encoding needs / diagnosis:
If switching all PowerShell consoles to UTF-8 isn't an option and/or you need to deal with "rogue" programs that use a specific encoding other than UTF-8 or the active OEM code page, you can install:
Function Invoke-WithEncoding, which temporarily switches to a given encoding when invoking an external program, directly from this Gist as follows (I can assure you that doing so is safe, but you should always check):
# Download and define advanced function Invoke-WithEncoding in the current session.
irm https://gist.github.com/mklement0/ef57aea441ea8bd43387a7d7edfc6c19/raw/Invoke-WithEncoding.ps1 | iex
Function Debug-NativeInOutput, which helps diagnose encoding problems with external programs, directly from this Gist as follows (again, you should check first):
# Download and define advanced function Debug-NativeInOutput in the current session.
irm https://gist.github.com/mklement0/eac1f18fbe0fc2798b214229b747e5dd/raw/Debug-NativeInOutput.ps1 | iex
Below are example commands that use a python command to print an accented character.
Like Node.js, Python's behavior is nonstandard, although it doesn't use UTF-8, but the system's active ANSI(!) code page (rather than the expected OEM code page).
That is, even if you switch your PowerShell consoles UTF-8, communication with Python scripts won't work properly by default, unless extra effort is made, which Invoke-WithEncoding can encapsulate for you:
Note: I'm using Python as an example here, to illustrate how the functions work. It is possible to make Python use UTF-8, namely by either setting environment variable PYTHONUTF8 to 1 or - in v3.7+ - by passing parameter -X utf8 (case-exactly).
Invoke-WithEncoding example:
# Outputs *already-decoded* output, so if the output *prints* fine,
# then *decoding* worked fine too.
PS> Invoke-WithEncoding { python -c "print('eé')" } -Encoding Ansi -WindowsOnly
eé
Note that Invoke-WithEncoding ensures that actual decoding to a .NET string happens before it outputs, so that encoding problems aren't accidentally masked by the direct-to-display output seemingly being correct on Windows (see below for more).
-WindowsOnly is for cross-platform compatibility and ensures that the encoding is only applied on Windows in this case (on Unix, Python uses UTF-8).
Debug-NativeInOutput example:
With the PowerShell console at its default, using the system's OEM code page, you'll see the following output with the same Python command, calling from PowerShell (Core) 7.1:
PS> Debug-NativeInOutput { python -c "print('eé')" }
Note the DecodedOutput property, showing the mis-decoded result based on interpreting Python's output as OEM- rather than as ANSI-encoded: 'eΘ'. (The Input* properties are blank, because the command did not involve piping data to the Python script.)
By contrast, with direct-to-display printing the output prints fine (because Python then - and only then - uses Unicode), which hides the problem, but as soon you want to programmatically process the output - capture in a variable, send to another command in the pipeline, redirect to a file - the encoding problem will surface.
Like Invoke-WithEncoding, Debug-NativeInOutput supports an -Encoding parameter, so if you pass -Encoding Ansi to the call above, you'll see that Python's output is decoded properly.
The output reflects the fact that, in PowerShell (Core), $OutputEncoding defaults to UTF-8, whereas in Windows PowerShell it defaults to ASCII(!). This mismatch with the actual encoding in effect in the console window is problematic, and this comment on GitHub issue #14945 proposes a way to resolve this (for PowerShell (Core) only) in the future.
Related
I've been trying to work with an API that only accepts raw text or base64 encoded values in a JSON object. The content I'm POSTing is data from an XML file. So I used Powershell's Get-Content cmdlet (without -Raw) to retrieve the data from the .xml and then base64 encode it and sent it to the API. The API then decodes it, but the XML formatting was lost.
I found a SO post about using the -Raw switch on Get-Content, but it seems like the documentation for this switch is vague. When I used the -Raw switch, encoded it and sent it back to the API, the formatting was good.
briantist's helpful comment on the question sums up the answer succinctly (in his words; lightly edited, emphasis added):
Get-Content [by default] reads a file line by line and returns an array of the lines. Using -Raw reads the entire contents of the file as a single string.
The name -Raw is tad unfortunate, because it mistakenly suggests reading raw bytes, whereas -Raw still detects encodings and ultimately reads everything into a .NET [string] type.
(By contrast, you need either -Encoding Byte (Windows PowerShell) or -AsByteStream (PowerShell Core) to read a file as a byte array.)
Given -Raw's actual purpose, perhaps something like -Whole would have been a better name, but that ship has sailed (though adding an alias name for a parameter is still an option).
Let's take a look at why this information may currently be difficult to discover [Update: It no longer is]:
[Update: This section is now OBSOLETE, except the link to the PowerShell documentation GitHub repository, which welcomes contributions, bug reports, suggestions]
A Tale of PowerShell Documentation Woes
The central conflict of this tale is the tension between the solid foundation of PowerShell's potentially great help system and its shoddy current content.
As is often the case, third parties come to the rescue, as shown in gms0ulman's helpful answer.
As briantist also points out, however, PowerShell's documentation is now open-source and welcomes contributions; he states:
"I will direct your attention to the Edit link
[for the Get-Content help topic on GitHub] [...] so you can actually fix it up and submit something better
(including examples). I have done it before; they do accept pull
requests for it."
The caveat is that while future PowerShell Core versions will benefit from improvements, it's not clear whether improvements will make their way back into Windows PowerShell.
Let's ask PowerShell's built-in help system, accessible via the standard Get-Help cmdlet (the content for which may not be preinstalled; install when prompted, or run Update-Help from an elevated session):
Get-Help Get-Content -Parameter Raw
Note how you can conveniently ask for help on a specific parameter (-Parameter Raw).
On Windows PowerShell v5.1, this yields:
-Raw
Ignores newline characters and returns the entire contents of a file in one string.
By default, the contents of a file is returned as a array of strings that is delimited
by the newline character.
Raw is a dynamic parameter that the FileSystem provider adds to the Get-Content cmdlet.
This parameter works only in file system drives.
This parameter is introduced in Windows PowerShell 3.0.
Required? false
Position? named
Default value
Accept pipeline input? false
Accept wildcard characters? false
That is indeed what we were looking for and quite helpful (leaving the awkward phrasing "delimited by the newline character" aside and that on Windows a newline is a character sequence).
On Powershell Core v6.0.2, this yields:
-Raw
Required? false
Position? Named
Accept pipeline input? false
Parameter set name (All)
Aliases None
Dynamic? true
While the meta-data is more detailed - including a hint that the parameter is dynamic (see below) - it is crucially missing a description of the parameter.
Some provider-cmdlet parameters are dynamic, in that they are specific to a given provider, so there is a mechanism to specify the target provider when asking for help, by passing a provider-specific example path to the -Path parameter.
In the case at hand, let's therefore try (PowerShell Core on Windows):
Get-Help Get-Content -Parameter Raw -Path C:\
Sadly, the result is the same unhelpful response as before.
Note that, as long as you're invoking the command from a filesystem location, explicit use of -Path should not be necessary, because the provider underlying the current location is implicitly targeted.
Now let's take a look at the online versions of PowerShell's help topics:
As it turns out, a given provider cmdlet can have multiple documentation pages:
A generic one that applies to all providers.
Provider-specific pages that document provider-exclusive behavior and parameters, such as -Raw for the filesystem provider.
Sadly, the generic topics make no mention of the existence of the provider-specific ones, making them hard to discover.
Googling Get-Content takes you to https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.management/get-content, the generic topic, which contains the following misleading statement: This parameter is not supported by any providers that are installed with Windows PowerShell.
This is not only unhelpful, but actively misleading, because the PowerShell file-system provider clearly is installed with PowerShell and it does support -Raw.
[Drive] providers are PowerShell's generalization of the filesystem drive metaphor to support targeting other [typically hierarchical] storage systems with a unified set of cmdlets. For instance, Windows PowerShell also ships with the registry drive provider, which allows managing the registry as if it were a drive.
The -Online switch for Get-Help conveniently allows opening the online version of the requested topic in the browser; so let's try that (Get-Help Get-Content -Online):
Windows PowerShell v5.1: Takes you a 404 page(!) related to v4.
PowerShell Core v6.0.1: Takes you to the same generic topic that googling does.
There's a sliver of hope, however: The aforementioned 404 page offers a link to the filesystem-provider-specific topic:
Get-Content for FileSystem
It is there that we finally discover the online version of the truly relevant, provider-specific information, which is the same that Get-Help Get-Content -Parameter Raw provides locally, but - as stated - only in Windows PowerShell.
As per Kory Gill's comment and your own, the built-in Get-Help and MSDN documentation should be your first port of call. But you've already RTFM!
When that fails, ss64 is great reference for Powershell documentation and additional examples.
Get-Content page here. It has this to say about -Raw:
Return multiple lines as a single string (PowerShell 3.0)
In PowerShell 2.0 use the static method: [System.IO.File]::ReadAllText(string path)
I've got a program that uses a few hash tables to resolve information. I'm getting some weird issues with foreign characters. Below is an accurate representation:
$Props =
#{
P1 = 'Norte Americano e Inglês'
}
$Expressions =
#{
E1 = { $Props['P1'] }
}
& $Expressions['E1']
If I paste this into PowerShell 5.1 console or run selection in VSCode I get:
Norte Americano e Inglês
As expected. But if I run the code in VSCose (hit F5). I get:
Norte Americano e Inglês
By debugging, setting a breakpoint right after the hash literal, I can tell the incorrect version is actually in the hash. So this isn't somehow a side effect of the call operator or the use of script blocks.
I attempted to set the output encoding like:
$OutputEncoding = [console]::InputEncoding = [console]::OutputEncoding = New-Object System.Text.UTF8Encoding
But this doesn't seem to change the pattern. Frankly, I'm surprised the console is handling Unicode so well in the first place. However, I can't understand the inconsistency. Ultimately this data is written to an AD attribute which again works fine if I execute the steps manually, but gets mangled if I actually run the script, even when the output encoding is set as previously mentioned.
I did look through this Q&A, but I don't seem to be having a console display issue, although that may be a result of the true type fonts. Perhaps they're masking the problem.
Interestingly it does seem to work correctly in VSCode if I switch it to PowerShell 7.1. However, because of integration with the AD cmdlets, which do not function well through implicit session compatibility, it's not possible to use PowerShell Core for this project.
The Dev environment is Windows 2012R2 up-to-date. I'm not sure there's an ability to change the system code page as is mentioned for Win 10 (1909).
This is pretty ugly but what happens if you try this at the end of your code:
$enc = [System.Text.Encoding]::UTF8
$enc.GetString($enc.GetBytes($(& $Expressions['E1'])))
Also, this might help you Encode a string in UTF-8
I've been trying to work with an API that only accepts raw text or base64 encoded values in a JSON object. The content I'm POSTing is data from an XML file. So I used Powershell's Get-Content cmdlet (without -Raw) to retrieve the data from the .xml and then base64 encode it and sent it to the API. The API then decodes it, but the XML formatting was lost.
I found a SO post about using the -Raw switch on Get-Content, but it seems like the documentation for this switch is vague. When I used the -Raw switch, encoded it and sent it back to the API, the formatting was good.
briantist's helpful comment on the question sums up the answer succinctly (in his words; lightly edited, emphasis added):
Get-Content [by default] reads a file line by line and returns an array of the lines. Using -Raw reads the entire contents of the file as a single string.
The name -Raw is tad unfortunate, because it mistakenly suggests reading raw bytes, whereas -Raw still detects encodings and ultimately reads everything into a .NET [string] type.
(By contrast, you need either -Encoding Byte (Windows PowerShell) or -AsByteStream (PowerShell Core) to read a file as a byte array.)
Given -Raw's actual purpose, perhaps something like -Whole would have been a better name, but that ship has sailed (though adding an alias name for a parameter is still an option).
Let's take a look at why this information may currently be difficult to discover [Update: It no longer is]:
[Update: This section is now OBSOLETE, except the link to the PowerShell documentation GitHub repository, which welcomes contributions, bug reports, suggestions]
A Tale of PowerShell Documentation Woes
The central conflict of this tale is the tension between the solid foundation of PowerShell's potentially great help system and its shoddy current content.
As is often the case, third parties come to the rescue, as shown in gms0ulman's helpful answer.
As briantist also points out, however, PowerShell's documentation is now open-source and welcomes contributions; he states:
"I will direct your attention to the Edit link
[for the Get-Content help topic on GitHub] [...] so you can actually fix it up and submit something better
(including examples). I have done it before; they do accept pull
requests for it."
The caveat is that while future PowerShell Core versions will benefit from improvements, it's not clear whether improvements will make their way back into Windows PowerShell.
Let's ask PowerShell's built-in help system, accessible via the standard Get-Help cmdlet (the content for which may not be preinstalled; install when prompted, or run Update-Help from an elevated session):
Get-Help Get-Content -Parameter Raw
Note how you can conveniently ask for help on a specific parameter (-Parameter Raw).
On Windows PowerShell v5.1, this yields:
-Raw
Ignores newline characters and returns the entire contents of a file in one string.
By default, the contents of a file is returned as a array of strings that is delimited
by the newline character.
Raw is a dynamic parameter that the FileSystem provider adds to the Get-Content cmdlet.
This parameter works only in file system drives.
This parameter is introduced in Windows PowerShell 3.0.
Required? false
Position? named
Default value
Accept pipeline input? false
Accept wildcard characters? false
That is indeed what we were looking for and quite helpful (leaving the awkward phrasing "delimited by the newline character" aside and that on Windows a newline is a character sequence).
On Powershell Core v6.0.2, this yields:
-Raw
Required? false
Position? Named
Accept pipeline input? false
Parameter set name (All)
Aliases None
Dynamic? true
While the meta-data is more detailed - including a hint that the parameter is dynamic (see below) - it is crucially missing a description of the parameter.
Some provider-cmdlet parameters are dynamic, in that they are specific to a given provider, so there is a mechanism to specify the target provider when asking for help, by passing a provider-specific example path to the -Path parameter.
In the case at hand, let's therefore try (PowerShell Core on Windows):
Get-Help Get-Content -Parameter Raw -Path C:\
Sadly, the result is the same unhelpful response as before.
Note that, as long as you're invoking the command from a filesystem location, explicit use of -Path should not be necessary, because the provider underlying the current location is implicitly targeted.
Now let's take a look at the online versions of PowerShell's help topics:
As it turns out, a given provider cmdlet can have multiple documentation pages:
A generic one that applies to all providers.
Provider-specific pages that document provider-exclusive behavior and parameters, such as -Raw for the filesystem provider.
Sadly, the generic topics make no mention of the existence of the provider-specific ones, making them hard to discover.
Googling Get-Content takes you to https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.management/get-content, the generic topic, which contains the following misleading statement: This parameter is not supported by any providers that are installed with Windows PowerShell.
This is not only unhelpful, but actively misleading, because the PowerShell file-system provider clearly is installed with PowerShell and it does support -Raw.
[Drive] providers are PowerShell's generalization of the filesystem drive metaphor to support targeting other [typically hierarchical] storage systems with a unified set of cmdlets. For instance, Windows PowerShell also ships with the registry drive provider, which allows managing the registry as if it were a drive.
The -Online switch for Get-Help conveniently allows opening the online version of the requested topic in the browser; so let's try that (Get-Help Get-Content -Online):
Windows PowerShell v5.1: Takes you a 404 page(!) related to v4.
PowerShell Core v6.0.1: Takes you to the same generic topic that googling does.
There's a sliver of hope, however: The aforementioned 404 page offers a link to the filesystem-provider-specific topic:
Get-Content for FileSystem
It is there that we finally discover the online version of the truly relevant, provider-specific information, which is the same that Get-Help Get-Content -Parameter Raw provides locally, but - as stated - only in Windows PowerShell.
As per Kory Gill's comment and your own, the built-in Get-Help and MSDN documentation should be your first port of call. But you've already RTFM!
When that fails, ss64 is great reference for Powershell documentation and additional examples.
Get-Content page here. It has this to say about -Raw:
Return multiple lines as a single string (PowerShell 3.0)
In PowerShell 2.0 use the static method: [System.IO.File]::ReadAllText(string path)
According to the MSDN for Strongly Encouraged Development Guidelines:
Cmdlets should not use the Console API.
Why is this?
If I write [Console]::Write("test"), it works just as well as
Write-Host "test"
EDIT:
It's well known that Write-Host should be avoided. When MSDN says to not use the Console API, is it safe to assume that they are implying that we should not use Write-Host either since that uses the Console API behind the scenes?
The main reason you shouldn't use console-related functionality is that not all PowerShell host environments are consoles.
While the typical use case is to run PowerShell in a console, PowerShell does not need a console and can cooperate with different kinds of host environments.
Thus, for your code to remain portable, it shouldn't assume the existence of a console.
It is safe, however, to assume the existence of (the abstraction called) host, which PowerShell exposes via the automatic $HOST variable.
The capabilities of hosts vary, however, which has historically created problems even when not using the console API directly, but its PowerShell abstraction, Write-Host - see below.
PowerShell provides a hosting API,
with which the PowerShell runtime can be embedded inside other applications. These applications can then use PowerShell functionality to implement certain operations, including those exposed via the graphical interface.
https://en.wikipedia.org/wiki/PowerShell
The regular PowerShell console using the Console Window Host (conhost.exe) on Windows is therefore just one implementation of a PowerShell host - the PowerShell ISE is another example, as is the Microsoft Exchange Server management GUI (2007+).
As for Write-Host:
Up to PSv4, as the name suggests, it used to write to the host - which may or may not be a console - so Write-Host could actually fail on hosts that don't support user interaction; see this question.
Starting with PSv5, Write-Host is safe to use, because it now writes to the newly introduced, host-independent information stream (number 6) - see Get-Help about_Redirection and the next section.
Note that Write-Host still does and always has generated output outside of the normal PowerShell output stream - its output is meant to be "commentary" (feedback to the user) rather than data.
While Write-Host is safe to use in PSv5+, it exist for backward compatibility, so instead consider using
Write-Information -InformationAction Continue or using Write-Information with preference variable $InformationPreference set to Continue, because:
"Write-Host" is now a bit of a misnomer, given that it doesn't actually directly write to the host anymore.
Write-Host, in the interest of backward compatibility, doesn't integrate with the $InformationPreference preference variable - see below.
Write-Host still offers console-inspired formatting parameters (-ForegroundColor, -BackgroundColor), which not all hosts (ultimately) support.
Write-Host vs. Write-Information:
Tip of the hat to PetSerAl for his help with the following.
Write-Information, introduced in PSv5, is the cmdlet that fully integrates with the new, host-independent information stream (number 6).
Notably, you can now redirect and thus capture Write-Information / Write-Host output by using 6>, something that wasn't possible with Write-Host in PSv4-.
Also note that this redirection works even with $InformationPreference's default value, SilentlyContinue, which only governs the display, not the output aspect (only using common parameter -InformationAction Ignore truly suppresses writing to the stream).
In line with how PowerShell handles errors and warnings, the display behavior of Write-Information is controllable via the new $InformationPreference preference variable / the new common -InformationAction cmdlet parameter.
Write-Information's default behavior is to be silent - $InformationPreference defaults to SilentlyContinue.
Note that Write-Information has no direct formatting parameters[1] and instead offers keyword tagging with the -Tags parameter[2]
.
By contrast, for backward compatibility, Write-Host effectively behaves like
Write-Information -InformationAction Continue, i.e., it outputs by default, and the only way to silence it is to use Write-Host -InformationAction Ignore[3]
- it does not respect an $InformationPreference value of SilentlyContinue (it does, however, respect the other values, such as Inquire).
[1] PetSerAl points out that you can pass formatting information to Write-Information, but only in an obscure fashion that isn't even documented as of PSv5.1; e.g.:
Write-Information -MessageData ([System.Management.Automation.HostInformationMessage] #{Message='Message'; ForegroundColor='Red'}) -InformationAction Continue
[2] Note how parameter name "Tags" actually violates one of the strongly encouraged cmdlet development guidelines: it should be "Tag" (singular).
[3] PetSerAl explains that this behavior stems from Write-Host passing the PSHOST tag to Cmdlet.WriteInformation behind the scenes.
[Console]::Write or Write-Host are basically the same. They both write a message to the console which can be seen on the screen.
The basic reason why this is discouraged is that it breaks the workflow. The output of a Write-Host cmdlet can't be piped or used further. Now if the script runs on a machine without graphical output or similar constraints the command is lost.
According to this and this thread, you should therefore rather use Write-Output, which sends the output message to the pipeline where it can be further used. Further, you can use exceptions if your message is meant to signal an error.
After I learned about reading unicode files in Python 3.0 web script, now it's time for me to learn using print() with unicode.
I searched for writing unicode, for example this question explains that you can't write unicode characters to non-unicode console. However, in my case, the output is given to Apache and I am sure that it is capable of handling unicode text. For some reason, however, the stdout of my web script is in ascii.
Obviously, if I was opening a file to write myself, I would do something like
open(filename, 'w', encoding='utf8')
but since I'm given an open stream, I resorted to using
sys.stdout.buffer.write(mytext.encode('utf-8'))
and everything seems to work. Does this violate some rule of good behavior or has any unintended consequences?
I don't think you're breaking any rule, but
sys.stdout = codecs.EncodedFile(sys.stdout, 'utf8')
looks like it might be handier / less clunky.
Edit: per comments, this isn't quite right -- #Miles gave the right variant (thanks!):
sys.stdout = codecs.getwriter('utf8')(sys.stdout.buffer)
Edit: if you can arrange for environment variable PYTHONIOENCODING to be set to utf8 when Apache starts your script, that would be even better, making sys.stdout be set to utf8 automatically; but if that's unfeasible or impractical the codecs solution stands.
This is an old answer but I'll add my version here since I first ventured here before finding my solution.
One of the issues with codecs.getwriter is if you are running a script of sorts, the output will be buffered (whereas normally python stdout prints after every line).
sys.stdout in the console is a IOTextWrapper, so my solution uses that. This also allows you to set line_buffering=True or False.
For example, to set stdout to, instead of erroring, backslash encode all output:
sys.stdout = io.TextIOWrapper(sys.stdout.detach(), encoding=sys.stdout.encoding,
errors="backslashreplace", line_buffering=True)
To force a specific encoding (in this case utf8):
sys.stdout = io.TextIOWrapper(sys.stdout.detach(), encoding="utf8",
line_buffering=True)
A note, calling sys.stdout.detach() will close the underlying buffer. Some modules use sys.__stdout__, which is just an alias for sys.stdout, so you may want to set that as well
sys.stdout = sys.__stdout__ = io.TextIOWrapper(sys.stdout.detach(), encoding=sys.stdout.encoding, errors="backslashreplace", line_buffering=True)
sys.stderr = sys.__stderr__ = io.TextIOWrapper(sys.stderr.detach(), encoding=sys.stdout.encoding, errors="backslashreplace", line_buffering=True)