def close(self): """ Closed by client. """ if not self._closed: self._closed = True self.vt100_input.close() get_event_loop().remove_reader(self.conn) self.conn.close()
def start(self): """ Start the telnet server. Don't forget to call `loop.run_forever()` after doing this. """ self._listen_socket = self._create_socket(self.host, self.port) logger.info('Listening for telnet connections on %s port %r', self.host, self.port) get_event_loop().add_reader(self._listen_socket, self._accept)
def timer(): time.sleep(self.CPR_TIMEOUT) # Not set in the meantime -> not supported. if self.cpr_support == CPR_Support.UNKNOWN: self.cpr_support = CPR_Support.NOT_SUPPORTED if self.cpr_not_supported_callback: # Make sure to call this callback in the main thread. get_event_loop().call_from_executor( self.cpr_not_supported_callback)
def __init__(self, title=None, formatters=None, bottom_toolbar=None, style=None, key_bindings=None, file=None, color_depth=None, output=None, input=None): assert formatters is None or (isinstance(formatters, list) and all( isinstance(fo, Formatter) for fo in formatters)) assert style is None or isinstance(style, BaseStyle) assert key_bindings is None or isinstance(key_bindings, KeyBindings) self.title = title self.formatters = formatters or create_default_formatters() self.bottom_toolbar = bottom_toolbar self.counters = [] self.style = style self.key_bindings = key_bindings # Note that we use __stderr__ as default error output, because that # works best with `patch_stdout`. self.color_depth = color_depth self.output = output or create_output(stdout=file or sys.__stderr__) self.input = input or get_default_input() self._thread = None self._loop = get_event_loop() self._previous_winch_handler = None self._has_sigwinch = False
def run(): with context() as ctx_id: self._context_id = ctx_id # Set input/output for all application running in this context. set_default_input(self.vt100_input) set_default_output(self.vt100_output) # Add reader. loop = get_event_loop() loop.add_reader(self.conn, handle_incoming_data) try: obj = self.interact(self) if _is_coroutine(obj): # Got an asyncio coroutine. import asyncio f = asyncio.ensure_future(obj) yield From(Future.from_asyncio_future(f)) else: # Got a prompt_toolkit coroutine. yield From(obj) except Exception as e: print('Got %s' % type(e).__name__, e) import traceback traceback.print_exc() raise finally: self.close()
def _attach_win32_input(input, callback): """ Context manager that makes this input active in the current event loop. :param input: :class:`~prompt_toolkit.input.Input` object. :param input_ready_callback: Called when the input is ready to read. """ assert isinstance(input, Input) loop = get_event_loop() previous_callback = _current_callbacks.get(loop) # Add reader. loop.add_win32_handle(input.handle, callback) _current_callbacks[loop] = callback try: yield finally: loop.remove_win32_handle(input.handle) if previous_callback: loop.add_win32_handle(input.handle, previous_callback) _current_callbacks[loop] = previous_callback else: del _current_callbacks[loop]
def run_coroutine_in_terminal(async_func, render_cli_done=False): """ Suspend the current application and run this coroutine instead. `async_func` can be a coroutine or a function that returns a Future. :param async_func: A function that returns either a Future or coroutine when called. :returns: A `Future`. """ assert callable(async_func) loop = get_event_loop() # Make sure to run this function in the current `Application`, or if no # application is active, run it normally. app = get_app(return_none=True) if app is None: return ensure_future(async_func()) assert app._is_running # When a previous `run_in_terminal` call was in progress. Wait for that # to finish, before starting this one. Chain to previous call. previous_run_in_terminal_f = app._running_in_terminal_f new_run_in_terminal_f = loop.create_future() app._running_in_terminal_f = new_run_in_terminal_f def _run_in_t(): " Coroutine. " # Wait for the previous `run_in_terminal` to finish. if previous_run_in_terminal_f is not None: yield previous_run_in_terminal_f # Draw interface in 'done' state, or erase. if render_cli_done: app._redraw(render_as_done=True) else: app.renderer.erase() # Disable rendering. app._running_in_terminal = True # Detach input. try: with app.input.detach(): with app.input.cooked_mode(): result = yield From(async_func()) raise Return(result) # Same as: "return result" finally: # Redraw interface again. try: app._running_in_terminal = False app.renderer.reset() app._request_absolute_cursor_position() app._redraw() finally: new_run_in_terminal_f.set_result(None) return ensure_future(_run_in_t())
def _detach_win32_input(input): loop = get_event_loop() previous = _current_callbacks.get(loop) if previous: loop.remove_win32_handle(input.handle) _current_callbacks[loop] = None try: yield finally: if previous: loop.add_win32_handle(input.handle, previous) _current_callbacks[loop] = previous
def run(self, pre_run=None, set_exception_handler=True, inputhook=None): """ A blocking 'run' call that waits until the UI is finished. :param set_exception_handler: When set, in case of an exception, go out of the alternate screen and hide the application, display the exception, and wait for the user to press ENTER. :param inputhook: None or a callable that takes an `InputHookContext`. """ loop = get_event_loop() def run(): f = self.run_async(pre_run=pre_run) run_until_complete(f, inputhook=inputhook) return f.result() def handle_exception(context): " Print the exception, using run_in_terminal. " # For Python 2: we have to get traceback at this point, because # we're still in the 'except:' block of the event loop where the # traceback is still available. Moving this code in the # 'print_exception' coroutine will loose the exception. tb = get_traceback_from_context(context) formatted_tb = ''.join(format_tb(tb)) def print_exception(): # Print output. Similar to 'loop.default_exception_handler', # but don't use logger. (This works better on Python 2.) print('\nUnhandled exception in event loop:') print(formatted_tb) print('Exception %s' % (context.get('exception'), )) yield From(_do_wait_for_enter('Press ENTER to continue...')) run_coroutine_in_terminal(print_exception) if set_exception_handler: # Run with patched exception handler. previous_exc_handler = loop.get_exception_handler() loop.set_exception_handler(handle_exception) try: return run() finally: loop.set_exception_handler(previous_exc_handler) else: run()
def _run_async(): " Coroutine. " loop = get_event_loop() f = loop.create_future() self.future = f # XXX: make sure to set this before calling '_redraw'. # Counter for cancelling 'flush' timeouts. Every time when a key is # pressed, we start a 'flush' timer for flushing our escape key. But # when any subsequent input is received, a new timer is started and # the current timer will be ignored. flush_counter = [0] # Non local. # Reset. self.reset() self._pre_run(pre_run) # Feed type ahead input first. self.key_processor.feed_multiple(get_typeahead(self.input)) self.key_processor.process_keys() def read_from_input(): # Ignore when we aren't running anymore. This callback will # removed from the loop next time. (It could be that it was # still in the 'tasks' list of the loop.) # Except: if we need to process incoming CPRs. if not self._is_running and not self.renderer.waiting_for_cpr: return # Get keys from the input object. keys = self.input.read_keys() # Feed to key processor. self.key_processor.feed_multiple(keys) self.key_processor.process_keys() # Quit when the input stream was closed. if self.input.closed: f.set_exception(EOFError) else: # Increase this flush counter. flush_counter[0] += 1 counter = flush_counter[0] # Automatically flush keys. # (_daemon needs to be set, otherwise, this will hang the # application for .5 seconds before exiting.) run_in_executor(lambda: auto_flush_input(counter), _daemon=True) def auto_flush_input(counter): # Flush input after timeout. # (Used for flushing the enter key.) time.sleep(self.ttimeoutlen) if flush_counter[0] == counter: call_from_executor(flush_input) def flush_input(): if not self.is_done: # Get keys, and feed to key processor. keys = self.input.flush_keys() self.key_processor.feed_multiple(keys) self.key_processor.process_keys() if self.input.closed: f.set_exception(EOFError) # Enter raw mode. with self.input.raw_mode(): with self.input.attach(read_from_input): # Draw UI. self._request_absolute_cursor_position() self._redraw() has_sigwinch = hasattr(signal, 'SIGWINCH') and in_main_thread() if has_sigwinch: previous_winch_handler = loop.add_signal_handler( signal.SIGWINCH, self._on_resize) # Wait for UI to finish. try: result = yield From(f) finally: # In any case, when the application finishes. (Successful, # or because of an error.) try: self._redraw(render_as_done=True) finally: # _redraw has a good chance to fail if it calls widgets # with bad code. Make sure to reset the renderer anyway. self.renderer.reset() # Unset `is_running`, this ensures that possibly # scheduled draws won't paint during the following # yield. self._is_running = False # Wait for CPR responses. if self.input.responds_to_cpr: yield From( self.renderer.wait_for_cpr_responses()) if has_sigwinch: loop.add_signal_handler( signal.SIGWINCH, previous_winch_handler) # Wait for the run-in-terminals to terminate. previous_run_in_terminal_f = self._running_in_terminal_f if previous_run_in_terminal_f: yield From(previous_run_in_terminal_f) # Store unprocessed input as typeahead for next time. store_typeahead(self.input, self.key_processor.empty_queue()) raise Return(result)