process.html   [plain text]


<?xml version="1.0"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml" lang="en"><head><title>Twisted Documentation: Using Processes</title><link href="../howto/stylesheet.css" type="text/css" rel="stylesheet" /></head><body bgcolor="white"><h1 class="title">Using Processes</h1><div class="toc"><ol><li><a href="#auto0">Overview</a></li><li><a href="#auto1">Running Another Process</a></li><li><a href="#auto2">Writing a ProcessProtocol</a></li><li><a href="#auto3">Things that can happen to your ProcessProtocol</a></li><li><a href="#auto4">Things you can do from your ProcessProtocol</a></li><li><a href="#auto5">Verbose Example</a></li><li><a href="#auto6">Doing it the Easy Way</a></li><li><a href="#auto7">Mapping File Descriptors</a></li><ul><li><a href="#auto8">ProcessProtocols with extra file descriptors</a></li><li><a href="#auto9">Examples</a></li></ul></ol></div><div class="content"><span></span><h2>Overview<a name="auto0"></a></h2><p>Along with connection to servers across the internet, Twisted also
connects to local processes with much the same API. The API is described in
more detail in the documentation of:
<ul><li><code class="API"><a href="http://twistedmatrix.com/documents/TwistedDocs/TwistedDocs-1.3.0/api/twisted.internet.interfaces.IReactorProcess.html" title="twisted.internet.interfaces.IReactorProcess">twisted.internet.interfaces.IReactorProcess</a></code></li><li><code class="API"><a href="http://twistedmatrix.com/documents/TwistedDocs/TwistedDocs-1.3.0/api/twisted.internet.interfaces.IProcessTransport.html" title="twisted.internet.interfaces.IProcessTransport">twisted.internet.interfaces.IProcessTransport</a></code></li><li><code class="API"><a href="http://twistedmatrix.com/documents/TwistedDocs/TwistedDocs-1.3.0/api/twisted.internet.protocol.ProcessProtocol.html" title="twisted.internet.protocol.ProcessProtocol">twisted.internet.protocol.ProcessProtocol</a></code></li></ul></p><h2>Running Another Process<a name="auto1"></a></h2><p>Processes are run through the reactor, using <code class="python">reactor.spawnProcess()</code>. Pipes are created to the child
process, and added to the reactor core so that the application will not
block while sending data into or pulling data out of the new process. <code class="python">reactor.spawnProcess()</code> requires two arguments,
processProtocol and executable, and optionally takes six more: arguments,
environment, path, userID, groupID, and usePTY.</p><pre class="python">
<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span><span class="py-src-op">.</span><span class="py-src-variable">internet</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">reactor</span><span class="py-src-newline">
</span><span class="py-src-nl">
</span><span class="py-src-variable">mypp</span> <span class="py-src-op">=</span> <span class="py-src-variable">MyProcessProtocol</span><span class="py-src-op">(</span><span class="py-src-op">)</span><span class="py-src-newline">
</span><span class="py-src-variable">reactor</span><span class="py-src-op">.</span><span class="py-src-variable">spawnProcess</span><span class="py-src-op">(</span><span class="py-src-variable">processProtocol</span><span class="py-src-op">,</span> <span class="py-src-variable">executable</span><span class="py-src-op">,</span> <span class="py-src-variable">args</span><span class="py-src-op">=</span><span class="py-src-op">[</span><span class="py-src-variable">program</span><span class="py-src-op">,</span> <span class="py-src-variable">arg1</span><span class="py-src-op">,</span> <span class="py-src-variable">arg2</span><span class="py-src-op">]</span><span class="py-src-op">,</span><span class="py-src-nl">
</span>                     <span class="py-src-variable">env</span><span class="py-src-op">=</span><span class="py-src-op">{</span><span class="py-src-string">'HOME'</span><span class="py-src-op">:</span> <span class="py-src-variable">os</span><span class="py-src-op">.</span><span class="py-src-variable">environ</span><span class="py-src-op">[</span><span class="py-src-string">'HOME'</span><span class="py-src-op">]</span><span class="py-src-op">}</span><span class="py-src-op">,</span> <span class="py-src-variable">path</span><span class="py-src-op">,</span><span class="py-src-nl">
</span>                     <span class="py-src-variable">uid</span><span class="py-src-op">,</span> <span class="py-src-variable">gid</span><span class="py-src-op">,</span> <span class="py-src-variable">usePTY</span><span class="py-src-op">,</span> <span class="py-src-variable">childFDs</span><span class="py-src-op">)</span><span class="py-src-newline">
</span><span class="py-src-endmarker"></span></pre><ul><li><code>processProtocol</code> should be an instance of a subclass of
  <code class="API"><a href="http://twistedmatrix.com/documents/TwistedDocs/TwistedDocs-1.3.0/api/twisted.internet.protocol.ProcessProtocol.html" title="twisted.internet.protocol.ProcessProtocol">twisted.internet.protocol.ProcessProtocol</a></code>. The
  interface is described below.</li><li><code>executable</code> is the full path of the program to run. It
  will be connected to processProtocol.</li><li><code>args</code> is a list of command line arguments to be passed to
  the process. <code>args[0]</code> should be the name of the process.</li><li><code>env</code> is a dictionary containing the environment to pass
  through to the process.</li><li><code>path</code> is the directory to run the process in. The child
  will switch to the given directory just before starting the new program.
  The default is to stay in the current directory.</li><li><code>uid</code> and <code>gid</code> are the user ID and group ID to
  run the subprocess as. Of course, changing identities will be more likely
  to succeed if you start as root.</li><li><code>usePTY</code> specifies whether the child process should be run
  with a pty, or if it should just get a pair of pipes. Interactive programs
  (where you don't know when it may read or write) need to be run with
  ptys.</li><li><code>childFDs</code> lets you specify how the child's file
  descriptors should be set up. Each key is a file descriptor number (an
  integer) as seen by the child. 0, 1, and 2 are usually stdin, stdout, and
  stderr, but some programs may be instructed to use additional fds through
  command-line arguments or environment variables. Each value is either an
  integer specifying one of the parent's current file descriptors, the
  string <q>r</q> which creates a pipe that the parent can read from, or the
  string <q>w</q> which creates a pipe that the parent can write to. If
  <code>childFDs</code> is not provided, a default is used which creates the
  usual stdin-writer, stdout-reader, and stderr-reader pipes.</li></ul><p><code>args</code> and <code>env</code> have empty default values, but
many programs depend upon them to be set correctly. At the very least,
<code>args[0]</code> should probably be the same as <code>executable</code>.
If you just provide <code>os.environ</code> for <code>env</code>, the child
program will inherit the environment from the current process, which is
usually the civilized thing to do (unless you want to explicitly clean the
environment as a security precaution). The default is to give an empty
<code>env</code> to the child.</p><p><code class="python">reactor.spawnProcess()</code> returns an instance
that implements the <code class="API"><a href="http://twistedmatrix.com/documents/TwistedDocs/TwistedDocs-1.3.0/api/twisted.internet.interfaces.IProcessTransport.html" title="twisted.internet.interfaces.IProcessTransport">twisted.internet.interfaces.IProcessTransport</a></code>.</p><h2>Writing a ProcessProtocol<a name="auto2"></a></h2><p>The ProcessProtocol you pass to spawnProcess is your interaction with the
process. It has a very similar signature to a regular Protocol, but it has
several extra methods to deal with events specific to a process. In our
example, we will interface with 'wc' to create a word count of user-given
text. First, we'll start by importing the required modules, and writing the
initialization for our ProcessProtocol.</p><pre class="python">
<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span><span class="py-src-op">.</span><span class="py-src-variable">internet</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">protocol</span><span class="py-src-newline">
</span><span class="py-src-keyword">class</span> <span class="py-src-identifier">WCProcessProtocol</span><span class="py-src-op">(</span><span class="py-src-parameter">protocol</span><span class="py-src-op">.</span><span class="py-src-parameter">ProcessProtocol</span><span class="py-src-op">)</span><span class="py-src-op">:</span><span class="py-src-newline">
</span><span class="py-src-nl">
</span><span class="py-src-indent">    </span><span class="py-src-keyword">def</span> <span class="py-src-identifier">__init__</span><span class="py-src-op">(</span><span class="py-src-parameter">self</span><span class="py-src-op">,</span> <span class="py-src-parameter">text</span><span class="py-src-op">)</span><span class="py-src-op">:</span><span class="py-src-newline">
</span><span class="py-src-indent">        </span><span class="py-src-variable">self</span><span class="py-src-op">.</span><span class="py-src-variable">text</span> <span class="py-src-op">=</span> <span class="py-src-variable">text</span><span class="py-src-newline">
</span><span class="py-src-dedent"></span><span class="py-src-dedent"></span><span class="py-src-endmarker"></span></pre><p>When the ProcessProtocol is connected to the protocol, it has the
connectionMade method called. In our protocol, we will write our text to the
standard input of our process and then close standard input, to the let the
process know we are done writing to it.</p><pre class="python">
<span class="py-src-keyword">def</span> <span class="py-src-identifier">connectionMade</span><span class="py-src-op">(</span><span class="py-src-parameter">self</span><span class="py-src-op">)</span><span class="py-src-op">:</span><span class="py-src-newline">
</span><span class="py-src-indent">        </span><span class="py-src-variable">self</span><span class="py-src-op">.</span><span class="py-src-variable">transport</span><span class="py-src-op">.</span><span class="py-src-variable">write</span><span class="py-src-op">(</span><span class="py-src-variable">self</span><span class="py-src-op">.</span><span class="py-src-variable">text</span><span class="py-src-op">)</span><span class="py-src-newline">
</span>        <span class="py-src-variable">self</span><span class="py-src-op">.</span><span class="py-src-variable">transport</span><span class="py-src-op">.</span><span class="py-src-variable">closeStdin</span><span class="py-src-op">(</span><span class="py-src-op">)</span><span class="py-src-newline">
</span><span class="py-src-dedent"></span><span class="py-src-endmarker"></span></pre><p>At this point, the process has receieved the data, and it's time for us
to read the results. Instead of being receieved in dataReceived, data from
standard output is receieve in outReceived. This is to distinguish it from
data on standard error.</p><pre class="python">
<span class="py-src-keyword">def</span> <span class="py-src-identifier">outReceived</span><span class="py-src-op">(</span><span class="py-src-parameter">self</span><span class="py-src-op">,</span> <span class="py-src-parameter">data</span><span class="py-src-op">)</span><span class="py-src-op">:</span><span class="py-src-newline">
</span><span class="py-src-indent">        </span><span class="py-src-variable">fieldLength</span> <span class="py-src-op">=</span> <span class="py-src-variable">len</span><span class="py-src-op">(</span><span class="py-src-variable">data</span><span class="py-src-op">)</span> <span class="py-src-op">/</span> <span class="py-src-number">3</span><span class="py-src-newline">
</span>        <span class="py-src-variable">lines</span> <span class="py-src-op">=</span> <span class="py-src-variable">int</span><span class="py-src-op">(</span><span class="py-src-variable">data</span><span class="py-src-op">[</span><span class="py-src-op">:</span><span class="py-src-variable">fieldLength</span><span class="py-src-op">]</span><span class="py-src-op">)</span><span class="py-src-newline">
</span>        <span class="py-src-variable">words</span> <span class="py-src-op">=</span> <span class="py-src-variable">int</span><span class="py-src-op">(</span><span class="py-src-variable">data</span><span class="py-src-op">[</span><span class="py-src-variable">fieldLength</span><span class="py-src-op">:</span><span class="py-src-variable">fieldLength</span><span class="py-src-op">*</span><span class="py-src-number">2</span><span class="py-src-op">]</span><span class="py-src-op">)</span><span class="py-src-newline">
</span>        <span class="py-src-variable">chars</span> <span class="py-src-op">=</span> <span class="py-src-variable">int</span><span class="py-src-op">(</span><span class="py-src-variable">data</span><span class="py-src-op">[</span><span class="py-src-variable">fieldLength</span><span class="py-src-op">*</span><span class="py-src-number">2</span><span class="py-src-op">:</span><span class="py-src-op">]</span><span class="py-src-op">)</span><span class="py-src-newline">
</span>        <span class="py-src-variable">self</span><span class="py-src-op">.</span><span class="py-src-variable">transport</span><span class="py-src-op">.</span><span class="py-src-variable">loseConnection</span><span class="py-src-op">(</span><span class="py-src-op">)</span><span class="py-src-newline">
</span>        <span class="py-src-variable">self</span><span class="py-src-op">.</span><span class="py-src-variable">receiveCounts</span><span class="py-src-op">(</span><span class="py-src-variable">lines</span><span class="py-src-op">,</span> <span class="py-src-variable">words</span><span class="py-src-op">,</span> <span class="py-src-variable">chars</span><span class="py-src-op">)</span><span class="py-src-newline">
</span><span class="py-src-dedent"></span><span class="py-src-endmarker"></span></pre><p>Now, the process has parsed the output, and ended the connection to the
process. Then it sends the results on to the final method, receiveCounts.
This is for users of the class to override, so as to do other things with
the data. For our demonstration, we will just print the results.</p><pre class="python">
<span class="py-src-keyword">def</span> <span class="py-src-identifier">receiveCounts</span><span class="py-src-op">(</span><span class="py-src-parameter">self</span><span class="py-src-op">,</span> <span class="py-src-parameter">lines</span><span class="py-src-op">,</span> <span class="py-src-parameter">words</span><span class="py-src-op">,</span> <span class="py-src-parameter">chars</span><span class="py-src-op">)</span><span class="py-src-op">:</span><span class="py-src-newline">
</span><span class="py-src-indent">        </span><span class="py-src-keyword">print</span> <span class="py-src-string">'Received counts from wc.'</span><span class="py-src-newline">
</span>        <span class="py-src-keyword">print</span> <span class="py-src-string">'Lines:'</span><span class="py-src-op">,</span> <span class="py-src-variable">lines</span><span class="py-src-newline">
</span>        <span class="py-src-keyword">print</span> <span class="py-src-string">'Words:'</span><span class="py-src-op">,</span> <span class="py-src-variable">words</span><span class="py-src-newline">
</span>        <span class="py-src-keyword">print</span> <span class="py-src-string">'Characters:'</span><span class="py-src-op">,</span> <span class="py-src-variable">chars</span><span class="py-src-newline">
</span><span class="py-src-dedent"></span><span class="py-src-endmarker"></span></pre><p>We're done! To use our WCProcessProtocol, we create an instance, and pass
it to spawnProcess.</p><pre class="python">
<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span><span class="py-src-op">.</span><span class="py-src-variable">internet</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">reactor</span><span class="py-src-newline">
</span><span class="py-src-variable">wcProcess</span> <span class="py-src-op">=</span> <span class="py-src-variable">WCProcessProtocol</span><span class="py-src-op">(</span><span class="py-src-string">&quot;accessing protocols through Twisted is fun!\n&quot;</span><span class="py-src-op">)</span><span class="py-src-newline">
</span><span class="py-src-variable">reactor</span><span class="py-src-op">.</span><span class="py-src-variable">spawnProcess</span><span class="py-src-op">(</span><span class="py-src-variable">wcProcess</span><span class="py-src-op">,</span> <span class="py-src-string">'wc'</span><span class="py-src-op">,</span> <span class="py-src-op">[</span><span class="py-src-string">'wc'</span><span class="py-src-op">]</span><span class="py-src-op">)</span><span class="py-src-newline">
</span><span class="py-src-variable">reactor</span><span class="py-src-op">.</span><span class="py-src-variable">run</span><span class="py-src-op">(</span><span class="py-src-op">)</span><span class="py-src-newline">
</span><span class="py-src-endmarker"></span></pre><h2>Things that can happen to your ProcessProtocol<a name="auto3"></a></h2><p>These are the methods that you can usefully override in your subclass of
<code>ProcessProtocol</code>:</p><ul><li><code>.connectionMade</code>: This is called when the program is
  started, and makes a good place to write data into the stdin pipe (using
  <code class="python">self.transport.write()</code>).</li><li><code>.outReceived(data)</code>: This is called with data that was
  received from the process' stdout pipe. Pipes tend to provide data in
  larger chunks than sockets (one kilobyte is a common buffer size), so you
  may not experience the <q>random dribs and drabs</q> behavior typical of
  network sockets, but regardless you should be prepared to deal if you
  don't get all your data in a single call. To do it properly,
  <code>outReceived</code> ought to simply accumulate the data and put off
  doing anything with it until the process has finished.</li><li><code>.errReceived(data)</code>: This is called with data from the
  process' stderr pipe. It behaves just like <code>outReceived</code>.</li><li><code>.inConnectionLost</code>: This is called when the reactor notices
  that the process' stdin pipe has closed. Programs don't typically close
  their own stdin, so this will probably get called when your
  ProcessProtocol has shut down the write side with <code class="python">self.transport.loseConnection()</code>.</li><li><code>.outConnectionLost</code>: This is called when the program closes
  its stdout pipe. This usually happens when the program terminates.</li><li><code>.errConnectionLost</code>: Same as
  <code>outConnectionLost</code>, but for stderr instead of stdout.</li><li><p><code>.processEnded(status)</code>: This is called when the child
  process has been reaped, and receives information about the process' exit
  status. The status is passed in the form of a <code class="API"><a href="http://twistedmatrix.com/documents/TwistedDocs/TwistedDocs-1.3.0/api/twisted.python.failure.Failure.html" title="twisted.python.failure.Failure">Failure</a></code> instance, created with a
  <code>.value</code> that either holds a <code class="API"><a href="http://twistedmatrix.com/documents/TwistedDocs/TwistedDocs-1.3.0/api/twisted.internet.error.ProcessDone.html" title="twisted.internet.error.ProcessDone">ProcessDone</a></code> object if the process
  terminated normally (it died of natural causes instead of receiving a
  signal, and if the exit code was 0), or a <code class="API"><a href="http://twistedmatrix.com/documents/TwistedDocs/TwistedDocs-1.3.0/api/twisted.internet.error.ProcessTerminated.html" title="twisted.internet.error.ProcessTerminated">ProcessTerminated</a></code> object (with an
  <code>.exitCode</code> attribute) if something went wrong. This scheme may
  seem a bit weird, but I trust that it proves useful when dealing with
  exceptions that occur in asynchronous code.</p><!-- XXX: check twisted/internet/process.py:v1.30:line357, I think
  death-by-signal wouldn't be reported properly. --><p>This will always be called <em>after</em><code>inConnectionLost</code>,
  <code>outConnectionLost</code>, and <code>errConnectionLost</code> are
  called.</p></li></ul><p>The base-class definitions of these functions are all no-ops. This will
result in all stdout and stderr being thrown away. Note that it is important
for data you don't care about to be thrown away: if the pipe were not read,
the child process would eventually block as it tried to write to a full
pipe.</p><h2>Things you can do from your ProcessProtocol<a name="auto4"></a></h2><p>The following are the basic ways to control the child process:</p><ul><li><code>self.transport.write(data)</code>: Stuff some data in the stdin
  pipe. Note that this <code>write</code> method will queue any data that can't
  be written immediately. Writing will resume in the future when the pipe
  becomes writable again.</li><li><code>self.transport.closeStdin</code>: Close the stdin pipe. Programs
  which act as filters (reading from stdin, modifying the data, writing to
  stdout) usually take this as a sign that they should finish their job and
  terminate. For these programs, it is important to close stdin when you're
  done with it, otherwise the child process will never quit.</li><li><code>self.transport.closeStdout</code>: Not usually called, since you're
  putting the process into a state where any attempt to write to stdout will
  cause a SIGPIPE error. This isn't a nice thing to do to the poor
  process.</li><li><code>self.transport.closeStderr</code>: Not usually called, same reason
  as <code>closeStdout</code>.</li><li><code>self.transport.loseConnection</code>: Close all three pipes.</li><li><code>os.kill(self.transport.pid, signal.SIGKILL)</code>: Kill the child
  process. This will eventually result in <code>processEnded</code> being
  called.</li></ul><h2>Verbose Example<a name="auto5"></a></h2><p>Here is an example that is rather verbose about exactly when all the
methods are called. It writes a number of lines into the <code>wc</code>
program and then parses the output.</p><div class="py-listing"><pre>
<span class="py-src-comment">#! /usr/bin/python
</span><span class="py-src-nl">
</span><span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span><span class="py-src-op">.</span><span class="py-src-variable">internet</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">protocol</span><span class="py-src-newline">
</span><span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span><span class="py-src-op">.</span><span class="py-src-variable">internet</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">reactor</span><span class="py-src-newline">
</span><span class="py-src-keyword">import</span> <span class="py-src-variable">re</span><span class="py-src-newline">
</span><span class="py-src-nl">
</span><span class="py-src-keyword">class</span> <span class="py-src-identifier">MyPP</span><span class="py-src-op">(</span><span class="py-src-parameter">protocol</span><span class="py-src-op">.</span><span class="py-src-parameter">ProcessProtocol</span><span class="py-src-op">)</span><span class="py-src-op">:</span><span class="py-src-newline">
</span><span class="py-src-indent">    </span><span class="py-src-keyword">def</span> <span class="py-src-identifier">__init__</span><span class="py-src-op">(</span><span class="py-src-parameter">self</span><span class="py-src-op">,</span> <span class="py-src-parameter">verses</span><span class="py-src-op">)</span><span class="py-src-op">:</span><span class="py-src-newline">
</span><span class="py-src-indent">        </span><span class="py-src-variable">self</span><span class="py-src-op">.</span><span class="py-src-variable">verses</span> <span class="py-src-op">=</span> <span class="py-src-variable">verses</span><span class="py-src-newline">
</span>        <span class="py-src-variable">self</span><span class="py-src-op">.</span><span class="py-src-variable">data</span> <span class="py-src-op">=</span> <span class="py-src-string">&quot;&quot;</span><span class="py-src-newline">
</span>    <span class="py-src-dedent"></span><span class="py-src-keyword">def</span> <span class="py-src-identifier">connectionMade</span><span class="py-src-op">(</span><span class="py-src-parameter">self</span><span class="py-src-op">)</span><span class="py-src-op">:</span><span class="py-src-newline">
</span><span class="py-src-indent">        </span><span class="py-src-keyword">print</span> <span class="py-src-string">&quot;connectionMade!&quot;</span><span class="py-src-newline">
</span>        <span class="py-src-keyword">for</span> <span class="py-src-variable">i</span> <span class="py-src-keyword">in</span> <span class="py-src-variable">range</span><span class="py-src-op">(</span><span class="py-src-variable">self</span><span class="py-src-op">.</span><span class="py-src-variable">verses</span><span class="py-src-op">)</span><span class="py-src-op">:</span><span class="py-src-newline">
</span><span class="py-src-indent">            </span><span class="py-src-variable">self</span><span class="py-src-op">.</span><span class="py-src-variable">transport</span><span class="py-src-op">.</span><span class="py-src-variable">write</span><span class="py-src-op">(</span><span class="py-src-string">&quot;Aleph-null bottles of beer on the wall,\n&quot;</span> <span class="py-src-op">+</span><span class="py-src-nl">
</span>                                 <span class="py-src-string">&quot;Aleph-null bottles of beer,\n&quot;</span> <span class="py-src-op">+</span><span class="py-src-nl">
</span>                                 <span class="py-src-string">&quot;Take one down and pass it around,\n&quot;</span> <span class="py-src-op">+</span><span class="py-src-nl">
</span>                                 <span class="py-src-string">&quot;Aleph-null bottles of beer on the wall.\n&quot;</span><span class="py-src-op">)</span><span class="py-src-newline">
</span>            <span class="py-src-variable">self</span><span class="py-src-op">.</span><span class="py-src-variable">transport</span><span class="py-src-op">.</span><span class="py-src-variable">closeStdin</span><span class="py-src-op">(</span><span class="py-src-op">)</span> <span class="py-src-comment"># tell them we're done</span><span class="py-src-newline">
</span>    <span class="py-src-dedent"></span><span class="py-src-dedent"></span><span class="py-src-keyword">def</span> <span class="py-src-identifier">outReceived</span><span class="py-src-op">(</span><span class="py-src-parameter">self</span><span class="py-src-op">,</span> <span class="py-src-parameter">data</span><span class="py-src-op">)</span><span class="py-src-op">:</span><span class="py-src-newline">
</span><span class="py-src-indent">        </span><span class="py-src-keyword">print</span> <span class="py-src-string">&quot;outReceived! with %d bytes!&quot;</span> <span class="py-src-op">%</span> <span class="py-src-variable">len</span><span class="py-src-op">(</span><span class="py-src-variable">data</span><span class="py-src-op">)</span><span class="py-src-newline">
</span>        <span class="py-src-variable">self</span><span class="py-src-op">.</span><span class="py-src-variable">data</span> <span class="py-src-op">=</span> <span class="py-src-variable">self</span><span class="py-src-op">.</span><span class="py-src-variable">data</span> <span class="py-src-op">+</span> <span class="py-src-variable">data</span><span class="py-src-newline">
</span>    <span class="py-src-dedent"></span><span class="py-src-keyword">def</span> <span class="py-src-identifier">errReceived</span><span class="py-src-op">(</span><span class="py-src-parameter">self</span><span class="py-src-op">,</span> <span class="py-src-parameter">data</span><span class="py-src-op">)</span><span class="py-src-op">:</span><span class="py-src-newline">
</span><span class="py-src-indent">        </span><span class="py-src-keyword">print</span> <span class="py-src-string">&quot;errReceived! with %d bytes!&quot;</span> <span class="py-src-op">%</span> <span class="py-src-variable">len</span><span class="py-src-op">(</span><span class="py-src-variable">data</span><span class="py-src-op">)</span><span class="py-src-newline">
</span>    <span class="py-src-dedent"></span><span class="py-src-keyword">def</span> <span class="py-src-identifier">inConnectionLost</span><span class="py-src-op">(</span><span class="py-src-parameter">self</span><span class="py-src-op">)</span><span class="py-src-op">:</span><span class="py-src-newline">
</span><span class="py-src-indent">        </span><span class="py-src-keyword">print</span> <span class="py-src-string">&quot;inConnectionLost! stdin is closed! (we probably did it)&quot;</span><span class="py-src-newline">
</span>    <span class="py-src-dedent"></span><span class="py-src-keyword">def</span> <span class="py-src-identifier">outConnectionLost</span><span class="py-src-op">(</span><span class="py-src-parameter">self</span><span class="py-src-op">)</span><span class="py-src-op">:</span><span class="py-src-newline">
</span><span class="py-src-indent">        </span><span class="py-src-keyword">print</span> <span class="py-src-string">&quot;outConnectionLost! The child closed their stdout!&quot;</span><span class="py-src-newline">
</span>        <span class="py-src-comment"># now is the time to examine what they wrote
</span>        <span class="py-src-comment">#print &quot;I saw them write:&quot;, self.data
</span>        <span class="py-src-op">(</span><span class="py-src-variable">dummy</span><span class="py-src-op">,</span> <span class="py-src-variable">lines</span><span class="py-src-op">,</span> <span class="py-src-variable">words</span><span class="py-src-op">,</span> <span class="py-src-variable">chars</span><span class="py-src-op">,</span> <span class="py-src-variable">file</span><span class="py-src-op">)</span> <span class="py-src-op">=</span> <span class="py-src-variable">re</span><span class="py-src-op">.</span><span class="py-src-variable">split</span><span class="py-src-op">(</span><span class="py-src-string">r'\s+'</span><span class="py-src-op">,</span> <span class="py-src-variable">self</span><span class="py-src-op">.</span><span class="py-src-variable">data</span><span class="py-src-op">)</span><span class="py-src-newline">
</span>        <span class="py-src-keyword">print</span> <span class="py-src-string">&quot;I saw %s lines&quot;</span> <span class="py-src-op">%</span> <span class="py-src-variable">lines</span><span class="py-src-newline">
</span>    <span class="py-src-dedent"></span><span class="py-src-keyword">def</span> <span class="py-src-identifier">errConnectionLost</span><span class="py-src-op">(</span><span class="py-src-parameter">self</span><span class="py-src-op">)</span><span class="py-src-op">:</span><span class="py-src-newline">
</span><span class="py-src-indent">        </span><span class="py-src-keyword">print</span> <span class="py-src-string">&quot;errConnectionLost! The child closed their stderr.&quot;</span><span class="py-src-newline">
</span>    <span class="py-src-dedent"></span><span class="py-src-keyword">def</span> <span class="py-src-identifier">processEnded</span><span class="py-src-op">(</span><span class="py-src-parameter">self</span><span class="py-src-op">,</span> <span class="py-src-parameter">status_object</span><span class="py-src-op">)</span><span class="py-src-op">:</span><span class="py-src-newline">
</span><span class="py-src-indent">        </span><span class="py-src-keyword">print</span> <span class="py-src-string">&quot;processEnded, status %d&quot;</span> <span class="py-src-op">%</span> <span class="py-src-variable">status_object</span><span class="py-src-op">.</span><span class="py-src-variable">value</span><span class="py-src-op">.</span><span class="py-src-variable">exitCode</span><span class="py-src-newline">
</span>        <span class="py-src-keyword">print</span> <span class="py-src-string">&quot;quitting&quot;</span><span class="py-src-newline">
</span>        <span class="py-src-variable">reactor</span><span class="py-src-op">.</span><span class="py-src-variable">stop</span><span class="py-src-op">(</span><span class="py-src-op">)</span><span class="py-src-newline">
</span><span class="py-src-nl">
</span><span class="py-src-dedent"></span><span class="py-src-dedent"></span><span class="py-src-variable">pp</span> <span class="py-src-op">=</span> <span class="py-src-variable">MyPP</span><span class="py-src-op">(</span><span class="py-src-number">10</span><span class="py-src-op">)</span><span class="py-src-newline">
</span><span class="py-src-variable">reactor</span><span class="py-src-op">.</span><span class="py-src-variable">spawnProcess</span><span class="py-src-op">(</span><span class="py-src-variable">pp</span><span class="py-src-op">,</span> <span class="py-src-string">&quot;wc&quot;</span><span class="py-src-op">,</span> <span class="py-src-op">[</span><span class="py-src-string">&quot;wc&quot;</span><span class="py-src-op">]</span><span class="py-src-op">,</span> <span class="py-src-op">{</span><span class="py-src-op">}</span><span class="py-src-op">)</span><span class="py-src-newline">
</span><span class="py-src-variable">reactor</span><span class="py-src-op">.</span><span class="py-src-variable">run</span><span class="py-src-op">(</span><span class="py-src-op">)</span><span class="py-src-newline">
</span><span class="py-src-endmarker"></span></pre><div class="caption">Source listing - <a href="listings/process/process.py"><span class="filename">listings/process/process.py</span></a></div></div><p>The exact output of this program depends upon the relative timing of some
un-synchronized events. In particular, the program may observe the child
process close its stderr pipe before or after it reads data from the stdout
pipe. One possible transcript would look like this:</p><pre class="shell">
% ./process.py 
connectionMade!
inConnectionLost! stdin is closed! (we probably did it)
errConnectionLost! The child closed their stderr.
outReceived! with 24 bytes!
outConnectionLost! The child closed their stdout!
I saw 40 lines
processEnded, status 0
quitting
Main loop terminated.
% 
</pre><h2>Doing it the Easy Way<a name="auto6"></a></h2><p>Frequently, one just needs a simple way to get all the output from a
program. In the blocking world, you might use <code class="python">commands.getoutput</code> from the standard library, but
using that in an event-driven program will cause everything else to stall
until the command finishes. (in addition, the SIGCHLD handler used by that
function does not play well with Twisted's own signal handling). For these
cases, the <code class="API"><a href="http://twistedmatrix.com/documents/TwistedDocs/TwistedDocs-1.3.0/api/twisted.internet.utils.getProcessOutput.html" title="twisted.internet.utils.getProcessOutput">twisted.internet.utils.getProcessOutput</a></code>
function can be used. Here is a simple example:</p><div class="py-listing"><pre>
<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span><span class="py-src-op">.</span><span class="py-src-variable">internet</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">protocol</span><span class="py-src-op">,</span> <span class="py-src-variable">utils</span><span class="py-src-op">,</span> <span class="py-src-variable">reactor</span><span class="py-src-newline">
</span><span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span><span class="py-src-op">.</span><span class="py-src-variable">python</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">failure</span><span class="py-src-newline">
</span><span class="py-src-keyword">from</span> <span class="py-src-variable">cStringIO</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">StringIO</span><span class="py-src-newline">
</span><span class="py-src-nl">
</span><span class="py-src-keyword">class</span> <span class="py-src-identifier">FortuneQuoter</span><span class="py-src-op">(</span><span class="py-src-parameter">protocol</span><span class="py-src-op">.</span><span class="py-src-parameter">Protocol</span><span class="py-src-op">)</span><span class="py-src-op">:</span><span class="py-src-newline">
</span><span class="py-src-nl">
</span><span class="py-src-indent">    </span><span class="py-src-variable">fortune</span> <span class="py-src-op">=</span> <span class="py-src-string">'/usr/games/fortune'</span><span class="py-src-newline">
</span><span class="py-src-nl">
</span>    <span class="py-src-keyword">def</span> <span class="py-src-identifier">connectionMade</span><span class="py-src-op">(</span><span class="py-src-parameter">self</span><span class="py-src-op">)</span><span class="py-src-op">:</span><span class="py-src-newline">
</span><span class="py-src-indent">        </span><span class="py-src-variable">output</span> <span class="py-src-op">=</span> <span class="py-src-variable">utils</span><span class="py-src-op">.</span><span class="py-src-variable">getProcessOutput</span><span class="py-src-op">(</span><span class="py-src-variable">self</span><span class="py-src-op">.</span><span class="py-src-variable">fortune</span><span class="py-src-op">)</span><span class="py-src-newline">
</span>        <span class="py-src-variable">output</span><span class="py-src-op">.</span><span class="py-src-variable">addCallbacks</span><span class="py-src-op">(</span><span class="py-src-variable">self</span><span class="py-src-op">.</span><span class="py-src-variable">writeResponse</span><span class="py-src-op">,</span> <span class="py-src-variable">self</span><span class="py-src-op">.</span><span class="py-src-variable">noResponse</span><span class="py-src-op">)</span><span class="py-src-newline">
</span><span class="py-src-nl">
</span>    <span class="py-src-dedent"></span><span class="py-src-keyword">def</span> <span class="py-src-identifier">writeResponse</span><span class="py-src-op">(</span><span class="py-src-parameter">self</span><span class="py-src-op">,</span> <span class="py-src-parameter">resp</span><span class="py-src-op">)</span><span class="py-src-op">:</span><span class="py-src-newline">
</span><span class="py-src-indent">        </span><span class="py-src-variable">self</span><span class="py-src-op">.</span><span class="py-src-variable">transport</span><span class="py-src-op">.</span><span class="py-src-variable">write</span><span class="py-src-op">(</span><span class="py-src-variable">resp</span><span class="py-src-op">)</span><span class="py-src-newline">
</span>        <span class="py-src-variable">self</span><span class="py-src-op">.</span><span class="py-src-variable">transport</span><span class="py-src-op">.</span><span class="py-src-variable">loseConnection</span><span class="py-src-op">(</span><span class="py-src-op">)</span><span class="py-src-newline">
</span><span class="py-src-nl">
</span>    <span class="py-src-dedent"></span><span class="py-src-keyword">def</span> <span class="py-src-identifier">noResponse</span><span class="py-src-op">(</span><span class="py-src-parameter">self</span><span class="py-src-op">,</span> <span class="py-src-parameter">err</span><span class="py-src-op">)</span><span class="py-src-op">:</span><span class="py-src-newline">
</span><span class="py-src-indent">        </span><span class="py-src-variable">self</span><span class="py-src-op">.</span><span class="py-src-variable">transport</span><span class="py-src-op">.</span><span class="py-src-variable">loseConnection</span><span class="py-src-op">(</span><span class="py-src-op">)</span><span class="py-src-newline">
</span><span class="py-src-nl">
</span><span class="py-src-nl">
</span><span class="py-src-dedent"></span><span class="py-src-dedent"></span><span class="py-src-keyword">if</span> <span class="py-src-variable">__name__</span> <span class="py-src-op">==</span> <span class="py-src-string">'__main__'</span><span class="py-src-op">:</span><span class="py-src-newline">
</span><span class="py-src-indent">    </span><span class="py-src-variable">f</span> <span class="py-src-op">=</span> <span class="py-src-variable">protocol</span><span class="py-src-op">.</span><span class="py-src-variable">Factory</span><span class="py-src-op">(</span><span class="py-src-op">)</span><span class="py-src-newline">
</span>    <span class="py-src-variable">f</span><span class="py-src-op">.</span><span class="py-src-variable">protocol</span> <span class="py-src-op">=</span> <span class="py-src-variable">FortuneQuoter</span><span class="py-src-newline">
</span>    <span class="py-src-variable">reactor</span><span class="py-src-op">.</span><span class="py-src-variable">listenTCP</span><span class="py-src-op">(</span><span class="py-src-number">10999</span><span class="py-src-op">,</span> <span class="py-src-variable">f</span><span class="py-src-op">)</span><span class="py-src-newline">
</span>    <span class="py-src-variable">reactor</span><span class="py-src-op">.</span><span class="py-src-variable">run</span><span class="py-src-op">(</span><span class="py-src-op">)</span><span class="py-src-newline">
</span><span class="py-src-dedent"></span><span class="py-src-endmarker"></span></pre><div class="caption">Source listing - <a href="listings/process/quotes.py"><span class="filename">listings/process/quotes.py</span></a></div></div><p>If you only need the final exit code (like <code class="python">commands.getstatusoutput(cmd)[0]</code>), the <code class="API"><a href="http://twistedmatrix.com/documents/TwistedDocs/TwistedDocs-1.3.0/api/twisted.internet.utils.getProcessValue.html" title="twisted.internet.utils.getProcessValue">twisted.internet.utils.getProcessValue</a></code> function is
useful. Here is an example:</p><div class="py-listing"><pre>
<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span><span class="py-src-op">.</span><span class="py-src-variable">internet</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">utils</span><span class="py-src-op">,</span> <span class="py-src-variable">reactor</span><span class="py-src-newline">
</span><span class="py-src-nl">
</span><span class="py-src-keyword">def</span> <span class="py-src-identifier">printTrueValue</span><span class="py-src-op">(</span><span class="py-src-parameter">val</span><span class="py-src-op">)</span><span class="py-src-op">:</span><span class="py-src-newline">
</span><span class="py-src-indent">    </span><span class="py-src-keyword">print</span> <span class="py-src-string">&quot;/bin/true exits with rc=%d&quot;</span> <span class="py-src-op">%</span> <span class="py-src-variable">val</span><span class="py-src-newline">
</span>    <span class="py-src-variable">output</span> <span class="py-src-op">=</span> <span class="py-src-variable">utils</span><span class="py-src-op">.</span><span class="py-src-variable">getProcessValue</span><span class="py-src-op">(</span><span class="py-src-string">'/bin/false'</span><span class="py-src-op">)</span><span class="py-src-newline">
</span>    <span class="py-src-variable">output</span><span class="py-src-op">.</span><span class="py-src-variable">addCallback</span><span class="py-src-op">(</span><span class="py-src-variable">printFalseValue</span><span class="py-src-op">)</span><span class="py-src-newline">
</span><span class="py-src-nl">
</span><span class="py-src-dedent"></span><span class="py-src-keyword">def</span> <span class="py-src-identifier">printFalseValue</span><span class="py-src-op">(</span><span class="py-src-parameter">val</span><span class="py-src-op">)</span><span class="py-src-op">:</span><span class="py-src-newline">
</span><span class="py-src-indent">    </span><span class="py-src-keyword">print</span> <span class="py-src-string">&quot;/bin/false exits with rc=%d&quot;</span> <span class="py-src-op">%</span> <span class="py-src-variable">val</span><span class="py-src-newline">
</span>    <span class="py-src-variable">reactor</span><span class="py-src-op">.</span><span class="py-src-variable">stop</span><span class="py-src-op">(</span><span class="py-src-op">)</span><span class="py-src-newline">
</span><span class="py-src-nl">
</span><span class="py-src-dedent"></span><span class="py-src-variable">output</span> <span class="py-src-op">=</span> <span class="py-src-variable">utils</span><span class="py-src-op">.</span><span class="py-src-variable">getProcessValue</span><span class="py-src-op">(</span><span class="py-src-string">'/bin/true'</span><span class="py-src-op">)</span><span class="py-src-newline">
</span><span class="py-src-variable">output</span><span class="py-src-op">.</span><span class="py-src-variable">addCallback</span><span class="py-src-op">(</span><span class="py-src-variable">printTrueValue</span><span class="py-src-op">)</span><span class="py-src-newline">
</span><span class="py-src-variable">reactor</span><span class="py-src-op">.</span><span class="py-src-variable">run</span><span class="py-src-op">(</span><span class="py-src-op">)</span><span class="py-src-newline">
</span><span class="py-src-endmarker"></span></pre><div class="caption">Source listing - <a href="listings/process/trueandfalse.py"><span class="filename">listings/process/trueandfalse.py</span></a></div></div><h2>Mapping File Descriptors<a name="auto7"></a></h2><p><q>stdin</q>, <q>stdout</q>, and <q>stderr</q> are just conventions.
Programs which operate as filters generally accept input on fd0, write their
output on fd1, and emit error messages on fd2. This is common enough that
the standard C library provides macros like <q>stdin</q> to mean fd0, and
shells interpret the pipe character <q>|</q> to mean <q>redirect fd1 from
one command into fd0 of the next command</q>.</p><p>But these are just conventions, and programs are free to use additional
file descriptors or even ignore the standard three entirely. The
<q>childFDs</q> argument allows you to specify exactly what kind of files
descriptors the child process should be given.</p><p>Each child FD can be put into one of three states:</p><ul><li>Mapped to a parent FD: this causes the child's reads and writes to
  come from or go to the same source/destination as the parent.</li><li>Feeding into a pipe which can be read by the parent.</li><li>Feeding from a pipe which the parent writes into.</li></ul><p>Mapping the child FDs to the parent's is very commonly used to send the
child's stderr output to the same place as the parent's. When you run a
program from the shell, it will typically leave fds 0, 1, and 2 mapped to
the shell's 0, 1, and 2, allowing you to see the child program's output on
the same terminal you used to launch the child. Likewise, inetd will
typically map both stdin and stdout to the network socket, and may map
stderr to the same socket or to some kind of logging mechanism. This allows
the child program to be implemented with no knowledge of the network: it
merely speaks its protocol by doing reads on fd0 and writes on fd1.</p><p>Feeding into a parent's read pipe is used to gather output from the
child, and is by far the most common way of interacting with child
processes.</p><p>Feeding from a parent's write pipe allows the parent to control the
child. Programs like <q>bc</q> or <q>ftp</q> can be controlled this way, by
writing commands into their stdin stream.</p><p>The <q>childFDs</q> dictionary maps file descriptor numbers (as will be
seen by the child process) to one of these three states. To map the fd to
one of the parent's fds, simply provide the fd number as the value. To map
it to a read pipe, use the string <q>r</q> as the value. To map it to a
write pipe, use the string <q>w</q>.</p><p>For example, the default mapping sets up the standard stdin/stdout/stderr
pipes. It is implemented with the following dictionary:</p><pre class="python">
<span class="py-src-variable">childFDs</span> <span class="py-src-op">=</span> <span class="py-src-op">{</span> <span class="py-src-number">0</span><span class="py-src-op">:</span> <span class="py-src-string">&quot;w&quot;</span><span class="py-src-op">,</span> <span class="py-src-number">1</span><span class="py-src-op">:</span> <span class="py-src-string">&quot;r&quot;</span><span class="py-src-op">,</span> <span class="py-src-number">2</span><span class="py-src-op">:</span> <span class="py-src-string">&quot;r&quot;</span> <span class="py-src-op">}</span><span class="py-src-newline">
</span><span class="py-src-endmarker"></span></pre><p>To launch a process which reads and writes to the same places that the
parent python program does, use this:</p><pre class="python">
<span class="py-src-variable">childFDs</span> <span class="py-src-op">=</span> <span class="py-src-op">{</span> <span class="py-src-number">0</span><span class="py-src-op">:</span> <span class="py-src-number">0</span><span class="py-src-op">,</span> <span class="py-src-number">1</span><span class="py-src-op">:</span> <span class="py-src-number">1</span><span class="py-src-op">,</span> <span class="py-src-number">2</span><span class="py-src-op">:</span> <span class="py-src-number">2</span><span class="py-src-op">}</span><span class="py-src-newline">
</span><span class="py-src-endmarker"></span></pre><p>To write into an additional fd (say it is fd number 4), use this:</p><pre class="python">
<span class="py-src-variable">childFDs</span> <span class="py-src-op">=</span> <span class="py-src-op">{</span> <span class="py-src-number">0</span><span class="py-src-op">:</span> <span class="py-src-string">&quot;w&quot;</span><span class="py-src-op">,</span> <span class="py-src-number">1</span><span class="py-src-op">:</span> <span class="py-src-string">&quot;r&quot;</span><span class="py-src-op">,</span> <span class="py-src-number">2</span><span class="py-src-op">:</span> <span class="py-src-string">&quot;r&quot;</span> <span class="py-src-op">,</span> <span class="py-src-number">4</span><span class="py-src-op">:</span> <span class="py-src-string">&quot;w&quot;</span><span class="py-src-op">}</span><span class="py-src-newline">
</span><span class="py-src-endmarker"></span></pre><h3>ProcessProtocols with extra file descriptors<a name="auto8"></a></h3><p>When you provide a <q>childFDs</q> dictionary with more than the normal
three fds, you need addtional methods to access those pipes. These methods
are more generalized than the <code>.outReceived</code> ones described above.
In fact, those methods (<code>outReceived</code> and
<code>errReceived</code>) are actually just wrappers left in for
compatibility with older code, written before this generalized fd mapping was
implemented. The new list of things that can happen to your ProcessProtocol
is as follows:</p><ul><li><code>.connectionMade</code>: This is called when the program is
  started.</li><li><code>.childDataReceived(childFD, data)</code>: This is called with
  data that was received from one of the process' output pipes (i.e. where
  the childFDs value was <q>r</q>. The actual file number (from the point of
  view of the child process) is in <q>childFD</q>. For compatibility, the
  default implementation of <code>.dataReceived</code> dispatches to
  <code>.outReceived</code> or <code>.errReceived</code> when <q>childFD</q>
  is 1 or 2.</li><li><code>.childConnectionLost(childFD)</code>: This is called when the
  reactor notices that one of the process' pipes has been closed. This
  either means you have just closed down the parent's end of the pipe (with
  <code>.transport.closeChildFD</code>), the child closed the pipe
  explicitly (sometimes to indicate EOF), or the child process has
  terminated and the kernel has closed all of its pipes. The <q>childFD</q>
  argument tells you which pipe was closed. Note that you can only find out
  about file descriptors which were mapped to pipes: when they are mapped to
  existing fds the parent has no way to notice when they've been closed. For
  compatibility, the default implementation dispatches to
  <code>.inConnectionLost</code>, <code>.outConnectionLost</code>, or
  <code>.errConnectionLost</code>.</li><li><code>.processEnded(status)</code>: This is called when the child
  process has been reaped, and all pipes have been closed. This insures that
  all data written by the child prior to its death will be received before
  <code>.processEnded</code> is invoked.</li></ul><p>In addition to those methods, there are other methods available to
influence the child process:</p><ul><li><code>self.transport.writeToChild(childFD, data)</code>: Stuff some
  data into an input pipe. <code>.write</code> simply writes to
  childFD=0.</li><li><code>self.transport.closeChildFD(childFD)</code>: Close one of the
  child's pipes. Closing an input pipe is a common way to indicate EOF to
  the child process. Closing an output pipe is neither very friendly nor
  very useful.</li><li><code>os.kill(self.transport.pid, signal.SIGKILL)</code>: Kill the child
  process. This will eventually result in <code>processEnded</code> being
  called.</li></ul><h3>Examples<a name="auto9"></a></h3><p>GnuPG, the encryption program, can use additional file descriptors to
accept a passphrase and emit status output. These are distinct from stdin
(used to accept the crypttext), stdout (used to emit the plaintext), and
stderr (used to emit human-readable status/warning messages). The passphrase
FD reads until the pipe is closed and uses the resulting string to unlock
the secret key that performs the actual decryption. The status FD emits
machine-parseable status messages to indicate the validity of the signature,
which key the message was encrypted to, etc.</p><p>gpg accepts command-line arguments to specify what these fds are, and
then assumes that they have been opened by the parent before the gpg process
is started. It simply performs reads and writes to these fd numbers.</p><p>To invoke gpg in decryption/verification mode, you would do something
like the following:</p><pre class="python">
<span class="py-src-keyword">class</span> <span class="py-src-identifier">GPGProtocol</span><span class="py-src-op">(</span><span class="py-src-parameter">ProcessProtocol</span><span class="py-src-op">)</span><span class="py-src-op">:</span><span class="py-src-newline">
</span><span class="py-src-indent">    </span><span class="py-src-keyword">def</span> <span class="py-src-identifier">__init__</span><span class="py-src-op">(</span><span class="py-src-parameter">self</span><span class="py-src-op">,</span> <span class="py-src-parameter">crypttext</span><span class="py-src-op">)</span><span class="py-src-op">:</span><span class="py-src-newline">
</span><span class="py-src-indent">        </span><span class="py-src-variable">self</span><span class="py-src-op">.</span><span class="py-src-variable">crypttext</span> <span class="py-src-op">=</span> <span class="py-src-variable">crypttext</span><span class="py-src-newline">
</span>        <span class="py-src-variable">self</span><span class="py-src-op">.</span><span class="py-src-variable">plaintext</span> <span class="py-src-op">=</span> <span class="py-src-string">&quot;&quot;</span><span class="py-src-newline">
</span>        <span class="py-src-variable">self</span><span class="py-src-op">.</span><span class="py-src-variable">status</span> <span class="py-src-op">=</span> <span class="py-src-string">&quot;&quot;</span><span class="py-src-newline">
</span>    <span class="py-src-dedent"></span><span class="py-src-keyword">def</span> <span class="py-src-identifier">connectionMade</span><span class="py-src-op">(</span><span class="py-src-parameter">self</span><span class="py-src-op">)</span><span class="py-src-op">:</span><span class="py-src-newline">
</span><span class="py-src-indent">        </span><span class="py-src-variable">self</span><span class="py-src-op">.</span><span class="py-src-variable">transport</span><span class="py-src-op">.</span><span class="py-src-variable">writeToChild</span><span class="py-src-op">(</span><span class="py-src-number">3</span><span class="py-src-op">,</span> <span class="py-src-variable">self</span><span class="py-src-op">.</span><span class="py-src-variable">passphrase</span><span class="py-src-op">)</span><span class="py-src-newline">
</span>        <span class="py-src-variable">self</span><span class="py-src-op">.</span><span class="py-src-variable">transport</span><span class="py-src-op">.</span><span class="py-src-variable">closeChildFD</span><span class="py-src-op">(</span><span class="py-src-number">3</span><span class="py-src-op">)</span><span class="py-src-newline">
</span>        <span class="py-src-variable">self</span><span class="py-src-op">.</span><span class="py-src-variable">transport</span><span class="py-src-op">.</span><span class="py-src-variable">writeToChild</span><span class="py-src-op">(</span><span class="py-src-number">0</span><span class="py-src-op">,</span> <span class="py-src-variable">self</span><span class="py-src-op">.</span><span class="py-src-variable">crypttext</span><span class="py-src-op">)</span><span class="py-src-newline">
</span>        <span class="py-src-variable">self</span><span class="py-src-op">.</span><span class="py-src-variable">transport</span><span class="py-src-op">.</span><span class="py-src-variable">closeChildFD</span><span class="py-src-op">(</span><span class="py-src-number">0</span><span class="py-src-op">)</span><span class="py-src-newline">
</span>    <span class="py-src-dedent"></span><span class="py-src-keyword">def</span> <span class="py-src-identifier">childDataReceived</span><span class="py-src-op">(</span><span class="py-src-parameter">self</span><span class="py-src-op">,</span> <span class="py-src-parameter">childFD</span><span class="py-src-op">,</span> <span class="py-src-parameter">data</span><span class="py-src-op">)</span><span class="py-src-op">:</span><span class="py-src-newline">
</span><span class="py-src-indent">        </span><span class="py-src-keyword">if</span> <span class="py-src-variable">childFD</span> <span class="py-src-op">==</span> <span class="py-src-number">1</span><span class="py-src-op">:</span> <span class="py-src-variable">self</span><span class="py-src-op">.</span><span class="py-src-variable">plaintext</span> <span class="py-src-op">+=</span> <span class="py-src-variable">data</span><span class="py-src-newline">
</span>        <span class="py-src-keyword">if</span> <span class="py-src-variable">childFD</span> <span class="py-src-op">==</span> <span class="py-src-number">4</span><span class="py-src-op">:</span> <span class="py-src-variable">self</span><span class="py-src-op">.</span><span class="py-src-variable">status</span> <span class="py-src-op">+=</span> <span class="py-src-variable">data</span><span class="py-src-newline">
</span>    <span class="py-src-dedent"></span><span class="py-src-keyword">def</span> <span class="py-src-identifier">processEnded</span><span class="py-src-op">(</span><span class="py-src-parameter">self</span><span class="py-src-op">,</span> <span class="py-src-parameter">status</span><span class="py-src-op">)</span><span class="py-src-op">:</span><span class="py-src-newline">
</span><span class="py-src-indent">        </span><span class="py-src-variable">rc</span> <span class="py-src-op">=</span> <span class="py-src-variable">status</span><span class="py-src-op">.</span><span class="py-src-variable">value</span><span class="py-src-op">.</span><span class="py-src-variable">exitCode</span><span class="py-src-newline">
</span>        <span class="py-src-keyword">if</span> <span class="py-src-variable">rc</span> <span class="py-src-op">==</span> <span class="py-src-number">0</span><span class="py-src-op">:</span><span class="py-src-newline">
</span><span class="py-src-indent">            </span><span class="py-src-variable">self</span><span class="py-src-op">.</span><span class="py-src-variable">deferred</span><span class="py-src-op">.</span><span class="py-src-variable">callback</span><span class="py-src-op">(</span><span class="py-src-variable">self</span><span class="py-src-op">)</span><span class="py-src-newline">
</span>        <span class="py-src-dedent"></span><span class="py-src-keyword">else</span><span class="py-src-op">:</span><span class="py-src-newline">
</span><span class="py-src-indent">            </span><span class="py-src-variable">self</span><span class="py-src-op">.</span><span class="py-src-variable">deferred</span><span class="py-src-op">.</span><span class="py-src-variable">errback</span><span class="py-src-op">(</span><span class="py-src-variable">rc</span><span class="py-src-op">)</span><span class="py-src-newline">
</span><span class="py-src-nl">
</span><span class="py-src-dedent"></span><span class="py-src-dedent"></span><span class="py-src-dedent"></span><span class="py-src-keyword">def</span> <span class="py-src-identifier">decrypt</span><span class="py-src-op">(</span><span class="py-src-parameter">crypttext</span><span class="py-src-op">)</span><span class="py-src-op">:</span><span class="py-src-newline">
</span><span class="py-src-indent">    </span><span class="py-src-variable">gp</span> <span class="py-src-op">=</span> <span class="py-src-variable">GPGProtocol</span><span class="py-src-op">(</span><span class="py-src-variable">crypttext</span><span class="py-src-op">)</span><span class="py-src-newline">
</span>    <span class="py-src-variable">gp</span><span class="py-src-op">.</span><span class="py-src-variable">deferred</span> <span class="py-src-op">=</span> <span class="py-src-variable">Deferred</span><span class="py-src-op">(</span><span class="py-src-op">)</span><span class="py-src-newline">
</span>    <span class="py-src-variable">cmd</span> <span class="py-src-op">=</span> <span class="py-src-op">[</span><span class="py-src-string">&quot;gpg&quot;</span><span class="py-src-op">,</span> <span class="py-src-string">&quot;--decrypt&quot;</span><span class="py-src-op">,</span> <span class="py-src-string">&quot;--passphrase-fd&quot;</span><span class="py-src-op">,</span> <span class="py-src-string">&quot;3&quot;</span><span class="py-src-op">,</span> <span class="py-src-string">&quot;--status-fd&quot;</span><span class="py-src-op">,</span> <span class="py-src-string">&quot;4&quot;</span><span class="py-src-op">,</span><span class="py-src-nl">
</span>           <span class="py-src-string">&quot;--batch&quot;</span><span class="py-src-op">]</span><span class="py-src-newline">
</span>    <span class="py-src-variable">p</span> <span class="py-src-op">=</span> <span class="py-src-variable">reactor</span><span class="py-src-op">.</span><span class="py-src-variable">spawnProcess</span><span class="py-src-op">(</span><span class="py-src-variable">gp</span><span class="py-src-op">,</span> <span class="py-src-variable">cmd</span><span class="py-src-op">[</span><span class="py-src-number">0</span><span class="py-src-op">]</span><span class="py-src-op">,</span> <span class="py-src-variable">cmd</span><span class="py-src-op">,</span> <span class="py-src-variable">env</span><span class="py-src-op">=</span><span class="py-src-variable">None</span><span class="py-src-op">,</span><span class="py-src-nl">
</span>                             <span class="py-src-variable">childFDs</span><span class="py-src-op">=</span><span class="py-src-op">{</span><span class="py-src-number">0</span><span class="py-src-op">:</span><span class="py-src-string">&quot;w&quot;</span><span class="py-src-op">,</span> <span class="py-src-number">1</span><span class="py-src-op">:</span><span class="py-src-string">&quot;r&quot;</span><span class="py-src-op">,</span> <span class="py-src-number">2</span><span class="py-src-op">:</span><span class="py-src-number">2</span><span class="py-src-op">,</span> <span class="py-src-number">3</span><span class="py-src-op">:</span><span class="py-src-string">&quot;w&quot;</span><span class="py-src-op">,</span> <span class="py-src-number">4</span><span class="py-src-op">:</span><span class="py-src-string">&quot;r&quot;</span><span class="py-src-op">}</span><span class="py-src-op">)</span><span class="py-src-newline">
</span>    <span class="py-src-keyword">return</span> <span class="py-src-variable">gp</span><span class="py-src-op">.</span><span class="py-src-variable">deferred</span><span class="py-src-newline">
</span><span class="py-src-dedent"></span><span class="py-src-endmarker"></span></pre><p>In this example, the status output could be parsed after the fact. It
could, of course, be parsed on the fly, as it is a simple line-oriented
protocol. Methods from LineReceiver could be mixed in to make this parsing
more convenient.</p><p>The stderr mapping (<q>2:2</q>) used will cause any GPG errors to be
emitted by the parent program, just as if those errors had caused in the
parent itself. This is sometimes desireable (it roughly corresponds to
letting exceptions propagate upwards), especially if you do not expect to
encounter errors in the child process and want them to be more visible to
the end user. The alternative is to map stderr to a read-pipe and handle any
such output from within the ProcessProtocol (roughly corresponding to
catching the exception locally).</p></div><p><a href="../howto/index.html">Index</a></p><span class="version">Version: 1.3.0</span></body></html>