tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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: