0
# Alternative Process Control
1
2
Alternative spawn implementations for different communication mechanisms. These classes provide expect-like functionality for scenarios where the standard PTY-based spawn is not suitable or available.
3
4
## Capabilities
5
6
### Subprocess-based Spawning
7
8
Process control using subprocess.Popen instead of pseudo-terminals, useful for Windows compatibility and certain Unix scenarios.
9
10
```python { .api }
11
class PopenSpawn(SpawnBase):
12
"""
13
Spawn class using subprocess.Popen for process communication.
14
15
Uses pipes instead of pseudo-terminals, making it compatible with Windows
16
and useful for scenarios where PTY behavior is not desired.
17
"""
18
19
def __init__(self, cmd, timeout=30, maxread=2000, searchwindowsize=None,
20
logfile=None, cwd=None, env=None, encoding=None,
21
codec_errors='strict', preexec_fn=None):
22
"""
23
Initialize PopenSpawn instance.
24
25
Parameters:
26
- cmd (str or list): Command to execute
27
- timeout (int): Default timeout for operations
28
- maxread (int): Maximum bytes to read at once
29
- searchwindowsize (int): Search window size for pattern matching
30
- logfile (file-like): File object for logging
31
- cwd (str): Working directory for child process
32
- env (dict): Environment variables for child process
33
- encoding (str): Text encoding for I/O operations
34
- codec_errors (str): How to handle encoding errors
35
- preexec_fn (callable): Function to call before exec (Unix only)
36
"""
37
```
38
39
### File Descriptor Control
40
41
Control existing file descriptors such as sockets, pipes, or other file-like objects with expect functionality.
42
43
```python { .api }
44
class fdspawn(SpawnBase):
45
"""
46
Spawn-like interface for existing file descriptors.
47
48
Allows expect functionality with sockets, named pipes (FIFOs),
49
or any existing file descriptor.
50
51
Note: On Windows, socket.fileno() doesn't provide a readable
52
file descriptor. Use SocketSpawn for cross-platform socket support.
53
"""
54
55
def __init__(self, fd, args=None, timeout=30, maxread=2000,
56
searchwindowsize=None, logfile=None, encoding=None,
57
codec_errors='strict', use_poll=False):
58
"""
59
Initialize fdspawn with existing file descriptor.
60
61
Parameters:
62
- fd (int): Existing file descriptor
63
- args (list): Arguments for compatibility (not used)
64
- timeout (int): Default timeout for operations
65
- maxread (int): Maximum bytes to read at once
66
- searchwindowsize (int): Search window size
67
- logfile (file-like): File object for logging
68
- encoding (str): Text encoding for I/O operations
69
- codec_errors (str): How to handle encoding errors
70
- use_poll (bool): Use poll() instead of select() for I/O
71
"""
72
73
def isalive(self):
74
"""
75
Check if file descriptor is still valid.
76
77
Returns:
78
bool: True if file descriptor is open and valid
79
"""
80
81
def close(self):
82
"""Close the file descriptor."""
83
84
def fileno(self):
85
"""
86
Get the file descriptor number.
87
88
Returns:
89
int: File descriptor number
90
"""
91
```
92
93
### Socket Communication
94
95
Cross-platform socket communication with expect functionality, particularly useful for network automation.
96
97
```python { .api }
98
class SocketSpawn(SpawnBase):
99
"""
100
Spawn-like interface for socket communication.
101
102
Provides expect functionality for socket connections,
103
useful for network protocol automation and testing.
104
"""
105
106
def __init__(self, socket, args=None, timeout=30, maxread=2000,
107
searchwindowsize=None, logfile=None, encoding=None,
108
codec_errors='strict'):
109
"""
110
Initialize SocketSpawn with existing socket.
111
112
Parameters:
113
- socket (socket.socket): Connected socket object
114
- args (list): Arguments for compatibility (not used)
115
- timeout (int): Default timeout for operations
116
- maxread (int): Maximum bytes to read at once
117
- searchwindowsize (int): Search window size
118
- logfile (file-like): File object for logging
119
- encoding (str): Text encoding for I/O operations
120
- codec_errors (str): How to handle encoding errors
121
"""
122
123
def close(self):
124
"""Close the socket connection."""
125
126
def isalive(self):
127
"""
128
Check if socket connection is still active.
129
130
Returns:
131
bool: True if socket is connected
132
"""
133
134
def fileno(self):
135
"""
136
Get the socket file descriptor.
137
138
Returns:
139
int: Socket file descriptor
140
"""
141
```
142
143
## Usage Examples
144
145
### PopenSpawn for Cross-Platform Compatibility
146
147
```python
148
from pexpect.popen_spawn import PopenSpawn
149
import sys
150
151
# PopenSpawn works on both Unix and Windows
152
if sys.platform == 'win32':
153
# Windows command
154
child = PopenSpawn('cmd.exe')
155
child.expect('>')
156
child.sendline('dir')
157
child.expect('>')
158
print(child.before.decode())
159
else:
160
# Unix command
161
child = PopenSpawn('bash')
162
child.expect('$ ')
163
child.sendline('ls -la')
164
child.expect('$ ')
165
print(child.before.decode())
166
167
child.close()
168
```
169
170
### PopenSpawn with Complex Commands
171
172
```python
173
from pexpect.popen_spawn import PopenSpawn
174
175
# Execute complex command with arguments
176
child = PopenSpawn(['python', '-c', 'print("Hello"); input("Enter: ")'])
177
178
# Wait for the input prompt
179
child.expect('Enter: ')
180
181
# Send input
182
child.sendline('World')
183
184
# Read the output
185
child.expect(pexpect.EOF)
186
output = child.before.decode()
187
print(f"Output: {output}")
188
189
child.close()
190
```
191
192
### File Descriptor Control with Named Pipes
193
194
```python
195
from pexpect.fdpexpect import fdspawn
196
import os
197
198
# Create a named pipe (FIFO)
199
pipe_path = '/tmp/test_pipe'
200
if not os.path.exists(pipe_path):
201
os.mkfifo(pipe_path)
202
203
# Open the pipe for reading/writing
204
fd = os.open(pipe_path, os.O_RDWR)
205
206
# Create fdspawn instance
207
child = fdspawn(fd)
208
209
# In another process/thread, write to the pipe
210
# For this example, we'll simulate it
211
os.write(fd, b'Hello from pipe\n')
212
213
# Use expect functionality
214
child.expect('Hello')
215
print(f"Received: {child.after.decode()}")
216
217
child.close()
218
os.unlink(pipe_path) # Clean up
219
```
220
221
### Socket Communication Example
222
223
```python
224
from pexpect.socket_pexpect import SocketSpawn
225
import socket
226
227
# Create and connect socket
228
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
229
sock.connect(('httpbin.org', 80))
230
231
# Create SocketSpawn instance
232
child = SocketSpawn(sock)
233
234
# Send HTTP request
235
child.send('GET /get HTTP/1.1\r\n')
236
child.send('Host: httpbin.org\r\n')
237
child.send('Connection: close\r\n')
238
child.send('\r\n')
239
240
# Wait for HTTP response
241
child.expect('HTTP/')
242
print("Got HTTP response header")
243
244
# Read response body
245
child.expect('200 OK')
246
child.expect('\r\n\r\n') # End of headers
247
248
# Read JSON response
249
child.expect(pexpect.EOF)
250
response_body = child.before.decode()
251
print(f"Response: {response_body}")
252
253
child.close()
254
```
255
256
### FTP Automation with Socket
257
258
```python
259
from pexpect.socket_pexpect import SocketSpawn
260
import socket
261
262
# Connect to FTP server
263
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
264
sock.connect(('ftp.example.com', 21))
265
266
child = SocketSpawn(sock)
267
268
# Wait for FTP welcome message
269
child.expect('220')
270
print("Connected to FTP server")
271
272
# Send username
273
child.sendline('USER anonymous')
274
child.expect('331') # User name okay, need password
275
276
# Send password
277
child.sendline('PASS guest@example.com')
278
child.expect('230') # User logged in
279
print("Logged in successfully")
280
281
# List directory
282
child.sendline('LIST')
283
child.expect('150') # File status okay, about to open data connection
284
child.expect('226') # Closing data connection
285
directory_listing = child.before.decode()
286
print(f"Directory listing:\n{directory_listing}")
287
288
# Quit
289
child.sendline('QUIT')
290
child.expect('221') # Service closing control connection
291
print("Disconnected from FTP server")
292
293
child.close()
294
```
295
296
### Telnet Automation with Socket
297
298
```python
299
from pexpect.socket_pexpect import SocketSpawn
300
import socket
301
302
# Connect to telnet server
303
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
304
sock.connect(('towel.blinkenlights.nl', 23)) # Star Wars ASCII movie
305
306
child = SocketSpawn(sock, encoding='utf-8')
307
308
try:
309
# Just watch the ASCII movie for a bit
310
for i in range(10): # Watch for 10 iterations
311
child.expect('\x1b[H') # ANSI clear screen sequence
312
frame = child.before
313
print(f"Frame {i+1}")
314
# Could process or display the frame here
315
316
except KeyboardInterrupt:
317
print("Stopping...")
318
319
child.close()
320
```
321
322
### Process Pipeline with fdspawn
323
324
```python
325
from pexpect.fdpexpect import fdspawn
326
import subprocess
327
import os
328
329
# Create a process pipeline
330
p1 = subprocess.Popen(['ls', '-la'], stdout=subprocess.PIPE)
331
p2 = subprocess.Popen(['grep', 'pexpect'], stdin=p1.stdout, stdout=subprocess.PIPE)
332
333
# Use fdspawn to interact with the pipeline output
334
child = fdspawn(p2.stdout.fileno())
335
336
try:
337
# Read output with expect
338
child.expect(pexpect.EOF)
339
result = child.before.decode()
340
print(f"Filtered output:\n{result}")
341
342
except pexpect.EOF:
343
# Expected when process completes
344
pass
345
346
# Clean up
347
p1.stdout.close()
348
p2.stdout.close()
349
p1.wait()
350
p2.wait()
351
child.close()
352
```
353
354
### Windows Command Automation
355
356
```python
357
from pexpect.popen_spawn import PopenSpawn
358
import sys
359
360
if sys.platform == 'win32':
361
# Windows PowerShell automation
362
child = PopenSpawn(['powershell.exe', '-Command', '-'])
363
364
# Wait for PowerShell prompt
365
child.expect('PS ')
366
367
# Execute PowerShell commands
368
child.sendline('Get-Date')
369
child.expect('PS ')
370
date_output = child.before.decode()
371
print(f"Current date: {date_output}")
372
373
child.sendline('Get-Process | Select-Object -First 5')
374
child.expect('PS ')
375
process_output = child.before.decode()
376
print(f"Top processes:\n{process_output}")
377
378
# Exit PowerShell
379
child.sendline('exit')
380
child.close()
381
382
else:
383
print("This example is for Windows only")
384
```
385
386
## Key Differences from Standard Spawn
387
388
### PopenSpawn vs spawn
389
390
- **PopenSpawn**: Uses subprocess.Popen, no PTY, works on Windows
391
- **spawn**: Uses pseudo-terminal, Unix-only, full terminal emulation
392
393
### fdspawn vs spawn
394
395
- **fdspawn**: Works with existing file descriptors, no process management
396
- **spawn**: Creates and manages child processes with PTY
397
398
### SocketSpawn vs spawn
399
400
- **SocketSpawn**: Network communication, no process involved
401
- **spawn**: Local process communication with PTY
402
403
## Choosing the Right Spawn Class
404
405
- **spawn**: Standard choice for Unix process automation
406
- **PopenSpawn**: Cross-platform compatibility, Windows support
407
- **fdspawn**: Existing file descriptors, pipes, custom I/O
408
- **SocketSpawn**: Network protocols, socket communication
409
- **pxssh**: SSH connections (uses spawn internally)