|
1 :mod:`mozprocess` --- Launch and manage processes |
|
2 ================================================= |
|
3 |
|
4 Mozprocess is a process-handling module that provides some additional |
|
5 features beyond those available with python's subprocess: |
|
6 |
|
7 * better handling of child processes, especially on Windows |
|
8 * the ability to timeout the process after some absolute period, or some |
|
9 period without any data written to stdout/stderr |
|
10 * the ability to specify output handlers that will be called |
|
11 for each line of output produced by the process |
|
12 * the ability to specify handlers that will be called on process timeout |
|
13 and normal process termination |
|
14 |
|
15 Running a process |
|
16 ----------------- |
|
17 |
|
18 mozprocess consists of two classes: ProcessHandler inherits from ProcessHandlerMixin. |
|
19 |
|
20 Let's see how to run a process. |
|
21 First, the class should be instanciated with at least one argument which is a command (or a list formed by the command followed by its arguments). |
|
22 Then the process can be launched using the *run()* method. |
|
23 Finally the *wait()* method will wait until end of execution. |
|
24 |
|
25 .. code-block:: python |
|
26 |
|
27 from mozprocess import processhandler |
|
28 |
|
29 # under Windows replace by command = ['dir', '/a'] |
|
30 command = ['ls', '-l'] |
|
31 p = processhandler.ProcessHandler(command) |
|
32 print("execute command: %s" % p.commandline) |
|
33 p.run() |
|
34 p.wait() |
|
35 |
|
36 Note that using *ProcessHandler* instead of *ProcessHandlerMixin* will print the output of executed command. The attribute *commandline* provides the launched command. |
|
37 |
|
38 Collecting process output |
|
39 ------------------------- |
|
40 |
|
41 Let's now consider a basic shell script that will print numbers from 1 to 5 waiting 1 second between each. |
|
42 This script will be used as a command to launch in further examples. |
|
43 |
|
44 **proc_sleep_echo.sh**: |
|
45 |
|
46 .. code-block:: sh |
|
47 |
|
48 #!/bin/sh |
|
49 |
|
50 for i in 1 2 3 4 5 |
|
51 do |
|
52 echo $i |
|
53 sleep 1 |
|
54 done |
|
55 |
|
56 If you are running under Windows, you won't be able to use the previous script (unless using Cygwin). |
|
57 So you'll use the following script: |
|
58 |
|
59 **proc_sleep_echo.bat**: |
|
60 |
|
61 .. code-block:: bat |
|
62 |
|
63 @echo off |
|
64 FOR %%A IN (1 2 3 4 5) DO ( |
|
65 ECHO %%A |
|
66 REM if you have TIMEOUT then use it instead of PING |
|
67 REM TIMEOUT /T 1 /NOBREAK |
|
68 PING -n 2 127.0.0.1 > NUL |
|
69 ) |
|
70 |
|
71 Mozprocess allows the specification of custom output handlers to gather process output while running. |
|
72 ProcessHandler will by default write all outputs on stdout. You can also provide (to ProcessHandler or ProcessHandlerMixin) a function or a list of functions that will be used as callbacks on each output line generated by the process. |
|
73 |
|
74 In the following example the command's output will be stored in a file *output.log* and printed in stdout: |
|
75 |
|
76 .. code-block:: python |
|
77 |
|
78 import sys |
|
79 from mozprocess import processhandler |
|
80 |
|
81 fd = open('output.log', 'w') |
|
82 |
|
83 def tostdout(line): |
|
84 sys.stdout.write("<%s>\n" % line) |
|
85 |
|
86 def tofile(line): |
|
87 fd.write("<%s>\n" % line) |
|
88 |
|
89 # under Windows you'll replace by 'proc_sleep_echo.bat' |
|
90 command = './proc_sleep_echo.sh' |
|
91 outputs = [tostdout, tofile] |
|
92 |
|
93 p = processhandler.ProcessHandlerMixin(command, processOutputLine=outputs) |
|
94 p.run() |
|
95 p.wait() |
|
96 |
|
97 fd.close() |
|
98 |
|
99 The process output can be saved (*obj = ProcessHandler(..., storeOutput=True)*) so as it is possible to request it (*obj.output*) at any time. Note that the default value for *stroreOutput* is *True*, so it is not necessary to provide it in the parameters. |
|
100 |
|
101 .. code-block:: python |
|
102 |
|
103 import time |
|
104 import sys |
|
105 from mozprocess import processhandler |
|
106 |
|
107 command = './proc_sleep_echo.sh' # Windows: 'proc_sleep_echo.bat' |
|
108 |
|
109 p = processhandler.ProcessHandler(command, storeOutput=True) |
|
110 p.run() |
|
111 for i in xrange(10): |
|
112 print(p.output) |
|
113 time.sleep(0.5) |
|
114 p.wait() |
|
115 |
|
116 In previous example, you will see the *p.output* list growing. |
|
117 |
|
118 Execution |
|
119 --------- |
|
120 |
|
121 Status |
|
122 `````` |
|
123 |
|
124 It is possible to query the status of the process via *poll()* that will return None if the process is still running, 0 if it ended without failures and a negative value if it was killed by a signal (Unix-only). |
|
125 |
|
126 .. code-block:: python |
|
127 |
|
128 import time |
|
129 import signal |
|
130 from mozprocess import processhandler |
|
131 |
|
132 command = './proc_sleep_echo.sh' |
|
133 p = processhandler.ProcessHandler(command) |
|
134 p.run() |
|
135 time.sleep(2) |
|
136 print("poll status: %s" % p.poll()) |
|
137 time.sleep(1) |
|
138 p.kill(signal.SIGKILL) |
|
139 print("poll status: %s" % p.poll()) |
|
140 |
|
141 Timeout |
|
142 ``````` |
|
143 |
|
144 A timeout can be provided to the *run()* method. If the process last more than timeout seconds, it will be stopped. |
|
145 |
|
146 After execution, the property *timedOut* will be set to True if a timeout was reached. |
|
147 |
|
148 It is also possible to provide functions (*obj = ProcessHandler[Mixin](..., onTimeout=functions)*) that will be called if the timeout was reached. |
|
149 |
|
150 .. code-block:: python |
|
151 |
|
152 from mozprocess import processhandler |
|
153 |
|
154 def ontimeout(): |
|
155 print("REACHED TIMEOUT") |
|
156 |
|
157 command = './proc_sleep_echo.sh' # Windows: 'proc_sleep_echo.bat' |
|
158 functions = [ontimeout] |
|
159 p = processhandler.ProcessHandler(command, onTimeout=functions) |
|
160 p.run(timeout=2) |
|
161 p.wait() |
|
162 print("timedOut = %s" % p.timedOut) |
|
163 |
|
164 By default the process will be killed on timeout but it is possible to prevent this by setting *kill_on_timeout* to *False*. |
|
165 |
|
166 .. code-block:: python |
|
167 |
|
168 p = processhandler.ProcessHandler(command, onTimeout=functions, kill_on_timeout=False) |
|
169 p.run(timeout=2) |
|
170 p.wait() |
|
171 print("timedOut = %s" % p.timedOut) |
|
172 |
|
173 In this case, no output will be available after the timeout, but the process will still be running. |
|
174 |
|
175 Waiting |
|
176 ``````` |
|
177 |
|
178 It is possible to wait until the process exits as already seen with the method *wait()*, or until the end of a timeout if given. Note that in last case the process is still alive after the timeout. |
|
179 |
|
180 .. code-block:: python |
|
181 |
|
182 command = './proc_sleep_echo.sh' # Windows: 'proc_sleep_echo.bat' |
|
183 p = processhandler.ProcessHandler(command) |
|
184 p.run() |
|
185 p.wait(timeout=2) |
|
186 print("timedOut = %s" % p.timedOut) |
|
187 p.wait() |
|
188 |
|
189 Killing |
|
190 ``````` |
|
191 |
|
192 You can request to kill the process with the method *kill*. f the parameter "ignore_children" is set to False when the process handler class is initialized, all the process's children will be killed as well. |
|
193 |
|
194 Except on Windows, you can specify the signal with which to kill method the process (e.g.: *kill(signal.SIGKILL)*). |
|
195 |
|
196 .. code-block:: python |
|
197 |
|
198 import time |
|
199 from mozprocess import processhandler |
|
200 |
|
201 command = './proc_sleep_echo.sh' # Windows: 'proc_sleep_echo.bat' |
|
202 p = processhandler.ProcessHandler(command) |
|
203 p.run() |
|
204 time.sleep(2) |
|
205 p.kill() |
|
206 |
|
207 End of execution |
|
208 ```````````````` |
|
209 |
|
210 You can provide a function or a list of functions to call at the end of the process using the initilization parameter *onFinish*. |
|
211 |
|
212 .. code-block:: python |
|
213 |
|
214 from mozprocess import processhandler |
|
215 |
|
216 def finish(): |
|
217 print("Finished!!") |
|
218 |
|
219 command = './proc_sleep_echo.sh' # Windows: 'proc_sleep_echo.bat' |
|
220 |
|
221 p = processhandler.ProcessHandler(command, onFinish=finish) |
|
222 p.run() |
|
223 p.wait() |
|
224 |
|
225 Child management |
|
226 ---------------- |
|
227 |
|
228 Consider the following scripts: |
|
229 |
|
230 **proc_child.sh**: |
|
231 |
|
232 .. code-block:: sh |
|
233 |
|
234 #!/bin/sh |
|
235 for i in a b c d e |
|
236 do |
|
237 echo $i |
|
238 sleep 1 |
|
239 done |
|
240 |
|
241 **proc_parent.sh**: |
|
242 |
|
243 .. code-block:: sh |
|
244 |
|
245 #!/bin/sh |
|
246 ./proc_child.sh |
|
247 for i in 1 2 3 4 5 |
|
248 do |
|
249 echo $i |
|
250 sleep 1 |
|
251 done |
|
252 |
|
253 For windows users consider: |
|
254 |
|
255 **proc_child.bat**: |
|
256 |
|
257 .. code-block:: bat |
|
258 |
|
259 @echo off |
|
260 FOR %%A IN (a b c d e) DO ( |
|
261 ECHO %%A |
|
262 REM TIMEOUT /T 1 /NOBREAK |
|
263 PING -n 2 127.0.0.1 > NUL |
|
264 ) |
|
265 |
|
266 **proc_parent.bat**: |
|
267 |
|
268 .. code-block:: bat |
|
269 |
|
270 @echo off |
|
271 call proc_child.bat |
|
272 FOR %%A IN (1 2 3 4 5) DO ( |
|
273 ECHO %%A |
|
274 REM TIMEOUT /T 1 /NOBREAK |
|
275 PING -n 2 127.0.0.1 > NUL |
|
276 ) |
|
277 |
|
278 For processes that launch other processes, mozprocess allows you to get child running status, wait for child termination, and kill children. |
|
279 |
|
280 Ignoring children |
|
281 ````````````````` |
|
282 |
|
283 By default the *ignore_children* option is False. In that case, killing the main process will kill all its children at the same time. |
|
284 |
|
285 .. code-block:: python |
|
286 |
|
287 import time |
|
288 from mozprocess import processhandler |
|
289 |
|
290 def finish(): |
|
291 print("Finished") |
|
292 |
|
293 command = './proc_parent.sh' |
|
294 p = processhandler.ProcessHandler(command, ignore_children=False, onFinish=finish) |
|
295 p.run() |
|
296 time.sleep(2) |
|
297 print("kill") |
|
298 p.kill() |
|
299 |
|
300 If *ignore_children* is set to *True*, killing will apply only to the main process that will wait children end of execution before stoping (join). |
|
301 |
|
302 .. code-block:: python |
|
303 |
|
304 import time |
|
305 from mozprocess import processhandler |
|
306 |
|
307 def finish(): |
|
308 print("Finished") |
|
309 |
|
310 command = './proc_parent.sh' |
|
311 p = processhandler.ProcessHandler(command, ignore_children=True, onFinish=finish) |
|
312 p.run() |
|
313 time.sleep(2) |
|
314 print("kill") |
|
315 p.kill() |
|
316 |
|
317 API Documentation |
|
318 ----------------- |
|
319 |
|
320 .. module:: mozprocess |
|
321 .. autoclass:: ProcessHandlerMixin |
|
322 :members: __init__, timedOut, commandline, run, kill, processOutputLine, onTimeout, onFinish, wait |
|
323 .. autoclass:: ProcessHandler |
|
324 :members: |