ptyprocess

repository·master·Indexed 42 days ago

https://github.com/pexpect/ptyprocess

A library for launching subprocesses in a pseudo terminal (pty), enabling interaction with programs that require a terminal environment, such as those using curses or those that behave differently when detecting a pipe instead of a TTY. It provides the PtyProcess class for byte-based interaction and PtyProcessUnicode for string-based interaction, allowing developers to control terminal settings like echo, window size, and control signals.

Tokens
3.4K
Snippets
13
Records
20
Agent score
54%

What's inside ptyprocess

  1. Overview of ptyprocess

    master
    ptyprocess allows you to launch a subprocess in a pseudo terminal (pty) and interact with both the process and its pty. This is useful for automating processes that require a terminal environment, such as those with password prompts that bypass stdin, output that changes when piped, or curses-style terminal interfaces.
  2. Understand the difference between a PTY and a Pipe

    master

    A pseudo-terminal (pty) is a kernel-level object that allows bidirectional data flow through a single interface.

    Key differences from standard pipes (like those used with subprocess.Popen):

    • Bidirectional Communication: Unlike a pipe which typically requires separate streams for stdin, stdout, and stderr, a single pty connects all three standard streams of a child process.
    • Terminal Awareness: Programs using isatty() will detect a pty and switch to 'interactive' mode. This means they may format output differently (e.g., ls using columns) or prompt for user confirmation, whereas they would behave differently when connected to a standard pipe.
    • Window Management: A pty tracks window size (rows and columns) and sends a SIGWINCH signal to child processes when the size changes.
    • Cooked Mode: In cooked mode, the pty processes input data. For example, sending the byte 03 (Ctrl-C) will cause the pty to send a SIGINT signal to the child process.
  3. Basic usage of PtyProcessUnicode

    master

    To interact with a subprocess using a pseudo terminal, use PtyProcessUnicode.spawn() to launch the process. You can then use .read(n) to read up to n characters from the terminal and .write(string) to send input to the process.

    from ptyprocess import PtyProcessUnicode
    
    # Launch a subprocess (e.g., the python interpreter)
    p = PtyProcessUnicode.spawn(['python'])
    
    # Read characters from the pty
    p.read(20)
    
    # Write input to the process
    p.write('6+6\n')
    
    # Read the result
    p.read(20)
  4. Control terminal signals and EOF in PtyProcess

    master

    You can send specific control signals to the subprocess using these methods:

    • sendcontrol(char): Sends a control character.
    • sendeof(): Sends an End-Of-File (EOF) signal.
    • sendintr(): Sends an interrupt signal (equivalent to Ctrl-C).
  5. Manage terminal echo settings in PtyProcess

    master

    To control whether characters sent to the terminal are echoed back, use:

    • getecho(): Returns the current echo state.
    • setecho(bool): Sets the echo state.
    • waitnoecho(): Waits for the terminal to stop echoing.
  6. Monitor and manage process lifecycle in PtyProcess

    master

    Use these methods to check the status or terminate the subprocess:

    • eof(): Returns True if the EOF has been reached.
    • isalive(): Returns True if the process is still running.
    • wait(): Waits for the process to exit.
    • kill(): Kills the process.
    • terminate(): Terminates the process.
    • close(): Closes the connection to the process.
  7. Use the PtyProcess class to interact with subprocesses

    master

    The PtyProcess class is the primary interface for launching a subprocess in a pseudo-terminal (pty) and interacting with its standard input and output. You can use it to spawn processes, read/write data, and control terminal settings like echo and window size.

    import ptyprocess
    
    # Example usage pattern
    process = ptyprocess.PtyProcess.spawn('/bin/bash')
    process.write('ls\n')
    output = process.read(1024)
    process.close()
  8. Read and write data using PtyProcess

    master

    The PtyProcess class provides methods to interact with the subprocess via its pseudo-terminal using bytes.

    • write(s, flush=True): Writes bytes s to the pseudoterminal. Returns the number of bytes written.
    • read(size=1024): Reads up to size bytes from the pty. This is a blocking call. Raises EOFError if the terminal is closed.
    • readline(): Reads one line from the pseudoterminal and returns it as bytes. This is a blocking call. Raises EOFError if the terminal is closed.
    • sendcontrol(char): Helper to send control characters (e.g., child.sendcontrol('g') for Ctrl-G).
    • sendeof(): Sends an EOF character (typically Ctrl-D).
    • sendintr(): Sends an interrupt character (typically Ctrl-C).
    # Writing bytes
    child.write(b'hello\n')
    
    # Reading bytes
    data = child.read(1024)
    line = child.readline()
    
    # Sending control characters
    child.sendcontrol('c')  # Sends Ctrl-C
  9. Spawn a subprocess with PtyProcess.spawn()

    master

    The PtyProcess.spawn() class method is the primary way to start a command in a pseudo-terminal. It handles the fork/exec logic and returns an instance of PtyProcess that you can use to interact with the child process.

    Parameters:

    • argv: A list or tuple of strings representing the command and its arguments.
    • cwd: (Optional) The directory to launch the process in.
    • env: (Optional) A dictionary of environment variables.
    • echo: (Optional) Boolean indicating whether to enable terminal echo. Defaults to True.
    • preexec_fn: (Optional) A function to be called in the child process before exec().
    • dimensions: (Optional) A tuple (rows, cols) for the terminal size. Defaults to (24, 80).
    • pass_fds: (Optional) A list of file descriptors to keep open in the child process.

    Note: If exec() fails, spawn() will raise the corresponding OSError in the parent process.

    from ptyprocess import PtyProcess
    
    # Example: Spawning a simple shell
    child = PtyProcess.spawn(['/bin/bash'])
    
    # You can then interact with it
    child.write(b'ls\n')
    print(child.read(1024))