diff --git a/gns3server/utils/asyncio/embed_shell.py b/gns3server/utils/asyncio/embed_shell.py index 6c7d9828..4797c6f2 100644 --- a/gns3server/utils/asyncio/embed_shell.py +++ b/gns3server/utils/asyncio/embed_shell.py @@ -19,6 +19,7 @@ import sys import asyncio import inspect +import io from prompt_toolkit import prompt from prompt_toolkit.history import InMemoryHistory @@ -29,6 +30,7 @@ from prompt_toolkit.interface import CommandLineInterface from prompt_toolkit.layout.screen import Size from prompt_toolkit.shortcuts import create_prompt_application, create_asyncio_eventloop from prompt_toolkit.terminal.vt100_output import Vt100_Output +from prompt_toolkit.input import StdinInput from .telnet_server import AsyncioTelnetServer, TelnetConnection from .input_stream import InputStream @@ -151,6 +153,24 @@ class EmbedShell: return commands +class PatchedStdinInput(StdinInput): + """ + `prompt_toolkit.input.StdinInput` checks whether stdin is tty or not, we don't need do that. + Fixes issue when PyCharm runs own terminal without emulation. + https://github.com/GNS3/gns3-server/issues/1172 + """ + def __init__(self, stdin=None): + self.stdin = stdin or sys.stdin + try: + self.stdin.fileno() + except io.UnsupportedOperation: + if 'idlelib.run' in sys.modules: + raise io.UnsupportedOperation( + 'Stdin is not a terminal. Running from Idle is not supported.') + else: + raise io.UnsupportedOperation('Stdin is not a terminal.') + + class UnstoppableEventLoop(EventLoop): """ Partially fake event loop which cannot be stopped by CommandLineInterface @@ -190,12 +210,18 @@ class ShellConnection(TelnetConnection): @asyncio.coroutine def connected(self): + # prompt_toolkit internally checks if it's on windows during output rendering but + # we need to force that we use Vt100_Output not Win32_Output + from prompt_toolkit import renderer + renderer.is_windows = lambda: False + def get_size(): return self._size self._cli = CommandLineInterface( application=create_prompt_application(self._shell.prompt), eventloop=UnstoppableEventLoop(create_asyncio_eventloop(self._loop)), + input=PatchedStdinInput(sys.stdin), output=Vt100_Output(self, get_size)) self._cb = self._cli.create_eventloop_callbacks()