author
======
Todd Mueller
toddmueller@gmail.com

version
=======
1.4b

history
=======
20130401 1.0   Initial release.
20130402 1.1b  Eliminate need for external timeout binary, now
                 uses threading.Timer().
               retval values have changed.
               Tests updated and moved to test/.
               Added installer.
               Added runtime to results.
               close_fds is now False when running subprocesses.
               Added pid to results.
20130408 1.2   Various clean ups and minor internal changes.
               Removed compressed version, mostly laziness.
20130802 1.4b  Added stdin support.
               Reworked function param checks.

install
=======
python setup.py install

truth
=====
This program is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the Free
Software Foundation, version 3 of the License.

This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
more details.

You should have received a copy of the GNU General Public License along
with this program. If not, see <http://www.gnu.org/licenses/>.

This program may contain bugs or do very bad things. I have done fairly
extensive testing, but certainly may not have uncovered all bugs or corner
cases. I am not a professional programmer. Criticisms and fixes welcome.

pyshell
=======
pyshell provides two user facing functions that execute shell commands and
return results in a normalized manner.

command() returns a namedtuple and multi_command() returns a namedtuple
generator:

result.command  <str>   command
result.pid      <int>   pid of process (None on exception)
result.retval   <int>   retval
result.runtime  <float> runtime down to ms (None on exception)
result.output   <list>  output split by line, stripped of vertical and
                        horizontal whitespace

retval = -9 on command timeout
retval = 127 on command not found
retval = 257 on exception

On retval -9 or 127 a standard description is returned as output. On retval
257, format_exc() is returned. Otherwise stdout + stderr is returned.

------------------------------------------------------------------
command(<str> command, <int|float> timeout=10, <mixed> stdin=None)
------------------------------------------------------------------
Executes a command with a timeout. Returns the result as a namedtuple.

result = pyshell.command('whoami', 2)

print result.command
print result.pid
print result.retval
print result.runtime
print result.output

-----------------------------------------------------------------------
multi_command(<list> commands, <int|float> timeout=10, <int> workers=4,
              <list> stdins=None
-----------------------------------------------------------------------
Executes commands concurrently with individual timeouts in a pool of workers.
Length of stdins must match commands, empty indexes must contain None. Returns
ordered results as a namedtuple generator.

results = pyshell.multi_command(['whoami', 'uptime'], 2)

for result in results:
  print result.command
  print result.pid
  print result.retval
  print result.runtime
  print result.output
  print
