OLD | NEW |
(Empty) | |
| 1 [mozprocess](https://github.com/mozilla/mozbase/tree/master/mozprocess) |
| 2 provides python process management via an operating system |
| 3 and platform transparent interface to Mozilla platforms of interest. |
| 4 Mozprocess aims to provide the ability |
| 5 to robustly terminate a process (by timeout or otherwise), along with |
| 6 any child processes, on Windows, OS X, and Linux. Mozprocess utilizes |
| 7 and extends `subprocess.Popen` to these ends. |
| 8 |
| 9 |
| 10 # API |
| 11 |
| 12 [mozprocess.processhandler:ProcessHandler](https://github.com/mozilla/mozbase/bl
ob/master/mozprocess/mozprocess/processhandler.py) |
| 13 is the central exposed API for mozprocess. `ProcessHandler` utilizes |
| 14 a contained subclass of [subprocess.Popen](http://docs.python.org/library/subpro
cess.html), |
| 15 `Process`, which does the brunt of the process management. |
| 16 |
| 17 ## Basic usage |
| 18 |
| 19 process = ProcessHandler(['command', '-line', 'arguments'], |
| 20 cwd=None, # working directory for cmd; defaults to
None |
| 21 env={}, # environment to use for the process; def
aults to os.environ |
| 22 ) |
| 23 process.run(timeout=60) # seconds |
| 24 process.wait() |
| 25 |
| 26 `ProcessHandler` offers several other properties and methods as part of its API: |
| 27 |
| 28 def __init__(self, |
| 29 cmd, |
| 30 args=None, |
| 31 cwd=None, |
| 32 env=None, |
| 33 ignore_children = False, |
| 34 processOutputLine=(), |
| 35 onTimeout=(), |
| 36 onFinish=(), |
| 37 **kwargs): |
| 38 """ |
| 39 cmd = Command to run |
| 40 args = array of arguments (defaults to None) |
| 41 cwd = working directory for cmd (defaults to None) |
| 42 env = environment to use for the process (defaults to os.environ) |
| 43 ignore_children = when True, causes system to ignore child processes, |
| 44 defaults to False (which tracks child processes) |
| 45 processOutputLine = handlers to process the output line |
| 46 onTimeout = handlers for timeout event |
| 47 kwargs = keyword args to pass directly into Popen |
| 48 |
| 49 NOTE: Child processes will be tracked by default. If for any reason |
| 50 we are unable to track child processes and ignore_children is set to Fal
se, |
| 51 then we will fall back to only tracking the root process. The fallback |
| 52 will be logged. |
| 53 """ |
| 54 |
| 55 @property |
| 56 def timedOut(self): |
| 57 """True if the process has timed out.""" |
| 58 |
| 59 |
| 60 def run(self, timeout=None, outputTimeout=None): |
| 61 """ |
| 62 Starts the process. |
| 63 |
| 64 If timeout is not None, the process will be allowed to continue for |
| 65 that number of seconds before being killed. |
| 66 |
| 67 If outputTimeout is not None, the process will be allowed to continue |
| 68 for that number of seconds without producing any output before |
| 69 being killed. |
| 70 """ |
| 71 |
| 72 def kill(self): |
| 73 """ |
| 74 Kills the managed process and if you created the process with |
| 75 'ignore_children=False' (the default) then it will also |
| 76 also kill all child processes spawned by it. |
| 77 If you specified 'ignore_children=True' when creating the process, |
| 78 only the root process will be killed. |
| 79 |
| 80 Note that this does not manage any state, save any output etc, |
| 81 it immediately kills the process. |
| 82 """ |
| 83 |
| 84 def readWithTimeout(self, f, timeout): |
| 85 """ |
| 86 Try to read a line of output from the file object |f|. |
| 87 |f| must be a pipe, like the |stdout| member of a subprocess.Popen |
| 88 object created with stdout=PIPE. If no output |
| 89 is received within |timeout| seconds, return a blank line. |
| 90 Returns a tuple (line, did_timeout), where |did_timeout| is True |
| 91 if the read timed out, and False otherwise. |
| 92 |
| 93 Calls a private member because this is a different function based on |
| 94 the OS |
| 95 """ |
| 96 |
| 97 def processOutputLine(self, line): |
| 98 """Called for each line of output that a process sends to stdout/stderr.
""" |
| 99 for handler in self.processOutputLineHandlers: |
| 100 handler(line) |
| 101 |
| 102 def onTimeout(self): |
| 103 """Called when a process times out.""" |
| 104 for handler in self.onTimeoutHandlers: |
| 105 handler() |
| 106 |
| 107 def onFinish(self): |
| 108 """Called when a process finishes without a timeout.""" |
| 109 for handler in self.onFinishHandlers: |
| 110 handler() |
| 111 |
| 112 def wait(self, timeout=None): |
| 113 """ |
| 114 Waits until all output has been read and the process is |
| 115 terminated. |
| 116 |
| 117 If timeout is not None, will return after timeout seconds. |
| 118 This timeout only causes the wait function to return and |
| 119 does not kill the process. |
| 120 """ |
| 121 |
| 122 See https://github.com/mozilla/mozbase/blob/master/mozprocess/mozprocess/process
handler.py |
| 123 for the python implementation. |
| 124 |
| 125 `ProcessHandler` extends `ProcessHandlerMixin` which by default prints the |
| 126 output, logs to a file (if specified), and stores the output (if specified, by |
| 127 default `True`). `ProcessHandlerMixin`, by default, does none of these things |
| 128 and has no handlers for `onTimeout`, `processOutput`, or `onFinish`. |
| 129 |
| 130 `ProcessHandler` may be subclassed to handle process timeouts (by overriding |
| 131 the `onTimeout()` method), process completion (by overriding |
| 132 `onFinish()`), and to process the command output (by overriding |
| 133 `processOutputLine()`). |
| 134 |
| 135 ## Examples |
| 136 |
| 137 In the most common case, a process_handler is created, then run followed by wait
are called: |
| 138 |
| 139 proc_handler = ProcessHandler([cmd, args]) |
| 140 proc_handler.run(outputTimeout=60) # will time out after 60 seconds without
output |
| 141 proc_handler.wait() |
| 142 |
| 143 Often, the main thread will do other things: |
| 144 |
| 145 proc_handler = ProcessHandler([cmd, args]) |
| 146 proc_handler.run(timeout=60) # will time out after 60 seconds regardless of
output |
| 147 do_other_work() |
| 148 |
| 149 if proc_handler.proc.poll() is None: |
| 150 proc_handler.wait() |
| 151 |
| 152 By default output is printed to stdout, but anything is possible: |
| 153 |
| 154 # this example writes output to both stderr and a file called 'output.log' |
| 155 def some_func(line): |
| 156 print >> sys.stderr, line |
| 157 |
| 158 with open('output.log', 'a') as log: |
| 159 log.write('%s\n' % line) |
| 160 |
| 161 proc_handler = ProcessHandler([cmd, args], processOutputLine=some_func) |
| 162 proc_handler.run() |
| 163 proc_handler.wait() |
| 164 |
| 165 # TODO |
| 166 |
| 167 - Document improvements over `subprocess.Popen.kill` |
| 168 - Introduce test the show improvements over `subprocess.Popen.kill` |
OLD | NEW |