aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/python/prompt-toolkit/py3/prompt_toolkit/output/flush_stdout.py
diff options
context:
space:
mode:
authorarcadia-devtools <arcadia-devtools@yandex-team.ru>2022-02-08 15:26:58 +0300
committerarcadia-devtools <arcadia-devtools@yandex-team.ru>2022-02-08 15:26:58 +0300
commit2efaaefec2cb2a55d55c01753d1eed2a3296adb5 (patch)
tree27ec5258b325565c3963b91b36d64e84084fdb04 /contrib/python/prompt-toolkit/py3/prompt_toolkit/output/flush_stdout.py
parent23793c5d0827a08b5ff9242d2123eff92b681912 (diff)
downloadydb-2efaaefec2cb2a55d55c01753d1eed2a3296adb5.tar.gz
intermediate changes
ref:0bfa27bb6c38df8c510497e54e4ebf0b4fb84503
Diffstat (limited to 'contrib/python/prompt-toolkit/py3/prompt_toolkit/output/flush_stdout.py')
-rw-r--r--contrib/python/prompt-toolkit/py3/prompt_toolkit/output/flush_stdout.py84
1 files changed, 84 insertions, 0 deletions
diff --git a/contrib/python/prompt-toolkit/py3/prompt_toolkit/output/flush_stdout.py b/contrib/python/prompt-toolkit/py3/prompt_toolkit/output/flush_stdout.py
new file mode 100644
index 00000000000..4adcbd109d0
--- /dev/null
+++ b/contrib/python/prompt-toolkit/py3/prompt_toolkit/output/flush_stdout.py
@@ -0,0 +1,84 @@
+import errno
+import os
+import sys
+from contextlib import contextmanager
+from typing import IO, Iterator, TextIO, cast
+
+__all__ = ["flush_stdout"]
+
+
+def flush_stdout(stdout: TextIO, data: str, write_binary: bool) -> None:
+ try:
+ # Ensure that `stdout` is made blocking when writing into it.
+ # Otherwise, when uvloop is activated (which makes stdout
+ # non-blocking), and we write big amounts of text, then we get a
+ # `BlockingIOError` here.
+ with _blocking_io(stdout):
+ # (We try to encode ourself, because that way we can replace
+ # characters that don't exist in the character set, avoiding
+ # UnicodeEncodeError crashes. E.g. u'\xb7' does not appear in 'ascii'.)
+ # My Arch Linux installation of july 2015 reported 'ANSI_X3.4-1968'
+ # for sys.stdout.encoding in xterm.
+ out: IO[bytes]
+ if write_binary:
+ if hasattr(stdout, "buffer"):
+ out = stdout.buffer
+ else:
+ # IO[bytes] was given to begin with.
+ # (Used in the unit tests, for instance.)
+ out = cast(IO[bytes], stdout)
+ out.write(data.encode(stdout.encoding or "utf-8", "replace"))
+ else:
+ stdout.write(data)
+
+ stdout.flush()
+ except IOError as e:
+ if e.args and e.args[0] == errno.EINTR:
+ # Interrupted system call. Can happen in case of a window
+ # resize signal. (Just ignore. The resize handler will render
+ # again anyway.)
+ pass
+ elif e.args and e.args[0] == 0:
+ # This can happen when there is a lot of output and the user
+ # sends a KeyboardInterrupt by pressing Control-C. E.g. in
+ # a Python REPL when we execute "while True: print('test')".
+ # (The `ptpython` REPL uses this `Output` class instead of
+ # `stdout` directly -- in order to be network transparent.)
+ # So, just ignore.
+ pass
+ else:
+ raise
+
+
+@contextmanager
+def _blocking_io(io: IO[str]) -> Iterator[None]:
+ """
+ Ensure that the FD for `io` is set to blocking in here.
+ """
+ if sys.platform == "win32":
+ # On Windows, the `os` module doesn't have a `get/set_blocking`
+ # function.
+ yield
+ return
+
+ try:
+ fd = io.fileno()
+ blocking = os.get_blocking(fd)
+ except: # noqa
+ # Failed somewhere.
+ # `get_blocking` can raise `OSError`.
+ # The io object can raise `AttributeError` when no `fileno()` method is
+ # present if we're not a real file object.
+ blocking = True # Assume we're good, and don't do anything.
+
+ try:
+ # Make blocking if we weren't blocking yet.
+ if not blocking:
+ os.set_blocking(fd, True)
+
+ yield
+
+ finally:
+ # Restore original blocking mode.
+ if not blocking:
+ os.set_blocking(fd, blocking)