Esempio n. 1
0
    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()
Esempio n. 2
0
    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)
Esempio n. 3
0
                    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)
Esempio n. 4
0
    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
Esempio n. 5
0
        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()
Esempio n. 6
0
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]
Esempio n. 7
0
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())
Esempio n. 8
0
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
Esempio n. 9
0
    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()
Esempio n. 10
0
        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)