Expect Module for Python
------------------------

This is Python module that does most of what you would normally
need from Tcl's expect, but it works like a standard popen(1)
call but with BOTH reading AND writing.


FTP:
----

ftp://ftp.obsidian.co.za/pub/expect/


Example:
--------

   #!/usr/bin/python

   import sys
   from expect import *

   f = popen2 ("passwd " + sys.argv[1])
   print f.read ("word: ")
   f.write (sys.argv[2])
   print f.read ("word: ")
   f.write (sys.argv[2])
   print f.read ()

or

   #!/usr/bin/python

   import sys, time
   from expect import *

   f = popen2 ("passwd " + sys.argv[1], "p")
   print f.read (": ")
   time.sleep (0.1)
   f.write (sys.argv[2] + "\r\n")
   print f.read (":")
   time.sleep (0.1)
   f.write (sys.argv[2] + "\r\n")
   print f.read()


Classes:
--------

There are three classes defined by this module:
   popen - this is like a standard UNIX popen command
           the difference being that you can both read
           and write to the result file object. The stderr
           stream of the process is NOT redirected and
           will hence appear on the terminal exactly like
           with popen or back-quotes under sh.

   popen2 - like popen, but both stderr AND stdout of the
           process can be read through the same pipe. i.e.
           f.read() calls return ALL output of the process.

   popen3 - like popen2, but stderr and stdout are read
           through two separate functions: f.read()
           returns stdout of the process. f.read_error()
           returns stderr.


How it works:
-------------

This is a completely standalone implementation of popen. It does
not rely on the existing popen in any way.

The problem with reading and writing to a process is that it is
easy to write code that blocks indefinitely waiting for IO.

This library works by queueing reads when doing either a read or
a write call. Read operations are buffered so that incoming data
(the stderr and stdout of the process) are queued in
anticipation of any future read(). write() operations are
unbuffered.

This allows you to arbitrarily read to and write from a process
without worrying about an indefinite block. It is hence very
similar to Tcl's expect program.


Invocation:
-----------

f = popen (command, options)
f = popen2 (command, options)
f = popen3 (command, options)

command is a string. command is a shell program passed as <arg> to
   /bin/sh -c <arg>
options is a string. If options contains the character `b' then the
blocking is turned off. read() and write() will then not block waiting
for data. This is untested.

If options contains the character `p', then a pseudo tty is
opened for the process. The process will still inherit all
environment variables, hence for consistent behaviour, the
caller may want to explicitly set the TERM environment variable.
Note that many programs follow different behaviour depending on
whether they are attached to a tty or not.

In the passwd examples above, passwd is happy to read from a
pipe. If you use a terminal (`p') then you are required to send
a '\n' at the end of the line, and pause a small amount while
the getpass C library function switches into ICANON mode
(whatever that is) causing passwd to raw read separately from
the normal read queue.

All other letters passed to options are ignored.


Methods:
--------

f.read (integer)
   * Can take a normal integer to read a finite amount of data in the
       same way as usual file object's read does.

f.read ()
   * If no arguments are passed, then this reads as much data as is
       outputted by the process, blocking until it reads nothing
       (i.e. the process has exited).

f.read (string)
   * If a single string is passed, then read() reads up to and
       including the matching string.

f.read ((string, string, ...))
   * If a tuple of strings are passed, then read() reads up to and
       including the first matching string.

f.read_error ()
   * works just like read. Typically you would check for errors with
       read_error() after calling read().

f.close ()
   * closes all pipes and returns the exit code of the process. If
       the process has been killed, then this raises an error giving
       the terminating signal.

f.flush ()
   * does nothing

f.isatty ()
   * returns 0

f.readline ()
   * reads up to an including a newline character. takes no arguments

f.readlines ()
   * analogous to file objects readline(). takes no arguments

f.seek (offset, whence)
   * reads and discards offset amount of data. whence must be 1.
       returns nothing

f.tell ()
   * returns the total amount of data read from stdout (or in the case
       of popen2) from stdout and stderr.

f.writelines (list)
   * analogous to file objects writelines (). returns nothing.

f.pid ()
   * get the pid of the child process. Returns -1 if the child
       has died.

f.setblocking (block)
   * takes an integer. 1 turns blocking on, 0 turns blocking off.
       This overrides the options string.

f.command
   * a copy of the command.


Backquote notation:
-------------------

Backquotes work the same as in sh. It does this by binding the
the __repr__ method. Hence

   a=`popen ("echo hello")`

Works just like

   a=`echo hello`

under a sh or perl.


Intricacies:
------------


- To save invocation of /bin/sh, popen checks if the command
   contains any shell special characters i.e.  > ` ! < & $ \n ;
   ( ) { }  and then, failing this, tries to interpret the
   command-line by itself, following the exact conventions of
   bash. If you are not convinced, add in a ; at the end of
   your command to force use of /bin/sh.

- If you try to close a process that has stopped or still executing,
   close blocks waiting for the process to die.

- del f  is just like f.close, but sends the process the
   SIGTERM signal before blocking waiting for the child to die.
   Since a process can intercept the SIGTERM signal, its is
   still possible for Python to block at an arbitrary location.
   For instance:

       def func ():
           f = popen2 ("prog")
           time.sleep (0.1)

       func ()

   If prog were to ignore SIGTERM, then func would block until
   prog had exited because python dereferences  f  before
   returning from func.

   (The reason you need to sleep(0.1) is to give prog a chance
   to set its signal handlers.)

- f.p is the internal object that you would normally not be
   interested in. However `f.p` prints useful output like:

       f = popen2 ("echo 'Hi there!'")
       print `f.p`
       <ExpectObject running command "echo 'Hi there!'" as
               pid 10373 at 80b30c0>

- You can carry on reading from a process even after it has
   died and been close()'d. So long as there is still data
   in the queue. If there is no data, read just returns an
   empty string.

- Opening a pty currently works BSD style using /dev/pty??
   To support other kinds, I'll probably copy some of the
   rxvt code across.