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.
Common errors
-
ModuleNotFoundError: No module named 'pexpect'
cause The pexpect module is not installed in the Python environment being used, or there's a mismatch between where pexpect was installed and the Python interpreter running the script.fixInstall pexpect using pip: `pip install pexpect`. If using virtual environments, ensure the environment is activated before installation. If multiple Python versions are present, ensure pexpect is installed for the correct version (e.g., `python3 -m pip install pexpect`). -
AttributeError: module 'pexpect' has no attribute 'spawn'
cause The `pexpect.spawn` method is not available on Windows because it relies on Unix pseudoterminals (ptys). Additionally, an outdated version of pexpect or an incorrect import statement can lead to similar `AttributeError` messages related to other attributes.fixOn Windows, use `pexpect.popen_spawn.PopenSpawn` instead of `pexpect.spawn`. For other `AttributeError` instances, ensure pexpect is up to date (`pip install --upgrade pexpect`) and that constants like `TIMEOUT` are accessed directly (e.g., `pexpect.TIMEOUT`) if imported as `import pexpect`. -
pexpect.TIMEOUT: Timeout exceeded.
cause The `expect()` method in pexpect raised a `TIMEOUT` exception because the expected pattern was not found within the specified timeout period. The default timeout is 30 seconds.fixIncrease the timeout value when calling `expect()` or `spawn()` (e.g., `child.expect('prompt', timeout=60)` or `pexpect.spawn('command', timeout=None)` for no timeout). Alternatively, include `pexpect.TIMEOUT` in the list of patterns to catch the timeout as a match index rather than an exception. -
pexpect.EOF: End Of File (EOF) in read()
cause The child process spawned by pexpect has unexpectedly exited or closed its connection, leading to an End Of File (EOF) condition before the expected pattern was matched.fixInclude `pexpect.EOF` in the list of patterns passed to `expect()` to handle the child exiting gracefully, allowing you to process any output received before the EOF. Review the child process's behavior or the commands sent to ensure it's not exiting prematurely. -
FileNotFoundError: [WinError 2] The system can't find the given file.
cause This error typically occurs on Windows when using `pexpect.popen_spawn.PopenSpawn` and the command specified as an argument cannot be found in the system's PATH. This is common for commands like 'ssh' which may not be natively in the Windows PATH without specific installations.fixProvide the full, absolute path to the executable file (e.g., `pexpect.popen_spawn.PopenSpawn('C:\Windows\System32\OpenSSH\ssh.exe ...')`) or ensure the executable's directory is correctly added to the system's PATH environment variable.
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.
- gotcha The child process terminated prematurely, likely due to an internal error (e.g., SyntaxError, unhandled exception, command not found, permissions error) or reaching its natural end of output, before the expected pattern could be found. Pexpect reports this as `pexpect.exceptions.EOF`.
- gotcha pexpect.exceptions.EOF can be raised if the child process terminates unexpectedly before the expected pattern is found. This often indicates an error or crash within the child process itself (e.g., SyntaxError, unhandled exception, program exit).
Install
-
pip install pexpect
Imports
- pexpect.spawn
# On Windows, pexpect.spawn raises ImportError — pty not available: import pexpect child = pexpect.spawn('cmd.exe') # ImportError on Windows # TIMEOUT and EOF are not exceptions to catch with except: try: child.expect('pattern') except pexpect.TIMEOUT: # TypeError — TIMEOUT is a class, use as pattern passimport 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)