0
# Subprocess Command Execution
1
2
Invoke provides powerful subprocess execution capabilities through contexts and runners, with support for various execution strategies, output capture, error handling, and interactive features.
3
4
## Capabilities
5
6
### Top-level Convenience Functions
7
8
Simple command execution functions for common use cases.
9
10
```python { .api }
11
def run(command: str, **kwargs):
12
"""
13
Run command in a subprocess and return a Result object.
14
15
This is a convenience wrapper around Context().run().
16
17
Parameters:
18
- command (str): Shell command to execute
19
- **kwargs: Additional execution options (see Context.run)
20
21
Returns:
22
Result: Command execution result
23
"""
24
25
def sudo(command: str, **kwargs):
26
"""
27
Run command in a sudo subprocess and return a Result object.
28
29
This is a convenience wrapper around Context().sudo().
30
31
Parameters:
32
- command (str): Shell command to execute with sudo
33
- **kwargs: Additional execution options (see Context.sudo)
34
35
Returns:
36
Result: Command execution result
37
"""
38
```
39
40
Usage example:
41
42
```python
43
from invoke import run, sudo
44
45
# Basic command execution
46
result = run("ls -la")
47
print(result.stdout)
48
49
# Sudo execution
50
result = sudo("systemctl restart nginx", pty=True)
51
```
52
53
### Context Class
54
55
Main execution context providing subprocess management and configuration.
56
57
```python { .api }
58
class Context:
59
"""
60
Execution context providing command running and configuration management.
61
62
Attributes:
63
- config (Config): Configuration object
64
- cwd (str): Current working directory
65
"""
66
67
def __init__(self, config=None):
68
"""
69
Initialize Context.
70
71
Parameters:
72
- config (Config, optional): Configuration object
73
"""
74
75
def run(self, command, **kwargs):
76
"""
77
Execute a shell command via the configured runner.
78
79
Parameters:
80
- command (str): Shell command to execute
81
- asynchronous (bool): Execute in background and return Promise
82
- disown (bool): Fully detach subprocess (implies asynchronous=True)
83
- echo (bool): Print command before execution
84
- encoding (str): Text encoding for I/O streams
85
- env (dict): Environment variables
86
- err_stream (file-like): Stream for stderr output
87
- hide (bool/str): Hide stdout/stderr ('stdout', 'stderr', 'both', True)
88
- in_stream (file-like): Stream for stdin input
89
- out_stream (file-like): Stream for stdout output
90
- pty (bool): Use a pseudo-terminal
91
- replace_env (bool): Replace entire environment vs updating
92
- shell (str): Shell to use for execution
93
- timeout (float): Command timeout in seconds
94
- warn (bool): Don't raise exceptions on non-zero exit
95
- watchers (list): Stream watchers for interaction
96
97
Returns:
98
Result or Promise: Command execution result
99
"""
100
101
def sudo(self, command, **kwargs):
102
"""
103
Execute a shell command via sudo.
104
105
Parameters:
106
- command (str): Command to execute with sudo
107
- password (str): Sudo password (will prompt if not provided)
108
- user (str): User to sudo as (default: root)
109
- **kwargs: Additional options (same as run())
110
111
Returns:
112
Result or Promise: Command execution result
113
"""
114
115
def cd(self, path):
116
"""
117
Context manager for temporarily changing working directory.
118
119
Parameters:
120
- path (str): Directory path to change to
121
122
Returns:
123
context manager: Directory change context
124
"""
125
126
def prefix(self, command):
127
"""
128
Context manager for prefixing commands.
129
130
Parameters:
131
- command (str): Command prefix to apply
132
133
Returns:
134
context manager: Command prefix context
135
"""
136
```
137
138
### MockContext Class
139
140
Testing mock context for simulating command execution.
141
142
```python { .api }
143
class MockContext(Context):
144
"""
145
Mock context for testing, allowing predefined command results.
146
147
Attributes:
148
- config (Config): Configuration object
149
"""
150
151
def set_result_for(self, command, result):
152
"""
153
Set expected result for a command.
154
155
Parameters:
156
- command (str): Command string to mock
157
- result (Result): Result to return
158
"""
159
```
160
161
### Runner Classes
162
163
Pluggable command execution strategies.
164
165
```python { .api }
166
class Runner:
167
"""
168
Abstract base class for command runners.
169
170
Attributes:
171
- context (Context): Associated context
172
- shell (str): Shell to use for execution
173
- echo (bool): Whether to echo commands
174
- encoding (str): Text encoding for streams
175
"""
176
177
def run(self, command, **kwargs):
178
"""
179
Execute command and return result.
180
181
Parameters:
182
- command (str): Command to execute
183
- **kwargs: Execution options
184
185
Returns:
186
Result: Execution result
187
"""
188
189
class Local(Runner):
190
"""
191
Local subprocess command runner.
192
193
Executes commands on the local machine using subprocess.Popen.
194
"""
195
196
def start(self, command, shell, env):
197
"""
198
Start subprocess for command execution.
199
200
Parameters:
201
- command (str): Command to execute
202
- shell (str): Shell to use
203
- env (dict): Environment variables
204
205
Returns:
206
subprocess.Popen: Started subprocess
207
"""
208
209
def wait(self):
210
"""
211
Wait for subprocess completion.
212
213
Returns:
214
int: Process return code
215
"""
216
```
217
218
### Result Classes
219
220
Command execution results and promises.
221
222
```python { .api }
223
class Result:
224
"""
225
Command execution result.
226
227
Attributes:
228
- return_code (int): Command exit code
229
- stdout (str): Standard output
230
- stderr (str): Standard error
231
- ok (bool): True if return_code == 0
232
- failed (bool): True if return_code != 0
233
- shell (str): Shell used for execution
234
- command (str): Executed command
235
- encoding (str): Text encoding used
236
"""
237
238
def __init__(self, stdout="", stderr="", encoding=None, command="", shell="", return_code=0, pty=False):
239
"""
240
Initialize Result.
241
242
Parameters:
243
- stdout (str): Standard output
244
- stderr (str): Standard error
245
- encoding (str): Text encoding
246
- command (str): Executed command
247
- shell (str): Shell used
248
- return_code (int): Exit code
249
- pty (bool): Whether PTY was used
250
"""
251
252
def tail(self, stream, count=10):
253
"""
254
Get last N lines from output stream.
255
256
Parameters:
257
- stream (str): Stream name ('stdout' or 'stderr')
258
- count (int): Number of lines
259
260
Returns:
261
str: Last N lines
262
"""
263
264
class Promise(Result):
265
"""
266
Asynchronous execution promise.
267
268
Provides access to running subprocess while it executes.
269
"""
270
271
def join(self, timeout=None):
272
"""
273
Wait for subprocess completion.
274
275
Parameters:
276
- timeout (float, optional): Wait timeout
277
278
Returns:
279
Result: Final execution result
280
"""
281
282
def __enter__(self):
283
"""Context manager entry."""
284
return self
285
286
def __exit__(self, *args):
287
"""Context manager exit."""
288
self.join()
289
290
class Failure:
291
"""
292
Command execution failure representation.
293
294
Attributes:
295
- result (Result): Associated result object
296
- reason (str): Failure reason
297
"""
298
```
299
300
## Usage Examples
301
302
### Basic Command Execution
303
304
```python
305
from invoke import Context, run
306
307
# Using convenience function
308
result = run("echo 'Hello World'")
309
print(f"Output: {result.stdout}")
310
print(f"Exit code: {result.return_code}")
311
print(f"Success: {result.ok}")
312
313
# Using context
314
ctx = Context()
315
result = ctx.run("ls -la")
316
if result.failed:
317
print("Command failed!")
318
```
319
320
### Advanced Execution Options
321
322
```python
323
from invoke import Context
324
325
ctx = Context()
326
327
# Hide output
328
result = ctx.run("make build", hide=True)
329
330
# Use PTY for interactive commands
331
result = ctx.run("ssh user@host", pty=True)
332
333
# Set timeout
334
try:
335
result = ctx.run("long-running-command", timeout=30)
336
except CommandTimedOut:
337
print("Command timed out!")
338
339
# Don't raise on failure
340
result = ctx.run("might-fail", warn=True)
341
if result.failed:
342
print(f"Command failed with code {result.return_code}")
343
```
344
345
### Environment and Working Directory
346
347
```python
348
from invoke import Context
349
350
ctx = Context()
351
352
# Set environment variables
353
result = ctx.run("echo $MY_VAR", env={'MY_VAR': 'hello'})
354
355
# Change working directory
356
with ctx.cd('/tmp'):
357
result = ctx.run("pwd") # Shows /tmp
358
359
# Use command prefixes
360
with ctx.prefix('source venv/bin/activate'):
361
result = ctx.run("python --version")
362
```
363
364
### Asynchronous Execution
365
366
```python
367
from invoke import Context
368
369
ctx = Context()
370
371
# Background execution
372
promise = ctx.run("long-task", asynchronous=True)
373
print("Task started, doing other work...")
374
375
# Check if complete
376
if promise.join(timeout=1): # Wait 1 second
377
print("Task completed:", promise.stdout)
378
else:
379
print("Task still running...")
380
381
# Context manager usage
382
with ctx.run("background-task", asynchronous=True) as promise:
383
# Do other work
384
pass
385
# Automatically waits for completion on exit
386
```
387
388
### Error Handling
389
390
```python
391
from invoke import Context, UnexpectedExit
392
393
ctx = Context()
394
395
try:
396
result = ctx.run("false") # Command that returns 1
397
except UnexpectedExit as e:
398
print(f"Command failed: {e.result.return_code}")
399
print(f"Stderr: {e.result.stderr}")
400
401
# Or use warn=True to avoid exceptions
402
result = ctx.run("false", warn=True)
403
if result.failed:
404
print("Command failed but didn't raise exception")
405
```
406
407
### Testing with MockContext
408
409
```python
410
from invoke import MockContext, Result
411
412
# Create mock context
413
ctx = MockContext()
414
415
# Set up expected results
416
ctx.set_result_for("echo hello", Result(stdout="hello\n"))
417
418
# Use in tests
419
result = ctx.run("echo hello")
420
assert result.stdout == "hello\n"
421
```