pywinpty

repository·main·Indexed 41 days ago

https://github.com/andfoy/pywinpty

Python bindings for creating and communicating with Windows processes via pseudoterminals, supporting both the modern ConPTY interface and the legacy winpty library. Version 3.0.6-dev provides high-level interaction via PtyProcess.spawn and granular control through the PTY class for managing terminal lifecycles, resizing, and raw I/O.

Tokens
1.6K
Snippets
8
Records
9
Agent score
1%

What's inside pywinpty

  1. Install pywinpty via conda or pip

    main

    You can install pywinpty using either the conda or pip package managers.

    Recommended: Use conda for installation.

    Alternative: Use pip for installation.

    # Using conda (Recommended)
    conda install pywinpty
    
    # Using pip
    pip install pywinpty
  2. Build pywinpty from source

    main

    To build pywinpty from source, you need a stable or nightly Rust toolchain with the x86_64-pc-windows-msvc target.

    Requirements:

    1. Rust Toolchain: Install via rustup.
    2. Winpty (Optional): If you want to link against the winpty library, install it via conda-forge:
      conda install winpty -c conda-forge
      Alternatively, ensure winpty binaries and headers are available on your PATH.
    3. Maturin: Install the build backend via pip:
      pip install maturin

    Build Command: To test your compilation environment and build locally, run:

    maturin develop
  3. High level usage using PtyProcess.spawn

    main

    For most use cases, use the PtyProcess class. The spawn method allows you to start a process and interact with it using high-level methods like write and readline.

    Example of spawning a Python process, sending commands, and reading output:

    from winpty import PtyProcess
    
    proc = PtyProcess.spawn('python')
    proc.write('print("hello, world!")\r\n')
    proc.write('exit()\r\n')
    while proc.isalive():
    	print(proc.readline())
  4. Low level usage using the PTY object

    main

    For granular control, use the PTY class. This allows you to manage the pseudoterminal lifecycle, resize the console, and handle raw byte input/output.

    Key Operations:

    • Initialization: PTY(cols, rows) starts a new winpty-agent process of a specific size.
    • Spawning: process.spawn(command) starts a console process (e.g., cmd.exe) inside the PTY.
    • I/O: Use process.read() for output and process.write(bytes) for input.
    • Resizing: process.set_size(cols, rows) updates the terminal dimensions.
    • Lifecycle: process.isalive() checks status; del process ends the winpty-agent process.
    from winpty import PTY
    
    # Start a new winpty-agent process of size (cols, rows)
    cols, rows = 80, 25
    process = PTY(cols, rows)
    
    # Spawn a new console process, e.g., CMD
    process.spawn(br'C:\windows\system32\cmd.exe')
    
    # Read console output (Unicode)
    process.read()
    
    # Write input to console (Unicode)
    process.write(b'Text')
    
    # Resize console size
    new_cols, new_rows = 90, 30
    process.set_size(new_cols, new_rows)
    
    # Know if the process is alive
    alive = process.isalive()
    
    # End winpty-agent process
    del process
  5. Read and write to the PTY stream

    main

    Interact with the running process using read and write.

    • read(blocking=False): Reads text from the output stream. If blocking=True, the call will wait until the requested length is available. Warning: Use blocking=True only if the process is awaiting on a thread, otherwise it may block your application in a way that can only be interrupted by killing the process.
    • write(to_write): Sends a character sequence to the input stream. Returns the number of bytes successfully written.
    # Writing input
    pty.write('ls\r\n')
    
    # Reading output (non-blocking)
    output = pty.read(blocking=False)
  6. Manage PTY state and size

    main

    The PTY class provides methods to monitor and control the terminal session:

    • set_size(cols, rows): Resizes the terminal. Columns and rows must be non-zero and positive.
    • isalive(): Returns True if the application process is still running.
    • get_exitstatus(): Returns the exit code of the process (or None if it hasn't finished/started).
    • iseof(): Returns True if the process emitted the end-of-file escape sequence.
    • cancel_io(): Cancels all pending I/O operations.
    • pid (property): Returns the Process ID of the running process.
    • fd (property): Returns the process handle number.
  7. Initialize a pseudo-terminal with PTY

    main

    Create a new PTY instance to manage a Windows pseudoterminal. You must specify non-zero, positive values for cols (width) and rows (height).

    If backend is not provided, the library automatically selects the best available backend. Note that the ConPTY backend is preferred over WinPTY because it is native to Windows and faster.

    Certain arguments like mouse_mode, timeout, and agent_config only take effect if the Winpty backend is used.

    from pywinpty import PTY
    
    # Create a PTY with 80 columns and 24 rows
    pty = PTY(cols=80, rows=24)
  8. Spawn an application in a PTY

    main

    Use the spawn method to start an application that communicates through the initialized pseudo-terminal.

    Arguments:

    • appname: The path to the application.
    • cmdline (optional): Parameters for the application, separated by whitespace.
    • cwd (optional): The working directory. If None, it inherits the Python interpreter's current directory.
    • env (optional): Environment variables. Format: name=value pairs separated by a null character \0.
    # Example: Spawning CMD
    pty.spawn('cmd.exe', cmdline='/c dir')
  9. Handle WinptyError exceptions

    main

    Errors occurring during PTY creation, spawning, resizing, reading, writing, or status retrieval will raise a WinptyError. This exception contains the error message provided by the underlying Windows API or WinPTY agent.

    from pywinpty import WinptyError
    
    try:
        pty = PTY(cols=80, rows=24)
    except WinptyError as e:
        print(f"Failed to create PTY: {e}")