Pexpect
Pure Python module for spawning child applications and controlling them — automates interactive CLI programs like ssh, ftp, passwd. Current version is 4.9.0 (Nov 2023). pexpect.spawn requires Unix/Linux (uses the pty module) — not available on Windows. For Windows use pexpect.PopenSpawn instead. Low maintenance activity since 2023.
Warnings
- breaking pexpect.spawn is not available on Windows — it requires the pty module which only exists on Unix. Importing pexpect works, but calling pexpect.spawn() raises ImportError or OSError on Windows.
- breaking The async= parameter was renamed to async_= as async became a Python keyword in 3.7. Using async= raises SyntaxError on Python 3.7+.
- gotcha Without encoding='utf-8', child.before and child.after return bytes, not str. Most tutorials show str patterns but they fail with bytes. Always specify encoding at spawn time.
- gotcha pexpect.TIMEOUT and pexpect.EOF are classes, not exceptions. They are passed to expect() as patterns (expect([pexpect.EOF, pexpect.TIMEOUT])), not caught with except. Catching them with except does not work as expected.
- gotcha child.before contains output BEFORE the matched pattern. child.after contains the matched pattern itself. Output AFTER the match is buffered internally. Accessing child.before after EOF gives all remaining output.
- gotcha pexpect.screen and pexpect.ANSI modules are deprecated. Do not import from them.
Install
-
pip install pexpect
Imports
- pexpect.spawn
import pexpect # Unix/Linux only — uses pty module child = pexpect.spawn('ssh user@host', encoding='utf-8', timeout=30) # expect() returns index of matched pattern (or raises TIMEOUT/EOF) index = child.expect(['password:', 'yes/no', pexpect.EOF, pexpect.TIMEOUT]) if index == 0: child.sendline('mysecretpassword') elif index == 1: child.sendline('yes') elif index == 2: print('Connection closed (EOF)') elif index == 3: raise TimeoutError('SSH timed out') # Wait for shell prompt child.expect(r'\$') child.sendline('ls -la') child.expect(r'\$') print(child.before)
Quickstart
import pexpect
# Basic spawn with string encoding (recommended)
child = pexpect.spawn(
'python3 -c "name = input(\"Name: \"); print(f\"Hello {name}!\")"',
encoding='utf-8',
timeout=10
)
# expect() waits for a pattern, returns the index of the match
child.expect('Name: ')
child.sendline('Alice')
child.expect(pexpect.EOF) # wait for program to finish
print(child.before) # 'Hello Alice!\r\n'
# Multi-pattern expect
index = child.expect(['pattern1', 'pattern2', pexpect.EOF, pexpect.TIMEOUT])
# index 0 = matched 'pattern1'
# index 1 = matched 'pattern2'
# index 2 = EOF (process ended)
# index 3 = timeout
# Windows: use PopenSpawn (no pty, no interactive echo)
from pexpect import popen_spawn
child = popen_spawn.PopenSpawn('python --version', encoding='utf-8')
child.expect(pexpect.EOF)
print(child.before)