add 'output.stdout', '.stdin', and '.stderr' options
(#1621, #2152, #2529) Allow setting custom input/output encodings and options without having to rely on Python's defaults.
This commit is contained in:
@@ -3808,6 +3808,42 @@ Description
|
|||||||
* ``{3}`` is percent of bytes downloaded to total bytes
|
* ``{3}`` is percent of bytes downloaded to total bytes
|
||||||
|
|
||||||
|
|
||||||
|
output.stdout & .stdin & .stderr
|
||||||
|
--------------------------------
|
||||||
|
Type
|
||||||
|
* ``string``
|
||||||
|
* ``object``
|
||||||
|
Example
|
||||||
|
.. code:: json
|
||||||
|
|
||||||
|
"utf-8"
|
||||||
|
|
||||||
|
.. code:: json
|
||||||
|
|
||||||
|
{
|
||||||
|
"encoding": "utf-8",
|
||||||
|
"errors": "replace",
|
||||||
|
"line_buffering": true
|
||||||
|
}
|
||||||
|
|
||||||
|
Description
|
||||||
|
`Reconfigure <https://docs.python.org/3/library/io.html#io.TextIOWrapper.reconfigure>`__
|
||||||
|
a `standard stream <https://docs.python.org/3/library/sys.html#sys.stdin>`__.
|
||||||
|
|
||||||
|
Possible options are
|
||||||
|
|
||||||
|
* ``encoding``
|
||||||
|
* ``errors``
|
||||||
|
* ``newline``
|
||||||
|
* ``line_buffering``
|
||||||
|
* ``write_through``
|
||||||
|
|
||||||
|
When this option is specified as a simple ``string``,
|
||||||
|
it is interpreted as ``{"encoding": "<string-value>", "errors": "replace"}``
|
||||||
|
|
||||||
|
Note: ``errors`` always defaults to ``"replace"``
|
||||||
|
|
||||||
|
|
||||||
output.shorten
|
output.shorten
|
||||||
--------------
|
--------------
|
||||||
Type
|
Type
|
||||||
|
|||||||
@@ -33,9 +33,6 @@ def progress(urls, pformat):
|
|||||||
|
|
||||||
def main():
|
def main():
|
||||||
try:
|
try:
|
||||||
if sys.stdout and sys.stdout.encoding.lower() != "utf-8":
|
|
||||||
output.replace_std_streams()
|
|
||||||
|
|
||||||
parser = option.build_parser()
|
parser = option.build_parser()
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
log = output.initialize_logging(args.loglevel)
|
log = output.initialize_logging(args.loglevel)
|
||||||
@@ -77,6 +74,8 @@ def main():
|
|||||||
for opts in args.options:
|
for opts in args.options:
|
||||||
config.set(*opts)
|
config.set(*opts)
|
||||||
|
|
||||||
|
output.configure_standard_streams()
|
||||||
|
|
||||||
# signals
|
# signals
|
||||||
signals = config.get((), "signals-ignore")
|
signals = config.get((), "signals-ignore")
|
||||||
if signals:
|
if signals:
|
||||||
|
|||||||
@@ -271,16 +271,32 @@ else:
|
|||||||
stderr_write = stderr_write_flush
|
stderr_write = stderr_write_flush
|
||||||
|
|
||||||
|
|
||||||
def replace_std_streams(errors="replace"):
|
def configure_standard_streams():
|
||||||
"""Replace standard streams and set their error handlers to 'errors'"""
|
for name in ("stdout", "stderr", "stdin"):
|
||||||
for name in ("stdout", "stdin", "stderr"):
|
options = config.get(("output",), name)
|
||||||
stream = getattr(sys, name)
|
if not options:
|
||||||
if stream:
|
continue
|
||||||
|
|
||||||
|
stream = getattr(sys, name, None)
|
||||||
|
if not stream:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if isinstance(options, str):
|
||||||
|
options = {"encoding": options, "errors": "replace"}
|
||||||
|
elif not options.get("errors"):
|
||||||
|
options["errors"] = "replace"
|
||||||
|
|
||||||
|
try:
|
||||||
|
stream.reconfigure(**options)
|
||||||
|
except AttributeError:
|
||||||
|
# no 'reconfigure' support
|
||||||
|
oget = options.get
|
||||||
setattr(sys, name, stream.__class__(
|
setattr(sys, name, stream.__class__(
|
||||||
stream.buffer,
|
stream.buffer,
|
||||||
errors=errors,
|
encoding=oget("encoding", stream.encoding),
|
||||||
newline=stream.newlines,
|
errors=oget("errors", "replace"),
|
||||||
line_buffering=stream.line_buffering,
|
newline=oget("newline", stream.newlines),
|
||||||
|
line_buffering=oget("line_buffering", stream.line_buffering),
|
||||||
))
|
))
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user