aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/python/prompt-toolkit/py2/prompt_toolkit/eventloop/posix.py
diff options
context:
space:
mode:
authorIvan Blinkov <ivan@blinkov.ru>2022-02-10 16:47:10 +0300
committerDaniil Cherednik <dcherednik@yandex-team.ru>2022-02-10 16:47:10 +0300
commit1aeb9a455974457866f78722ad98114bafc84e8a (patch)
treee4340eaf1668684d83a0a58c36947c5def5350ad /contrib/python/prompt-toolkit/py2/prompt_toolkit/eventloop/posix.py
parentbd5ef432f5cfb1e18851381329d94665a4c22470 (diff)
downloadydb-1aeb9a455974457866f78722ad98114bafc84e8a.tar.gz
Restoring authorship annotation for Ivan Blinkov <ivan@blinkov.ru>. Commit 1 of 2.
Diffstat (limited to 'contrib/python/prompt-toolkit/py2/prompt_toolkit/eventloop/posix.py')
-rw-r--r--contrib/python/prompt-toolkit/py2/prompt_toolkit/eventloop/posix.py528
1 files changed, 264 insertions, 264 deletions
diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/eventloop/posix.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/eventloop/posix.py
index f631dbd891..a2ef2ac3d8 100644
--- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/eventloop/posix.py
+++ b/contrib/python/prompt-toolkit/py2/prompt_toolkit/eventloop/posix.py
@@ -1,244 +1,244 @@
-from __future__ import unicode_literals
-import fcntl
-import os
-import signal
-import threading
+from __future__ import unicode_literals
+import fcntl
+import os
+import signal
+import threading
import time
-
-from prompt_toolkit.terminal.vt100_input import InputStream
-from prompt_toolkit.utils import DummyContext, in_main_thread
-from prompt_toolkit.input import Input
-from .base import EventLoop, INPUT_TIMEOUT
-from .callbacks import EventLoopCallbacks
-from .inputhook import InputHookContext
-from .posix_utils import PosixStdinReader
-from .utils import TimeIt
+
+from prompt_toolkit.terminal.vt100_input import InputStream
+from prompt_toolkit.utils import DummyContext, in_main_thread
+from prompt_toolkit.input import Input
+from .base import EventLoop, INPUT_TIMEOUT
+from .callbacks import EventLoopCallbacks
+from .inputhook import InputHookContext
+from .posix_utils import PosixStdinReader
+from .utils import TimeIt
from .select import AutoSelector, Selector, fd_to_int
-
-__all__ = (
- 'PosixEventLoop',
-)
-
+
+__all__ = (
+ 'PosixEventLoop',
+)
+
_now = time.time
-
-
-class PosixEventLoop(EventLoop):
- """
- Event loop for posix systems (Linux, Mac os X).
- """
+
+
+class PosixEventLoop(EventLoop):
+ """
+ Event loop for posix systems (Linux, Mac os X).
+ """
def __init__(self, inputhook=None, selector=AutoSelector):
- assert inputhook is None or callable(inputhook)
+ assert inputhook is None or callable(inputhook)
assert issubclass(selector, Selector)
-
- self.running = False
- self.closed = False
- self._running = False
- self._callbacks = None
-
- self._calls_from_executor = []
- self._read_fds = {} # Maps fd to handler.
+
+ self.running = False
+ self.closed = False
+ self._running = False
+ self._callbacks = None
+
+ self._calls_from_executor = []
+ self._read_fds = {} # Maps fd to handler.
self.selector = selector()
-
- # Create a pipe for inter thread communication.
- self._schedule_pipe = os.pipe()
- fcntl.fcntl(self._schedule_pipe[0], fcntl.F_SETFL, os.O_NONBLOCK)
-
- # Create inputhook context.
- self._inputhook_context = InputHookContext(inputhook) if inputhook else None
-
- def run(self, stdin, callbacks):
- """
- The input 'event loop'.
- """
- assert isinstance(stdin, Input)
- assert isinstance(callbacks, EventLoopCallbacks)
- assert not self._running
-
- if self.closed:
- raise Exception('Event loop already closed.')
-
- self._running = True
- self._callbacks = callbacks
-
- inputstream = InputStream(callbacks.feed_key)
- current_timeout = [INPUT_TIMEOUT] # Nonlocal
-
- # Create reader class.
- stdin_reader = PosixStdinReader(stdin.fileno())
-
- # Only attach SIGWINCH signal handler in main thread.
- # (It's not possible to attach signal handlers in other threads. In
- # that case we should rely on a the main thread to call this manually
- # instead.)
- if in_main_thread():
- ctx = call_on_sigwinch(self.received_winch)
- else:
- ctx = DummyContext()
-
- def read_from_stdin():
- " Read user input. "
- # Feed input text.
- data = stdin_reader.read()
- inputstream.feed(data)
-
- # Set timeout again.
- current_timeout[0] = INPUT_TIMEOUT
-
+
+ # Create a pipe for inter thread communication.
+ self._schedule_pipe = os.pipe()
+ fcntl.fcntl(self._schedule_pipe[0], fcntl.F_SETFL, os.O_NONBLOCK)
+
+ # Create inputhook context.
+ self._inputhook_context = InputHookContext(inputhook) if inputhook else None
+
+ def run(self, stdin, callbacks):
+ """
+ The input 'event loop'.
+ """
+ assert isinstance(stdin, Input)
+ assert isinstance(callbacks, EventLoopCallbacks)
+ assert not self._running
+
+ if self.closed:
+ raise Exception('Event loop already closed.')
+
+ self._running = True
+ self._callbacks = callbacks
+
+ inputstream = InputStream(callbacks.feed_key)
+ current_timeout = [INPUT_TIMEOUT] # Nonlocal
+
+ # Create reader class.
+ stdin_reader = PosixStdinReader(stdin.fileno())
+
+ # Only attach SIGWINCH signal handler in main thread.
+ # (It's not possible to attach signal handlers in other threads. In
+ # that case we should rely on a the main thread to call this manually
+ # instead.)
+ if in_main_thread():
+ ctx = call_on_sigwinch(self.received_winch)
+ else:
+ ctx = DummyContext()
+
+ def read_from_stdin():
+ " Read user input. "
+ # Feed input text.
+ data = stdin_reader.read()
+ inputstream.feed(data)
+
+ # Set timeout again.
+ current_timeout[0] = INPUT_TIMEOUT
+
# Quit when the input stream was closed.
if stdin_reader.closed:
self.stop()
- self.add_reader(stdin, read_from_stdin)
- self.add_reader(self._schedule_pipe[0], None)
-
- with ctx:
- while self._running:
- # Call inputhook.
+ self.add_reader(stdin, read_from_stdin)
+ self.add_reader(self._schedule_pipe[0], None)
+
+ with ctx:
+ while self._running:
+ # Call inputhook.
if self._inputhook_context:
with TimeIt() as inputhook_timer:
- def ready(wait):
- " True when there is input ready. The inputhook should return control. "
- return self._ready_for_reading(current_timeout[0] if wait else 0) != []
- self._inputhook_context.call_inputhook(ready)
+ def ready(wait):
+ " True when there is input ready. The inputhook should return control. "
+ return self._ready_for_reading(current_timeout[0] if wait else 0) != []
+ self._inputhook_context.call_inputhook(ready)
inputhook_duration = inputhook_timer.duration
else:
inputhook_duration = 0
-
- # Calculate remaining timeout. (The inputhook consumed some of the time.)
- if current_timeout[0] is None:
- remaining_timeout = None
- else:
+
+ # Calculate remaining timeout. (The inputhook consumed some of the time.)
+ if current_timeout[0] is None:
+ remaining_timeout = None
+ else:
remaining_timeout = max(0, current_timeout[0] - inputhook_duration)
-
- # Wait until input is ready.
- fds = self._ready_for_reading(remaining_timeout)
-
- # When any of the FDs are ready. Call the appropriate callback.
- if fds:
- # Create lists of high/low priority tasks. The main reason
- # for this is to allow painting the UI to happen as soon as
- # possible, but when there are many events happening, we
- # don't want to call the UI renderer 1000x per second. If
- # the eventloop is completely saturated with many CPU
- # intensive tasks (like processing input/output), we say
- # that drawing the UI can be postponed a little, to make
- # CPU available. This will be a low priority task in that
- # case.
- tasks = []
- low_priority_tasks = []
+
+ # Wait until input is ready.
+ fds = self._ready_for_reading(remaining_timeout)
+
+ # When any of the FDs are ready. Call the appropriate callback.
+ if fds:
+ # Create lists of high/low priority tasks. The main reason
+ # for this is to allow painting the UI to happen as soon as
+ # possible, but when there are many events happening, we
+ # don't want to call the UI renderer 1000x per second. If
+ # the eventloop is completely saturated with many CPU
+ # intensive tasks (like processing input/output), we say
+ # that drawing the UI can be postponed a little, to make
+ # CPU available. This will be a low priority task in that
+ # case.
+ tasks = []
+ low_priority_tasks = []
now = None # Lazy load time. (Fewer system calls.)
-
- for fd in fds:
- # For the 'call_from_executor' fd, put each pending
- # item on either the high or low priority queue.
- if fd == self._schedule_pipe[0]:
- for c, max_postpone_until in self._calls_from_executor:
+
+ for fd in fds:
+ # For the 'call_from_executor' fd, put each pending
+ # item on either the high or low priority queue.
+ if fd == self._schedule_pipe[0]:
+ for c, max_postpone_until in self._calls_from_executor:
if max_postpone_until is None:
# Execute now.
- tasks.append(c)
- else:
+ tasks.append(c)
+ else:
# Execute soon, if `max_postpone_until` is in the future.
now = now or _now()
if max_postpone_until < now:
tasks.append(c)
else:
low_priority_tasks.append((c, max_postpone_until))
- self._calls_from_executor = []
-
- # Flush all the pipe content.
- os.read(self._schedule_pipe[0], 1024)
- else:
- handler = self._read_fds.get(fd)
- if handler:
- tasks.append(handler)
-
- # When there are high priority tasks, run all these.
- # Schedule low priority tasks for the next iteration.
- if tasks:
- for t in tasks:
- t()
-
- # Postpone low priority tasks.
- for t, max_postpone_until in low_priority_tasks:
- self.call_from_executor(t, _max_postpone_until=max_postpone_until)
- else:
- # Currently there are only low priority tasks -> run them right now.
- for t, _ in low_priority_tasks:
- t()
-
- else:
- # Flush all pending keys on a timeout. (This is most
- # important to flush the vt100 'Escape' key early when
- # nothing else follows.)
- inputstream.flush()
-
- # Fire input timeout event.
- callbacks.input_timeout()
- current_timeout[0] = None
-
- self.remove_reader(stdin)
- self.remove_reader(self._schedule_pipe[0])
-
- self._callbacks = None
-
- def _ready_for_reading(self, timeout=None):
- """
- Return the file descriptors that are ready for reading.
- """
+ self._calls_from_executor = []
+
+ # Flush all the pipe content.
+ os.read(self._schedule_pipe[0], 1024)
+ else:
+ handler = self._read_fds.get(fd)
+ if handler:
+ tasks.append(handler)
+
+ # When there are high priority tasks, run all these.
+ # Schedule low priority tasks for the next iteration.
+ if tasks:
+ for t in tasks:
+ t()
+
+ # Postpone low priority tasks.
+ for t, max_postpone_until in low_priority_tasks:
+ self.call_from_executor(t, _max_postpone_until=max_postpone_until)
+ else:
+ # Currently there are only low priority tasks -> run them right now.
+ for t, _ in low_priority_tasks:
+ t()
+
+ else:
+ # Flush all pending keys on a timeout. (This is most
+ # important to flush the vt100 'Escape' key early when
+ # nothing else follows.)
+ inputstream.flush()
+
+ # Fire input timeout event.
+ callbacks.input_timeout()
+ current_timeout[0] = None
+
+ self.remove_reader(stdin)
+ self.remove_reader(self._schedule_pipe[0])
+
+ self._callbacks = None
+
+ def _ready_for_reading(self, timeout=None):
+ """
+ Return the file descriptors that are ready for reading.
+ """
fds = self.selector.select(timeout)
return fds
-
- def received_winch(self):
- """
- Notify the event loop that SIGWINCH has been received
- """
- # Process signal asynchronously, because this handler can write to the
- # output, and doing this inside the signal handler causes easily
- # reentrant calls, giving runtime errors..
-
- # Furthur, this has to be thread safe. When the CommandLineInterface
- # runs not in the main thread, this function still has to be called
- # from the main thread. (The only place where we can install signal
- # handlers.)
- def process_winch():
- if self._callbacks:
- self._callbacks.terminal_size_changed()
-
- self.call_from_executor(process_winch)
-
- def run_in_executor(self, callback):
- """
- Run a long running function in a background thread.
- (This is recommended for code that could block the event loop.)
- Similar to Twisted's ``deferToThread``.
- """
- # Wait until the main thread is idle.
- # We start the thread by using `call_from_executor`. The event loop
- # favours processing input over `calls_from_executor`, so the thread
- # will not start until there is no more input to process and the main
- # thread becomes idle for an instant. This is good, because Python
- # threading favours CPU over I/O -- an autocompletion thread in the
- # background would cause a significantly slow down of the main thread.
- # It is mostly noticable when pasting large portions of text while
- # having real time autocompletion while typing on.
- def start_executor():
- threading.Thread(target=callback).start()
- self.call_from_executor(start_executor)
-
- def call_from_executor(self, callback, _max_postpone_until=None):
- """
- Call this function in the main event loop.
- Similar to Twisted's ``callFromThread``.
-
+
+ def received_winch(self):
+ """
+ Notify the event loop that SIGWINCH has been received
+ """
+ # Process signal asynchronously, because this handler can write to the
+ # output, and doing this inside the signal handler causes easily
+ # reentrant calls, giving runtime errors..
+
+ # Furthur, this has to be thread safe. When the CommandLineInterface
+ # runs not in the main thread, this function still has to be called
+ # from the main thread. (The only place where we can install signal
+ # handlers.)
+ def process_winch():
+ if self._callbacks:
+ self._callbacks.terminal_size_changed()
+
+ self.call_from_executor(process_winch)
+
+ def run_in_executor(self, callback):
+ """
+ Run a long running function in a background thread.
+ (This is recommended for code that could block the event loop.)
+ Similar to Twisted's ``deferToThread``.
+ """
+ # Wait until the main thread is idle.
+ # We start the thread by using `call_from_executor`. The event loop
+ # favours processing input over `calls_from_executor`, so the thread
+ # will not start until there is no more input to process and the main
+ # thread becomes idle for an instant. This is good, because Python
+ # threading favours CPU over I/O -- an autocompletion thread in the
+ # background would cause a significantly slow down of the main thread.
+ # It is mostly noticable when pasting large portions of text while
+ # having real time autocompletion while typing on.
+ def start_executor():
+ threading.Thread(target=callback).start()
+ self.call_from_executor(start_executor)
+
+ def call_from_executor(self, callback, _max_postpone_until=None):
+ """
+ Call this function in the main event loop.
+ Similar to Twisted's ``callFromThread``.
+
:param _max_postpone_until: `None` or `time.time` value. For interal
- use. If the eventloop is saturated, consider this task to be low
- priority and postpone maximum until this timestamp. (For instance,
- repaint is done using low priority.)
- """
+ use. If the eventloop is saturated, consider this task to be low
+ priority and postpone maximum until this timestamp. (For instance,
+ repaint is done using low priority.)
+ """
assert _max_postpone_until is None or isinstance(_max_postpone_until, float)
- self._calls_from_executor.append((callback, _max_postpone_until))
-
- if self._schedule_pipe:
+ self._calls_from_executor.append((callback, _max_postpone_until))
+
+ if self._schedule_pipe:
try:
os.write(self._schedule_pipe[1], b'x')
except (AttributeError, IndexError, OSError):
@@ -247,60 +247,60 @@ class PosixEventLoop(EventLoop):
# - We catch `OSError` (actually BrokenPipeError), because the
# main thread could have closed the pipe already.
pass
-
- def stop(self):
- """
- Stop the event loop.
- """
- self._running = False
-
- def close(self):
- self.closed = True
-
- # Close pipes.
- schedule_pipe = self._schedule_pipe
- self._schedule_pipe = None
-
- if schedule_pipe:
- os.close(schedule_pipe[0])
- os.close(schedule_pipe[1])
-
- if self._inputhook_context:
- self._inputhook_context.close()
-
- def add_reader(self, fd, callback):
- " Add read file descriptor to the event loop. "
+
+ def stop(self):
+ """
+ Stop the event loop.
+ """
+ self._running = False
+
+ def close(self):
+ self.closed = True
+
+ # Close pipes.
+ schedule_pipe = self._schedule_pipe
+ self._schedule_pipe = None
+
+ if schedule_pipe:
+ os.close(schedule_pipe[0])
+ os.close(schedule_pipe[1])
+
+ if self._inputhook_context:
+ self._inputhook_context.close()
+
+ def add_reader(self, fd, callback):
+ " Add read file descriptor to the event loop. "
fd = fd_to_int(fd)
- self._read_fds[fd] = callback
+ self._read_fds[fd] = callback
self.selector.register(fd)
-
- def remove_reader(self, fd):
- " Remove read file descriptor from the event loop. "
+
+ def remove_reader(self, fd):
+ " Remove read file descriptor from the event loop. "
fd = fd_to_int(fd)
- if fd in self._read_fds:
- del self._read_fds[fd]
-
+ if fd in self._read_fds:
+ del self._read_fds[fd]
+
self.selector.unregister(fd)
-
-
-class call_on_sigwinch(object):
- """
- Context manager which Installs a SIGWINCH callback.
- (This signal occurs when the terminal size changes.)
- """
- def __init__(self, callback):
- self.callback = callback
- self.previous_callback = None
-
- def __enter__(self):
- self.previous_callback = signal.signal(signal.SIGWINCH, lambda *a: self.callback())
-
- def __exit__(self, *a, **kw):
- if self.previous_callback is None:
- # Normally, `signal.signal` should never return `None`.
- # For some reason it happens here:
- # https://github.com/jonathanslenders/python-prompt-toolkit/pull/174
- signal.signal(signal.SIGWINCH, 0)
- else:
- signal.signal(signal.SIGWINCH, self.previous_callback)
+
+
+class call_on_sigwinch(object):
+ """
+ Context manager which Installs a SIGWINCH callback.
+ (This signal occurs when the terminal size changes.)
+ """
+ def __init__(self, callback):
+ self.callback = callback
+ self.previous_callback = None
+
+ def __enter__(self):
+ self.previous_callback = signal.signal(signal.SIGWINCH, lambda *a: self.callback())
+
+ def __exit__(self, *a, **kw):
+ if self.previous_callback is None:
+ # Normally, `signal.signal` should never return `None`.
+ # For some reason it happens here:
+ # https://github.com/jonathanslenders/python-prompt-toolkit/pull/174
+ signal.signal(signal.SIGWINCH, 0)
+ else:
+ signal.signal(signal.SIGWINCH, self.previous_callback)