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