| :mod:`mozprocess` --- Launch and manage processes |
| ================================================= |
| |
| Mozprocess is a process-handling module that provides some additional |
| features beyond those available with python's subprocess: |
| |
| * better handling of child processes, especially on Windows |
| * the ability to timeout the process after some absolute period, or some |
| period without any data written to stdout/stderr |
| * the ability to specify output handlers that will be called |
| for each line of output produced by the process |
| * the ability to specify handlers that will be called on process timeout |
| and normal process termination |
| |
| Running a process |
| ----------------- |
| |
| mozprocess consists of two classes: ProcessHandler inherits from ProcessHandlerMixin. |
| |
| Let's see how to run a process. |
| 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). |
| Then the process can be launched using the *run()* method. |
| Finally the *wait()* method will wait until end of execution. |
| |
| .. code-block:: python |
| |
| from mozprocess import processhandler |
| |
| # under Windows replace by command = ['dir', '/a'] |
| command = ['ls', '-l'] |
| p = processhandler.ProcessHandler(command) |
| print("execute command: %s" % p.commandline) |
| p.run() |
| p.wait() |
| |
| Note that using *ProcessHandler* instead of *ProcessHandlerMixin* will print the output of executed command. The attribute *commandline* provides the launched command. |
| |
| Collecting process output |
| ------------------------- |
| |
| Let's now consider a basic shell script that will print numbers from 1 to 5 waiting 1 second between each. |
| This script will be used as a command to launch in further examples. |
| |
| **proc_sleep_echo.sh**: |
| |
| .. code-block:: sh |
| |
| #!/bin/sh |
| |
| for i in 1 2 3 4 5 |
| do |
| echo $i |
| sleep 1 |
| done |
| |
| If you are running under Windows, you won't be able to use the previous script (unless using Cygwin). |
| So you'll use the following script: |
| |
| **proc_sleep_echo.bat**: |
| |
| .. code-block:: bat |
| |
| @echo off |
| FOR %%A IN (1 2 3 4 5) DO ( |
| ECHO %%A |
| REM if you have TIMEOUT then use it instead of PING |
| REM TIMEOUT /T 1 /NOBREAK |
| PING -n 2 127.0.0.1 > NUL |
| ) |
| |
| Mozprocess allows the specification of custom output handlers to gather process output while running. |
| 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. |
| |
| In the following example the command's output will be stored in a file *output.log* and printed in stdout: |
| |
| .. code-block:: python |
| |
| import sys |
| from mozprocess import processhandler |
| |
| fd = open('output.log', 'w') |
| |
| def tostdout(line): |
| sys.stdout.write("<%s>\n" % line) |
| |
| def tofile(line): |
| fd.write("<%s>\n" % line) |
| |
| # under Windows you'll replace by 'proc_sleep_echo.bat' |
| command = './proc_sleep_echo.sh' |
| outputs = [tostdout, tofile] |
| |
| p = processhandler.ProcessHandlerMixin(command, processOutputLine=outputs) |
| p.run() |
| p.wait() |
| |
| fd.close() |
| |
| 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. |
| |
| .. code-block:: python |
| |
| import time |
| import sys |
| from mozprocess import processhandler |
| |
| command = './proc_sleep_echo.sh' # Windows: 'proc_sleep_echo.bat' |
| |
| p = processhandler.ProcessHandler(command, storeOutput=True) |
| p.run() |
| for i in xrange(10): |
| print(p.output) |
| time.sleep(0.5) |
| p.wait() |
| |
| In previous example, you will see the *p.output* list growing. |
| |
| Execution |
| --------- |
| |
| Status |
| `````` |
| |
| 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). |
| |
| .. code-block:: python |
| |
| import time |
| import signal |
| from mozprocess import processhandler |
| |
| command = './proc_sleep_echo.sh' |
| p = processhandler.ProcessHandler(command) |
| p.run() |
| time.sleep(2) |
| print("poll status: %s" % p.poll()) |
| time.sleep(1) |
| p.kill(signal.SIGKILL) |
| print("poll status: %s" % p.poll()) |
| |
| Timeout |
| ``````` |
| |
| A timeout can be provided to the *run()* method. If the process last more than timeout seconds, it will be stopped. |
| |
| After execution, the property *timedOut* will be set to True if a timeout was reached. |
| |
| It is also possible to provide functions (*obj = ProcessHandler[Mixin](..., onTimeout=functions)*) that will be called if the timeout was reached. |
| |
| .. code-block:: python |
| |
| from mozprocess import processhandler |
| |
| def ontimeout(): |
| print("REACHED TIMEOUT") |
| |
| command = './proc_sleep_echo.sh' # Windows: 'proc_sleep_echo.bat' |
| functions = [ontimeout] |
| p = processhandler.ProcessHandler(command, onTimeout=functions) |
| p.run(timeout=2) |
| p.wait() |
| print("timedOut = %s" % p.timedOut) |
| |
| By default the process will be killed on timeout but it is possible to prevent this by setting *kill_on_timeout* to *False*. |
| |
| .. code-block:: python |
| |
| p = processhandler.ProcessHandler(command, onTimeout=functions, kill_on_timeout=False) |
| p.run(timeout=2) |
| p.wait() |
| print("timedOut = %s" % p.timedOut) |
| |
| In this case, no output will be available after the timeout, but the process will still be running. |
| |
| Waiting |
| ``````` |
| |
| 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. |
| |
| .. code-block:: python |
| |
| command = './proc_sleep_echo.sh' # Windows: 'proc_sleep_echo.bat' |
| p = processhandler.ProcessHandler(command) |
| p.run() |
| p.wait(timeout=2) |
| print("timedOut = %s" % p.timedOut) |
| p.wait() |
| |
| Killing |
| ``````` |
| |
| 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. |
| |
| Except on Windows, you can specify the signal with which to kill method the process (e.g.: *kill(signal.SIGKILL)*). |
| |
| .. code-block:: python |
| |
| import time |
| from mozprocess import processhandler |
| |
| command = './proc_sleep_echo.sh' # Windows: 'proc_sleep_echo.bat' |
| p = processhandler.ProcessHandler(command) |
| p.run() |
| time.sleep(2) |
| p.kill() |
| |
| End of execution |
| ```````````````` |
| |
| You can provide a function or a list of functions to call at the end of the process using the initilization parameter *onFinish*. |
| |
| .. code-block:: python |
| |
| from mozprocess import processhandler |
| |
| def finish(): |
| print("Finished!!") |
| |
| command = './proc_sleep_echo.sh' # Windows: 'proc_sleep_echo.bat' |
| |
| p = processhandler.ProcessHandler(command, onFinish=finish) |
| p.run() |
| p.wait() |
| |
| Child management |
| ---------------- |
| |
| Consider the following scripts: |
| |
| **proc_child.sh**: |
| |
| .. code-block:: sh |
| |
| #!/bin/sh |
| for i in a b c d e |
| do |
| echo $i |
| sleep 1 |
| done |
| |
| **proc_parent.sh**: |
| |
| .. code-block:: sh |
| |
| #!/bin/sh |
| ./proc_child.sh |
| for i in 1 2 3 4 5 |
| do |
| echo $i |
| sleep 1 |
| done |
| |
| For windows users consider: |
| |
| **proc_child.bat**: |
| |
| .. code-block:: bat |
| |
| @echo off |
| FOR %%A IN (a b c d e) DO ( |
| ECHO %%A |
| REM TIMEOUT /T 1 /NOBREAK |
| PING -n 2 127.0.0.1 > NUL |
| ) |
| |
| **proc_parent.bat**: |
| |
| .. code-block:: bat |
| |
| @echo off |
| call proc_child.bat |
| FOR %%A IN (1 2 3 4 5) DO ( |
| ECHO %%A |
| REM TIMEOUT /T 1 /NOBREAK |
| PING -n 2 127.0.0.1 > NUL |
| ) |
| |
| For processes that launch other processes, mozprocess allows you to get child running status, wait for child termination, and kill children. |
| |
| Ignoring children |
| ````````````````` |
| |
| By default the *ignore_children* option is False. In that case, killing the main process will kill all its children at the same time. |
| |
| .. code-block:: python |
| |
| import time |
| from mozprocess import processhandler |
| |
| def finish(): |
| print("Finished") |
| |
| command = './proc_parent.sh' |
| p = processhandler.ProcessHandler(command, ignore_children=False, onFinish=finish) |
| p.run() |
| time.sleep(2) |
| print("kill") |
| p.kill() |
| |
| 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). |
| |
| .. code-block:: python |
| |
| import time |
| from mozprocess import processhandler |
| |
| def finish(): |
| print("Finished") |
| |
| command = './proc_parent.sh' |
| p = processhandler.ProcessHandler(command, ignore_children=True, onFinish=finish) |
| p.run() |
| time.sleep(2) |
| print("kill") |
| p.kill() |
| |
| API Documentation |
| ----------------- |
| |
| .. module:: mozprocess |
| .. autoclass:: ProcessHandlerMixin |
| :members: __init__, timedOut, commandline, run, kill, processOutputLine, onTimeout, onFinish, wait |
| .. autoclass:: ProcessHandler |
| :members: |