aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/python/prompt-toolkit/py3/prompt_toolkit/input
diff options
context:
space:
mode:
authorarcadia-devtools <arcadia-devtools@yandex-team.ru>2022-04-06 18:18:01 +0300
committerarcadia-devtools <arcadia-devtools@yandex-team.ru>2022-04-06 18:18:01 +0300
commit01fbacb386809436dfa331780875aed72cb76118 (patch)
tree04c911ad96ff0523bd4d3e7a45c23cf2f2d7607d /contrib/python/prompt-toolkit/py3/prompt_toolkit/input
parent48fb997d7f820a474b9094a72d9798a95ec612b7 (diff)
downloadydb-01fbacb386809436dfa331780875aed72cb76118.tar.gz
intermediate changes
ref:b4f892f3c2b06a356c155f73c27efc5661a7fb89
Diffstat (limited to 'contrib/python/prompt-toolkit/py3/prompt_toolkit/input')
-rw-r--r--contrib/python/prompt-toolkit/py3/prompt_toolkit/input/__init__.py3
-rw-r--r--contrib/python/prompt-toolkit/py3/prompt_toolkit/input/base.py6
-rw-r--r--contrib/python/prompt-toolkit/py3/prompt_toolkit/input/defaults.py22
-rw-r--r--contrib/python/prompt-toolkit/py3/prompt_toolkit/input/posix_pipe.py74
-rw-r--r--contrib/python/prompt-toolkit/py3/prompt_toolkit/input/vt100.py5
-rw-r--r--contrib/python/prompt-toolkit/py3/prompt_toolkit/input/win32.py2
-rw-r--r--contrib/python/prompt-toolkit/py3/prompt_toolkit/input/win32_pipe.py29
7 files changed, 111 insertions, 30 deletions
diff --git a/contrib/python/prompt-toolkit/py3/prompt_toolkit/input/__init__.py b/contrib/python/prompt-toolkit/py3/prompt_toolkit/input/__init__.py
index 421d4ccdf4..dc319769ef 100644
--- a/contrib/python/prompt-toolkit/py3/prompt_toolkit/input/__init__.py
+++ b/contrib/python/prompt-toolkit/py3/prompt_toolkit/input/__init__.py
@@ -1,9 +1,10 @@
-from .base import DummyInput, Input
+from .base import DummyInput, Input, PipeInput
from .defaults import create_input, create_pipe_input
__all__ = [
# Base.
"Input",
+ "PipeInput",
"DummyInput",
# Defaults.
"create_input",
diff --git a/contrib/python/prompt-toolkit/py3/prompt_toolkit/input/base.py b/contrib/python/prompt-toolkit/py3/prompt_toolkit/input/base.py
index 9885a37bc2..313622de5a 100644
--- a/contrib/python/prompt-toolkit/py3/prompt_toolkit/input/base.py
+++ b/contrib/python/prompt-toolkit/py3/prompt_toolkit/input/base.py
@@ -9,6 +9,7 @@ from prompt_toolkit.key_binding import KeyPress
__all__ = [
"Input",
+ "PipeInput",
"DummyInput",
]
@@ -104,6 +105,9 @@ class PipeInput(Input):
class DummyInput(Input):
"""
Input for use in a `DummyApplication`
+
+ If used in an actual application, it will make the application render
+ itself once and exit immediately, due to an `EOFError`.
"""
def fileno(self) -> int:
@@ -117,6 +121,8 @@ class DummyInput(Input):
@property
def closed(self) -> bool:
+ # This needs to be true, so that the dummy input will trigger an
+ # `EOFError` immediately in the application.
return True
def raw_mode(self) -> ContextManager[None]:
diff --git a/contrib/python/prompt-toolkit/py3/prompt_toolkit/input/defaults.py b/contrib/python/prompt-toolkit/py3/prompt_toolkit/input/defaults.py
index 347f8c6ad3..197dcb9a60 100644
--- a/contrib/python/prompt-toolkit/py3/prompt_toolkit/input/defaults.py
+++ b/contrib/python/prompt-toolkit/py3/prompt_toolkit/input/defaults.py
@@ -1,7 +1,5 @@
import sys
-from typing import Optional, TextIO
-
-from prompt_toolkit.utils import is_windows
+from typing import ContextManager, Optional, TextIO
from .base import DummyInput, Input, PipeInput
@@ -23,7 +21,7 @@ def create_input(
`sys.stdin`. (We can open `stdout` or `stderr` for reading, this is how
a `$PAGER` works.)
"""
- if is_windows():
+ if sys.platform == "win32":
from .win32 import Win32Input
# If `stdin` was assigned `None` (which happens with pythonw.exe), use
@@ -48,16 +46,24 @@ def create_input(
return Vt100Input(stdin)
-def create_pipe_input() -> PipeInput:
+def create_pipe_input() -> ContextManager[PipeInput]:
"""
Create an input pipe.
This is mostly useful for unit testing.
+
+ Usage::
+
+ with create_pipe_input() as input:
+ input.send_text('inputdata')
+
+ Breaking change: In prompt_toolkit 3.0.28 and earlier, this was returning
+ the `PipeInput` directly, rather than through a context manager.
"""
- if is_windows():
+ if sys.platform == "win32":
from .win32_pipe import Win32PipeInput
- return Win32PipeInput()
+ return Win32PipeInput.create()
else:
from .posix_pipe import PosixPipeInput
- return PosixPipeInput()
+ return PosixPipeInput.create()
diff --git a/contrib/python/prompt-toolkit/py3/prompt_toolkit/input/posix_pipe.py b/contrib/python/prompt-toolkit/py3/prompt_toolkit/input/posix_pipe.py
index 22dd7be6b5..1e7dec77fd 100644
--- a/contrib/python/prompt-toolkit/py3/prompt_toolkit/input/posix_pipe.py
+++ b/contrib/python/prompt-toolkit/py3/prompt_toolkit/input/posix_pipe.py
@@ -1,5 +1,10 @@
+import sys
+
+assert sys.platform != "win32"
+
import os
-from typing import ContextManager, TextIO, cast
+from contextlib import contextmanager
+from typing import ContextManager, Iterator, TextIO, cast
from ..utils import DummyContext
from .base import PipeInput
@@ -10,6 +15,36 @@ __all__ = [
]
+class _Pipe:
+ "Wrapper around os.pipe, that ensures we don't double close any end."
+
+ def __init__(self) -> None:
+ self.read_fd, self.write_fd = os.pipe()
+ self._read_closed = False
+ self._write_closed = False
+
+ def close_read(self) -> None:
+ "Close read-end if not yet closed."
+ if self._read_closed:
+ return
+
+ os.close(self.read_fd)
+ self._read_closed = True
+
+ def close_write(self) -> None:
+ "Close write-end if not yet closed."
+ if self._write_closed:
+ return
+
+ os.close(self.write_fd)
+ self._write_closed = True
+
+ def close(self) -> None:
+ "Close both read and write ends."
+ self.close_read()
+ self.close_write()
+
+
class PosixPipeInput(Vt100Input, PipeInput):
"""
Input that is send through a pipe.
@@ -18,14 +53,15 @@ class PosixPipeInput(Vt100Input, PipeInput):
Usage::
- input = PosixPipeInput()
- input.send_text('inputdata')
+ with PosixPipeInput.create() as input:
+ input.send_text('inputdata')
"""
_id = 0
- def __init__(self, text: str = "") -> None:
- self._r, self._w = os.pipe()
+ def __init__(self, _pipe: _Pipe, _text: str = "") -> None:
+ # Private constructor. Users should use the public `.create()` method.
+ self.pipe = _pipe
class Stdin:
encoding = "utf-8"
@@ -34,21 +70,30 @@ class PosixPipeInput(Vt100Input, PipeInput):
return True
def fileno(stdin) -> int:
- return self._r
+ return self.pipe.read_fd
super().__init__(cast(TextIO, Stdin()))
- self.send_text(text)
+ self.send_text(_text)
# Identifier for every PipeInput for the hash.
self.__class__._id += 1
self._id = self.__class__._id
+ @classmethod
+ @contextmanager
+ def create(cls, text: str = "") -> Iterator["PosixPipeInput"]:
+ pipe = _Pipe()
+ try:
+ yield PosixPipeInput(_pipe=pipe, _text=text)
+ finally:
+ pipe.close()
+
def send_bytes(self, data: bytes) -> None:
- os.write(self._w, data)
+ os.write(self.pipe.write_fd, data)
def send_text(self, data: str) -> None:
"Send text to the input."
- os.write(self._w, data.encode("utf-8"))
+ os.write(self.pipe.write_fd, data.encode("utf-8"))
def raw_mode(self) -> ContextManager[None]:
return DummyContext()
@@ -58,12 +103,11 @@ class PosixPipeInput(Vt100Input, PipeInput):
def close(self) -> None:
"Close pipe fds."
- os.close(self._r)
- os.close(self._w)
-
- # We should assign `None` to 'self._r` and 'self._w',
- # The event loop still needs to know the the fileno for this input in order
- # to properly remove it from the selectors.
+ # Only close the write-end of the pipe. This will unblock the reader
+ # callback (in vt100.py > _attached_input), which eventually will raise
+ # `EOFError`. If we'd also close the read-end, then the event loop
+ # won't wake up the corresponding callback because of this.
+ self.pipe.close_write()
def typeahead_hash(self) -> str:
"""
diff --git a/contrib/python/prompt-toolkit/py3/prompt_toolkit/input/vt100.py b/contrib/python/prompt-toolkit/py3/prompt_toolkit/input/vt100.py
index 639d372609..45ce37208a 100644
--- a/contrib/python/prompt-toolkit/py3/prompt_toolkit/input/vt100.py
+++ b/contrib/python/prompt-toolkit/py3/prompt_toolkit/input/vt100.py
@@ -1,6 +1,9 @@
+import sys
+
+assert sys.platform != "win32"
+
import contextlib
import io
-import sys
import termios
import tty
from asyncio import AbstractEventLoop
diff --git a/contrib/python/prompt-toolkit/py3/prompt_toolkit/input/win32.py b/contrib/python/prompt-toolkit/py3/prompt_toolkit/input/win32.py
index c59375b3d4..db3fa2badd 100644
--- a/contrib/python/prompt-toolkit/py3/prompt_toolkit/input/win32.py
+++ b/contrib/python/prompt-toolkit/py3/prompt_toolkit/input/win32.py
@@ -7,6 +7,8 @@ from prompt_toolkit.eventloop import get_event_loop
from ..utils import SPHINX_AUTODOC_RUNNING
+assert sys.platform == "win32"
+
# Do not import win32-specific stuff when generating documentation.
# Otherwise RTD would be unable to generate docs for this module.
if not SPHINX_AUTODOC_RUNNING:
diff --git a/contrib/python/prompt-toolkit/py3/prompt_toolkit/input/win32_pipe.py b/contrib/python/prompt-toolkit/py3/prompt_toolkit/input/win32_pipe.py
index fdbcb8ee83..ebee2075ed 100644
--- a/contrib/python/prompt-toolkit/py3/prompt_toolkit/input/win32_pipe.py
+++ b/contrib/python/prompt-toolkit/py3/prompt_toolkit/input/win32_pipe.py
@@ -1,6 +1,11 @@
+import sys
+
+assert sys.platform == "win32"
+
+from contextlib import contextmanager
from ctypes import windll
from ctypes.wintypes import HANDLE
-from typing import Callable, ContextManager, List
+from typing import Callable, ContextManager, Iterator, List
from prompt_toolkit.eventloop.win32 import create_win32_event
@@ -31,7 +36,7 @@ class Win32PipeInput(_Win32InputBase, PipeInput):
_id = 0
- def __init__(self) -> None:
+ def __init__(self, _event: HANDLE) -> None:
super().__init__()
# Event (handle) for registering this input in the event loop.
# This event is set when there is data available to read from the pipe.
@@ -50,6 +55,15 @@ class Win32PipeInput(_Win32InputBase, PipeInput):
self.__class__._id += 1
self._id = self.__class__._id
+ @classmethod
+ @contextmanager
+ def create(cls) -> Iterator["Win32PipeInput"]:
+ event = create_win32_event()
+ try:
+ yield Win32PipeInput(_event=event)
+ finally:
+ windll.kernel32.CloseHandle(event)
+
@property
def closed(self) -> bool:
return self._closed
@@ -87,7 +101,9 @@ class Win32PipeInput(_Win32InputBase, PipeInput):
self._buffer = []
# Reset event.
- windll.kernel32.ResetEvent(self._event)
+ if not self._closed:
+ # (If closed, the event should not reset.)
+ windll.kernel32.ResetEvent(self._event)
return result
@@ -111,6 +127,9 @@ class Win32PipeInput(_Win32InputBase, PipeInput):
def send_text(self, text: str) -> None:
"Send text to the input."
+ if self._closed:
+ raise ValueError("Attempt to write into a closed pipe.")
+
# Pass it through our vt100 parser.
self.vt100_parser.feed(text)
@@ -124,9 +143,9 @@ class Win32PipeInput(_Win32InputBase, PipeInput):
return DummyContext()
def close(self) -> None:
- "Close pipe handles."
- windll.kernel32.CloseHandle(self._event)
+ "Close write-end of the pipe."
self._closed = True
+ windll.kernel32.SetEvent(self._event)
def typeahead_hash(self) -> str:
"""