Terminal Sessions¶
Vty runs a command on the remote host and streams its output. A session with a
terminal gives job control, a window size and full screen programs. A session
with pipes keeps the bytes exactly and reports a real end of input.
The module needs a POSIX host, because a terminal comes from pty and
termios.
The output call is a streaming call, so the bytes arrive as the child writes them. See interactive shell for the command line client built on this tool, or SSH multiplexing for ordinary OpenSSH clients.
- class rmote.tools.vty.Vty[source]¶
Bases:
ToolStart a command on the remote host and stream its output.
Open a session, read its output, write to it, and close it. The output call is a streaming call, so the bytes arrive as the child writes them:
key = await remote(Vty.open, ["/bin/sh"], want_pty=False) async for chunk in remote(Vty.output, key): handle(chunk) status = await remote(Vty.close, key)
Close releases the terminal and the child on every path, so a caller must call it even after a failure.
A session with pipes works on every platform. A session with a terminal needs a POSIX host for now.
- CHUNK_SIZE = 65536¶
- async static close(key)[source]¶
Release the session and return the exit status of its child.
Repeated calls are safe. A session that already ended reports its status again.
- Return type:
getint
- async static end_input(key)[source]¶
Tell the child that its input ended, and keep reading its output.
- Return type:
- last_key = 0¶
- async static open(argv=None, rows=24, cols=80, term='', env=None, cwd=None, want_pty=True, launcher='', separate_stderr=False)[source]¶
Start a command and return the key of its session.
- Parameters:
argv (
list[Text] |None) – Command and arguments. None or an empty list starts the command processor of the remote host.rows (
getint) – Terminal height in character cells.cols (
getint) – Terminal width in character cells.term (
Text) – Value of the TERM variable. An empty value keeps the environment of the remote interpreter.env (
WSGIEnvironment[Text,Text] |None) – Extra environment variables for the child.cwd (
Text|None) – Working directory of the child. None keeps the remote default.want_pty (
bool) – True gives the child a terminal, which needs a POSIX host. False gives it pipes, which work everywhere.launcher (
Text) – Source of the helper that takes the controlling terminal. The caller produces it with launcher_source(), because a transferred module has no file of its own. An empty value makes this side produce it, which works only with the file present.separate_stderr (
bool) – Keep stderr separate in pipe mode. Read it with stderr() concurrently with output() to avoid blocking the child. A terminal always combines stdout and stderr.
- Return type:
getint- Returns:
The key of the session, for the other methods.
- Raises:
OSError – The command cannot start.
NotImplementedError – A terminal was asked for on a host that has no backend for one.
- static output(key)[source]¶
Yield the output of the session until it ends.
The stream ends when the child releases its output. The exit status comes from close().
- Parameters:
key (
getint) – Key that open() returned.- Yields:
Chunks of output, in the order the child wrote them.
- async static resize(key, rows, cols)[source]¶
Report a new window size to the terminal of the session.
- Return type:
- async static shell(command='', *, rows=24, cols=80, term='', env=None, want_pty=True, launcher='')[source]¶
Run a command through the remote user’s shell, or open a login shell.
Pipe sessions keep stderr separate; read stderr() alongside output(). All other arguments have the same meaning as in open().
- Return type:
getint
Session backends¶
The tool chooses a backend from the want_pty argument. Application code uses
Vty and does not touch these classes, but their contracts explain how the end
of input and the cleanup behave.
- class rmote.tools.vty.Session[source]¶
Bases:
objectA child process on the remote host, with the descriptors it needs.
The contract holds no process object of its own, because a backend can run the child through an interface that gives none.
- async read_stderr(size)[source]¶
Read separate stderr, or EOF when it is merged into output.
- Return type:
- async release()[source]¶
End the child and release the descriptors. Return when it is done.
- Return type:
- class rmote.tools.vty.TerminalSession(process, master_fd, slave_fd)[source]¶
Bases:
ProcessSessionA child process behind a pseudo terminal.
- async end_input()[source]¶
Write the VEOF character of the terminal.
A terminal has no half close. A reader in canonical mode treats VEOF as the end of its input. A program that set raw mode gets the character as ordinary data, so this is not a general half close.
- Return type:
- end_of_input_character()[source]¶
Return the VEOF character of the terminal, or Ctrl-D.
- Return type:
- async release()[source]¶
End the child and release the descriptors. Return when it is done.
- Return type:
- resize(rows, cols)[source]¶
Apply a new window size. A session without a terminal has none.
- Return type:
- class rmote.tools.vty.PipeSession(process)[source]¶
Bases:
ProcessSessionA child process with ordinary pipes and no terminal.
A pipe has a real half close, so the end of input reaches the child exactly. The bytes pass through without terminal processing, which keeps binary data and line endings as they are. This backend works on every platform.
- async end_input()[source]¶
Close the write end of the child’s input. This is a real half close.
- Return type:
- async read_stderr(size)[source]¶
Read separate stderr, or EOF when it is merged into output.
- Return type:
Controlling terminal¶
A child needs a controlling terminal, or a shell reports that job control is
off. The helper below takes it after exec, in a fresh interpreter with one
thread. A preexec_fn would instead run Python between fork and exec in a
process that has threads, where the standard library warns about a deadlock.
- rmote.tools.vty.take_controlling_terminal(motd_paths=())[source]¶
Take the controlling terminal, then run the requested command.
The function runs as a fresh interpreter after exec, so the process has one thread and Python is safe to use. A preexec_fn would instead run Python between fork and exec in a process that has threads, where the standard library warns about a deadlock.
Descriptor 0 is the terminal, and the process is already a session leader. Without TIOCSCTTY a shell reports that job control is off.
- Return type:
- rmote.tools.vty.launcher_source(*, motd_paths=())[source]¶
Return the launcher as source that
python -ccan run.The launcher has to be a fresh interpreter, so it travels as text. The text comes from the function itself, which keeps one definition that the linter and the type checker also read. A transferred module has no file, so only the side that holds the file can produce the text.
The child displays files from motd_paths before exec. Callers must supply paths only for interactive login shells.
- Return type:
Helpers¶
- rmote.tools.vty.default_shell()[source]¶
Return the login shell of the current user, or /bin/sh.
- Return type:
- rmote.tools.vty.set_winsize(fd, rows, cols)[source]¶
Set the window size of a terminal descriptor.
- Return type: