def _feed_cli_with_input(text, editing_mode=EditingMode.EMACS, clipboard=None, history=None): """ Create a CommandLineInterface, feed it with the given user input and return the CLI object. This returns a (result, CLI) tuple. """ # If the given text doesn't end with a newline, the interface won't finish. assert text.endswith('\n') loop = PosixEventLoop() try: inp = PipeInput() inp.send_text(text) cli = CommandLineInterface( application=Application( buffer=Buffer(accept_action=AcceptAction.RETURN_DOCUMENT, history=history), editing_mode=editing_mode, clipboard=clipboard or InMemoryClipboard(), key_bindings_registry=KeyBindingManager.for_prompt().registry, ), eventloop=loop, input=inp, output=DummyOutput()) result = cli.run() return result, cli finally: loop.close() inp.close()
def setUp(self): self.input = PipeInput() output = DummyOutput() self.aws_shell = AWSShell(None, mock.Mock(), mock.Mock(), input=self.input, output=output) self.processor = self.aws_shell.cli.input_processor
class KeyBindingsTest(unittest.TestCase): def init(self): self.input = PipeInput() output = DummyOutput() # self.shell = Shell(input=self.input, output=output) self.processor = InputProcessor def tearDown(self): self.input.close()
class KeysTest(unittest.TestCase): def setUp(self): self.input = PipeInput() output = DummyOutput() self.aws_shell = AWSShell(None, mock.Mock(), mock.Mock(), input=self.input, output=output) self.processor = self.aws_shell.cli.input_processor def tearDown(self): self.input.close() def feed_key(self, key): self.processor.feed(KeyPress(key, u'')) self.processor.process_keys() def test_F2(self): match_fuzzy = self.aws_shell.model_completer.match_fuzzy self.feed_key(Keys.F2) assert match_fuzzy != self.aws_shell.model_completer.match_fuzzy def test_F3(self): enable_vi_bindings = self.aws_shell.enable_vi_bindings with self.assertRaises(InputInterrupt): self.feed_key(Keys.F3) assert enable_vi_bindings != self.aws_shell.enable_vi_bindings def test_F4(self): show_completion_columns = self.aws_shell.show_completion_columns with self.assertRaises(InputInterrupt): self.feed_key(Keys.F4) assert show_completion_columns != \ self.aws_shell.show_completion_columns def test_F5(self): show_help = self.aws_shell.show_help with self.assertRaises(InputInterrupt): self.feed_key(Keys.F5) assert show_help != self.aws_shell.show_help def test_F9(self): assert self.aws_shell.cli.current_buffer_name == u'DEFAULT_BUFFER' self.feed_key(Keys.F9) assert self.aws_shell.cli.current_buffer_name == u'clidocs' def test_F10(self): self.feed_key(Keys.F10) assert self.aws_shell.cli.is_exiting
def run_server(self): # Ignore keyboard. (When people run "pymux server" and press Ctrl-C.) # Pymux has to be terminated by termining all the processes running in # its panes. def handle_sigint(*a): print('Ignoring keyboard interrupt.') signal.signal(signal.SIGINT, handle_sigint) # Run eventloop. # XXX: Both the PipeInput and DummyCallbacks are not used. # This is a workaround to run the PosixEventLoop continuously # without having a CommandLineInterface instance. # A better API in prompt_toolkit is desired. try: self.eventloop.run(PipeInput(), DummyCallbacks()) except: # When something bad happens, always dump the traceback. # (Otherwise, when running as a daemon, and stdout/stderr are not # available, it's hard to see what went wrong.) fd, path = tempfile.mkstemp(prefix='pymux.crash-') logger.fatal( 'Pymux has crashed, dumping traceback to {0}'.format(path)) os.write(fd, traceback.format_exc().encode('utf-8')) os.close(fd) raise # Clean up socket. os.remove(self.socket_name)
class KeysTest(unittest.TestCase): def setUp(self): self.input = PipeInput() output = DummyOutput() self.aws_shell = AWSShell(None, mock.Mock(), mock.Mock(), input=self.input, output=output) self.processor = self.aws_shell.cli.input_processor def tearDown(self): self.input.close() def feed_key(self, key): self.processor.feed(KeyPress(key, u'')) self.processor.process_keys() def test_F2(self): match_fuzzy = self.aws_shell.model_completer.match_fuzzy self.feed_key(Keys.F2) assert match_fuzzy != self.aws_shell.model_completer.match_fuzzy def test_F3(self): enable_vi_bindings = self.aws_shell.enable_vi_bindings with self.assertRaises(InputInterrupt): self.feed_key(Keys.F3) assert enable_vi_bindings != self.aws_shell.enable_vi_bindings def test_F4(self): show_completion_columns = self.aws_shell.show_completion_columns with self.assertRaises(InputInterrupt): self.feed_key(Keys.F4) assert show_completion_columns != \ self.aws_shell.show_completion_columns def test_F5(self): show_help = self.aws_shell.show_help with self.assertRaises(InputInterrupt): self.feed_key(Keys.F5) assert show_help != self.aws_shell.show_help def test_F10(self): self.feed_key(Keys.F10) assert self.aws_shell.cli.is_exiting
def __init__(self, get_globals, get_locals=None): assert callable(get_globals) assert get_locals is None or callable(get_locals) self._chan = None def _globals(): data = get_globals() data.setdefault('print', self._print) return data repl = PythonRepl(get_globals=_globals, get_locals=get_locals or _globals) # Disable open-in-editor and system prompt. Because it would run and # display these commands on the server side, rather than in the SSH # client. repl.enable_open_in_editor = False repl.enable_system_bindings = False # PipInput object, for sending input in the CLI. # (This is something that we can use in the prompt_toolkit event loop, # but still write date in manually.) self._input_pipe = PipeInput() # Output object. Don't render to the real stdout, but write everything # in the SSH channel. class Stdout(object): def write(s, data): if self._chan is not None: self._chan.write(data.replace('\n', '\r\n')) def flush(s): pass # Create command line interface. self.cli = CommandLineInterface(application=repl.create_application(), eventloop=create_asyncio_eventloop(), input=self._input_pipe, output=Vt100_Output( Stdout(), self._get_size)) self._callbacks = self.cli.create_eventloop_callbacks()
def feed_app_with_input(type, message, text, **kwargs): """ Create a CommandLineInterface, feed it with the given user input and return the CLI object. This returns a (result, CLI) tuple. note: this only works if you import your prompt and then this function!! """ # If the given text doesn't end with a newline, the interface won't finish. assert text.endswith('\n') application = getattr(prompts, type).question(message, **kwargs) loop = PosixEventLoop() try: inp = PipeInput() inp.send_text(text) cli = CommandLineInterface( application=application, eventloop=loop, input=inp, output=DummyOutput()) result = cli.run() return result, cli finally: loop.close() inp.close()
def _feed_cli_with_input(text, editing_mode=EditingMode.EMACS, clipboard=None, history=None): """ Create a CommandLineInterface, feed it with the given user input and return the CLI object. This returns a (result, CLI) tuple. """ # If the given text doesn't end with a newline, the interface won't finish. assert text.endswith('\n') from prompt_toolkit.eventloop.posix import PosixEventLoop as EventLoop loop = EventLoop() try: inp = PipeInput() inp.send_text(text) cli = CommandLineInterface(application=Application( buffer=Buffer(accept_action=AcceptAction.RETURN_DOCUMENT, history=history), editing_mode=editing_mode, clipboard=clipboard or InMemoryClipboard(), key_bindings_registry=KeyBindingManager.for_prompt().registry, ), eventloop=loop, input=inp, output=DummyOutput()) result = cli.run() return result, cli finally: loop.close() inp.close()
def __init__(self, get_globals, get_locals=None): assert callable(get_globals) assert get_locals is None or callable(get_locals) self._chan = None def _globals(): data = get_globals() data.setdefault('print', self._print) return data repl = PythonRepl(get_globals=_globals, get_locals=get_locals or _globals) # Disable open-in-editor and system prompt. Because it would run and # display these commands on the server side, rather than in the SSH # client. repl.enable_open_in_editor = False repl.enable_system_bindings = False # PipInput object, for sending input in the CLI. # (This is something that we can use in the prompt_toolkit event loop, # but still write date in manually.) self._input_pipe = PipeInput() # Output object. Don't render to the real stdout, but write everything # in the SSH channel. class Stdout(object): def write(s, data): if self._chan is not None: self._chan.write(data.replace('\n', '\r\n')) def flush(s): pass # Create command line interface. self.cli = CommandLineInterface( application=repl.create_application(), eventloop=create_asyncio_eventloop(), input=self._input_pipe, output=Vt100_Output(Stdout(), self._get_size)) self._callbacks = self.cli.create_eventloop_callbacks()
def _feed_cli_with_input(text, editing_mode=EditingMode.EMACS): """ Create a CommandLineInterface, feed it with the given user input and return the CLI object. This returns a (result, CLI) tuple. """ # If the given text doesn't end with a newline, the interface won't finish. assert text.endswith('\n') loop = PosixEventLoop() try: inp = PipeInput() inp.send_text(text) cli = CommandLineInterface( application=Application(editing_mode=editing_mode), eventloop=loop, input=inp, output=DummyOutput()) result = cli.run() return result, cli finally: loop.close() inp.close()
class ReplSSHServerSession(asyncssh.SSHServerSession): """ SSH server session that runs a Python REPL. :param get_globals: callable that returns the current globals. :param get_locals: (optional) callable that returns the current locals. """ def __init__(self, get_globals, get_locals=None): assert callable(get_globals) assert get_locals is None or callable(get_locals) self._chan = None def _globals(): data = get_globals() data.setdefault('print', self._print) return data repl = PythonRepl(get_globals=_globals, get_locals=get_locals or _globals) # Disable open-in-editor and system prompt. Because it would run and # display these commands on the server side, rather than in the SSH # client. repl.enable_open_in_editor = False repl.enable_system_bindings = False # PipInput object, for sending input in the CLI. # (This is something that we can use in the prompt_toolkit event loop, # but still write date in manually.) self._input_pipe = PipeInput() # Output object. Don't render to the real stdout, but write everything # in the SSH channel. class Stdout(object): def write(s, data): if self._chan is not None: self._chan.write(data.replace('\n', '\r\n')) def flush(s): pass # Create command line interface. self.cli = CommandLineInterface( application=repl.create_application(), eventloop=create_asyncio_eventloop(), input=self._input_pipe, output=Vt100_Output(Stdout(), self._get_size)) self._callbacks = self.cli.create_eventloop_callbacks() def _get_size(self): """ Callable that returns the current `Size`, required by Vt100_Output. """ if self._chan is None: return Size(rows=20, columns=79) else: width, height, pixwidth, pixheight = self._chan.get_terminal_size() return Size(rows=height, columns=width) def connection_made(self, chan): """ Client connected, run repl in coroutine. """ self._chan = chan # Run REPL interface. f = asyncio.async(self.cli.run_async()) # Close channel when done. def done(_): chan.close() self._chan = None f.add_done_callback(done) def shell_requested(self): return True def terminal_size_changed(self, width, height, pixwidth, pixheight): """ When the terminal size changes, report back to CLI. """ self._callbacks.terminal_size_changed() def data_received(self, data, datatype): """ When data is received, send to inputstream of the CLI and repaint. """ self._input_pipe.send(data) def _print(self, *data, **kw): """ _print(self, *data, sep=' ', end='\n', file=None) Alternative 'print' function that prints back into the SSH channel. """ # Pop keyword-only arguments. (We cannot use the syntax from the # signature. Otherwise, Python2 will give a syntax error message when # installing.) sep = kw.pop('sep', ' ') end = kw.pop('end', '\n') file = kw.pop('end', None) assert not kw, 'Too many keyword-only arguments' data = sep.join(map(str, data)) self._chan.write(data + end)
def init(self): self.input = PipeInput() output = DummyOutput() # self.shell = Shell(input=self.input, output=output) self.processor = InputProcessor
class ReplSSHServerSession(asyncssh.SSHServerSession): """ SSH server session that runs a Python REPL. :param get_globals: callable that returns the current globals. :param get_locals: (optional) callable that returns the current locals. """ def __init__(self, get_globals, get_locals=None): assert callable(get_globals) assert get_locals is None or callable(get_locals) self._chan = None def _globals(): data = get_globals() data.setdefault('print', self._print) return data repl = PythonRepl(get_globals=_globals, get_locals=get_locals or _globals) # Disable open-in-editor and system prompt. Because it would run and # display these commands on the server side, rather than in the SSH # client. repl.enable_open_in_editor = False repl.enable_system_bindings = False # PipInput object, for sending input in the CLI. # (This is something that we can use in the prompt_toolkit event loop, # but still write date in manually.) self._input_pipe = PipeInput() # Output object. Don't render to the real stdout, but write everything # in the SSH channel. class Stdout(object): def write(s, data): if self._chan is not None: self._chan.write(data.replace('\n', '\r\n')) def flush(s): pass # Create command line interface. self.cli = CommandLineInterface(application=repl.create_application(), eventloop=create_asyncio_eventloop(), input=self._input_pipe, output=Vt100_Output( Stdout(), self._get_size)) self._callbacks = self.cli.create_eventloop_callbacks() def _get_size(self): """ Callable that returns the current `Size`, required by Vt100_Output. """ if self._chan is None: return Size(rows=20, columns=79) else: width, height, pixwidth, pixheight = self._chan.get_terminal_size() return Size(rows=height, columns=width) def connection_made(self, chan): """ Client connected, run repl in coroutine. """ self._chan = chan # Run REPL interface. f = asyncio.ensure_future(self.cli.run_async()) # Close channel when done. def done(_): chan.close() self._chan = None f.add_done_callback(done) def shell_requested(self): return True def terminal_size_changed(self, width, height, pixwidth, pixheight): """ When the terminal size changes, report back to CLI. """ self._callbacks.terminal_size_changed() def data_received(self, data, datatype): """ When data is received, send to inputstream of the CLI and repaint. """ self._input_pipe.send(data) def _print(self, *data, **kw): """ _print(self, *data, sep=' ', end='\n', file=None) Alternative 'print' function that prints back into the SSH channel. """ # Pop keyword-only arguments. (We cannot use the syntax from the # signature. Otherwise, Python2 will give a syntax error message when # installing.) sep = kw.pop('sep', ' ') end = kw.pop('end', '\n') _ = kw.pop('file', None) assert not kw, 'Too many keyword-only arguments' data = sep.join(map(str, data)) self._chan.write(data + end)