[Python-modules-commits] r931 - in /packages/pexpect/trunk: ANSI.py FSM.py INSTALL LICENSE PKG-INFO README debian/changelog debian/control debian/python2.3-pexpect.docs debian/python2.4-pexpect.docs debian/rules doc/ examples/ fdpexpect.py pexpect.py pxssh.py screen.py setup.py

rganesan at users.alioth.debian.org rganesan at users.alioth.debian.org
Mon Jun 19 11:41:29 UTC 2006


Author: rganesan
Date: Mon Jun 19 11:41:27 2006
New Revision: 931

URL: http://svn.debian.org/wsvn/python-modules/?sc=1&rev=931
Log:
* New upstream version (2.1)
* Support new python policy.


Added:
    packages/pexpect/trunk/INSTALL
      - copied unchanged from r930, packages/pexpect/branches/upstream/current/INSTALL
    packages/pexpect/trunk/LICENSE
      - copied unchanged from r930, packages/pexpect/branches/upstream/current/LICENSE
    packages/pexpect/trunk/doc/
      - copied from r930, packages/pexpect/branches/upstream/current/doc/
    packages/pexpect/trunk/examples/
      - copied from r930, packages/pexpect/branches/upstream/current/examples/
    packages/pexpect/trunk/fdpexpect.py
      - copied unchanged from r930, packages/pexpect/branches/upstream/current/fdpexpect.py
Removed:
    packages/pexpect/trunk/debian/python2.3-pexpect.docs
    packages/pexpect/trunk/debian/python2.4-pexpect.docs
Modified:
    packages/pexpect/trunk/ANSI.py
    packages/pexpect/trunk/FSM.py
    packages/pexpect/trunk/PKG-INFO
    packages/pexpect/trunk/README
    packages/pexpect/trunk/debian/changelog
    packages/pexpect/trunk/debian/control
    packages/pexpect/trunk/debian/rules
    packages/pexpect/trunk/pexpect.py
    packages/pexpect/trunk/pxssh.py
    packages/pexpect/trunk/screen.py
    packages/pexpect/trunk/setup.py

Modified: packages/pexpect/trunk/ANSI.py
URL: http://svn.debian.org/wsvn/python-modules/packages/pexpect/trunk/ANSI.py?rev=931&op=diff
==============================================================================
--- packages/pexpect/trunk/ANSI.py (original)
+++ packages/pexpect/trunk/ANSI.py Mon Jun 19 11:41:27 2006
@@ -1,6 +1,6 @@
 '''
-$Revision: 1.10 $
-$Date: 2003/02/06 23:53:30 $
+$Revision: 374 $
+$Date: 2006-03-06 18:47:28 -0800 (Mon, 06 Mar 2006) $
 
 '''
 # references:
@@ -19,7 +19,7 @@
 
 def Emit (fsm):
         screen = fsm.something[0]
-        screen.write(fsm.input_symbol)
+        screen.write_ch(fsm.input_symbol)
 def StartNumber (fsm):
         fsm.something.append (fsm.input_symbol)
 def BuildNumber (fsm):
@@ -202,30 +202,23 @@
     def process (self, c):
         self.state.process(c)
     def process_list (self, l):
-        for c in l:
-            self.process (c)
-
-    def test (self):
-        import sys
-        dump = file('dump').read()
-        for c in dump:
-                self.state.process(c)
-                sys.stdout.write (c)
-                sys.stdout.flush()
-        print str(self)
-
-
-    def write (self, ch):
+        self.write(l)
+    def write (self, s):
+        for c in s:
+            self.process(c)
+    def flush (self):
+        pass
+    def write_ch (self, ch):
         '''Puts a character at the current cursor position.
         cursor position if moved forward with wrap-around, but
         no scrolling is done if the cursor hits the lower-right corner
         of the screen.
-        \r and \n both produce a call to crlf().
         '''
+        #\r and \n both produce a call to crlf().
         ch = ch[0]
 
         if ch == '\r':
-            self.crlf()
+        #    self.crlf()
             return
         if ch == '\n':
             self.crlf()
@@ -239,7 +232,6 @@
             fout = open ('log', 'a')
             fout.write ('Nonprint: ' + str(ord(ch)))
             fout.close()
-
             return
         self.put_abs(self.cur_r, self.cur_c, ch)
         old_r = self.cur_r
@@ -253,6 +245,37 @@
                 self.scroll_up ()
                 self.cursor_home (self.cur_r, 1)
                 self.erase_line()
+
+    def test (self):
+        import sys
+        write_text = 'I\'ve got a ferret sticking up my nose.\n' + \
+        '(He\'s got a ferret sticking up his nose.)\n' + \
+        'How it got there I can\'t tell\n' + \
+        'But now it\'s there it hurts like hell\n' + \
+        'And what is more it radically affects my sense of smell.\n' + \
+        '(His sense of smell.)\n' + \
+        'I can see a bare-bottomed mandril.\n' + \
+        '(Slyly eyeing his other nostril.)\n' + \
+        'If it jumps inside there too I really don\'t know what to do\n' + \
+        'I\'ll be the proud posessor of a kind of nasal zoo.\n' + \
+        '(A nasal zoo.)\n' + \
+        'I\'ve got a ferret sticking up my nose.\n' + \
+        '(And what is worst of all it constantly explodes.)\n' + \
+        '"Ferrets don\'t explode," you say\n' + \
+        'But it happened nine times yesterday\n' + \
+        'And I should know for each time I was standing in the way.\n' + \
+        'I\'ve got a ferret sticking up my nose.\n' + \
+        '(He\'s got a ferret sticking up his nose.)\n' + \
+        'How it got there I can\'t tell\n' + \
+        'But now it\'s there it hurts like hell\n' + \
+        'And what is more it radically affects my sense of smell.\n' + \
+        '(His sense of smell.)'
+        self.fill('.')
+        self.cursor_home()
+        for c in write_text:
+            self.write_ch (c)
+        print str(self)
+
 if __name__ == '__main__':
-    t = ANSI()
+    t = ANSI(6,65)
     t.test()

Modified: packages/pexpect/trunk/FSM.py
URL: http://svn.debian.org/wsvn/python-modules/packages/pexpect/trunk/FSM.py?rev=931&op=diff
==============================================================================
--- packages/pexpect/trunk/FSM.py (original)
+++ packages/pexpect/trunk/FSM.py Mon Jun 19 11:41:27 2006
@@ -60,8 +60,8 @@
 
 Noah Spurrier
 
-$Revision: 1.2 $
-$Date: 2002/08/28 19:07:03 $
+$Revision: 33 $
+$Date: 2002-08-28 12:07:03 -0700 (Wed, 28 Aug 2002) $
 
 '''
 

Modified: packages/pexpect/trunk/PKG-INFO
URL: http://svn.debian.org/wsvn/python-modules/packages/pexpect/trunk/PKG-INFO?rev=931&op=diff
==============================================================================
--- packages/pexpect/trunk/PKG-INFO (original)
+++ packages/pexpect/trunk/PKG-INFO Mon Jun 19 11:41:27 2006
@@ -1,10 +1,10 @@
 Metadata-Version: 1.0
 Name: pexpect
-Version: 2.0
+Version: 2.1
 Summary: Pexpect is a pure Python Expect. It allows easy control of other applications.
 Home-page: http://pexpect.sourceforge.net/
 Author: Noah Spurrier
 Author-email: noah at noah.org
-License: Python Software Foundation License
+License: MIT license
 Description: UNKNOWN
 Platform: UNIX

Modified: packages/pexpect/trunk/README
URL: http://svn.debian.org/wsvn/python-modules/packages/pexpect/trunk/README?rev=931&op=diff
==============================================================================
--- packages/pexpect/trunk/README (original)
+++ packages/pexpect/trunk/README Mon Jun 19 11:41:27 2006
@@ -16,7 +16,26 @@
 extensions to be compiled. It should work on any platform that supports the
 standard Python pty module. The Pexpect interface was designed to be easy to use.
 
-License: Python Software Foundation License
+Free, open source, and all that good stuff.
+Pexpect Copyright (c) 2006 Noah Spurrier
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+USE OR OTHER DEALINGS IN THE SOFTWARE.
 
 Noah Spurrier
 http://pexpect.sourceforge.net/

Modified: packages/pexpect/trunk/debian/changelog
URL: http://svn.debian.org/wsvn/python-modules/packages/pexpect/trunk/debian/changelog?rev=931&op=diff
==============================================================================
--- packages/pexpect/trunk/debian/changelog (original)
+++ packages/pexpect/trunk/debian/changelog Mon Jun 19 11:41:27 2006
@@ -1,10 +1,13 @@
-pexpect (2.1-1) UNRELEASED; urgency=low
+pexpect (2.1-1) unstable; urgency=low
 
-  * New upstream version
-  * Added watch file
+  * New upstream version.
+  * Included pxssh.py and fdpxpect.py (Closes: #356128).
+  * Included docs and examples (Closes:  #230850).
+  * Updated for new python policy using python-central (Closes: #373476).
+  * Added watch file.
 
- -- Piotr Ozarowski <ozarow at gmail.com>  Tue,  6 Jun 2006 13:42:37 +0200
-  
+ -- Ganesan Rajagopal <rganesan at debian.org>  Mon, 19 Jun 2006 16:43:58 +0530
+
 pexpect (2.0-2) unstable; urgency=low
 
   * Included pexpect package into Python Modules repository.

Modified: packages/pexpect/trunk/debian/control
URL: http://svn.debian.org/wsvn/python-modules/packages/pexpect/trunk/debian/control?rev=931&op=diff
==============================================================================
--- packages/pexpect/trunk/debian/control (original)
+++ packages/pexpect/trunk/debian/control Mon Jun 19 11:41:27 2006
@@ -1,45 +1,22 @@
 Source: pexpect
 Section: python
 Priority: optional
-Build-Depends-Indep: python, python2.3-dev, python2.4-dev, debhelper (>> 4.1.52)
+Build-Depends-Indep: python-all-dev (>= 2.3.5-10), python-central (>= 0.4.17), debhelper (>= 5.0.37.1)
+XS-Python-Version: all
 Maintainer: Ganesan Rajagopal <rganesan at debian.org>
 Uploaders: Debian Python Modules Team <python-modules-team at lists.alioth.debian.org>
-Standards-Version: 3.6.2
+Standards-Version: 3.7.2
 
 Package: python-pexpect
 Architecture: all
 Depends: ${python:Depends}
-Description: Python module for automating interactive applications (dummy)
+Provides: ${python:Provides}
+Conflicts: python2.3-pexpect, python2.4-pexpect
+Replaces: python2.3-pexpect, python2.4-pexpect
+XB-Python-Version: ${python:Versions}
+Description: Python module for automating interactive applications
  Pexpect is a pure Python module for spawning child applications;
  controlling them; and responding to expected patterns in their
  output. Pexpect works like Don Libes' Expect. Pexpect allows your
  script to spawn a child application and control it as if a human were
  typing commands.  
- .
- This package is an empty dummy package that always depends on a package
- built for Debian's default Python version.   
-
-Package: python2.3-pexpect
-Architecture: all
-Depends: python2.3
-Description: Python 2.3.x module for automating interactive applications 
- Pexpect is a pure Python module for spawning child applications;
- controlling them; and responding to expected patterns in their
- output. Pexpect works like Don Libes' Expect. Pexpect allows your
- script to spawn a child application and control it as if a human were
- typing commands.  
- .
- This package is built for Python 2.3.x
-
-Package: python2.4-pexpect
-Architecture: all
-Depends: python2.4
-Description: Python 2.4.x module for automating interactive applications 
- Pexpect is a pure Python module for spawning child applications;
- controlling them; and responding to expected patterns in their
- output. Pexpect works like Don Libes' Expect. Pexpect allows your
- script to spawn a child application and control it as if a human were
- typing commands.  
- .
- This package is built for Python 2.4.x
-

Modified: packages/pexpect/trunk/debian/rules
URL: http://svn.debian.org/wsvn/python-modules/packages/pexpect/trunk/debian/rules?rev=931&op=diff
==============================================================================
--- packages/pexpect/trunk/debian/rules (original)
+++ packages/pexpect/trunk/debian/rules Mon Jun 19 11:41:27 2006
@@ -4,28 +4,28 @@
 #export DH_VERBOSE=1
 
 # This is the debhelper compatibility version to use.
-export DH_COMPAT=4
+export DH_COMPAT=5
 
-PYTHON2.3 = /usr/bin/python2.3
-PYTHON2.4 = /usr/bin/python2.4
+PYVERS	:= $(shell pyversions -vr debian/control)
+DEB_UPSTREAM_VERSION := $(shell dpkg-parsechangelog \
+                         | grep ^Version: | cut -d ' ' -f 2 | cut -d '-' -f 1)
+PYMOD	= pexpect
+d	= debian/python-pexpect
 
-configure: configure-stamp
-configure-stamp:
+build: $(PYVERS:%=build-python%)
+	touch $@
+
+build-python%:
 	dh_testdir
-	touch configure-stamp
-
-build: configure-stamp build-stamp
-build-stamp:
-	dh_testdir
-	$(PYTHON2.3) setup.py build
-	$(PYTHON2.4) setup.py build
+	python$* setup.py build
 	touch build-stamp
 
 clean:
 	dh_testdir
 	dh_testroot
-	rm -f build-stamp configure-stamp
-	rm -rf build
+	rm -f build-stamp build-python*
+	rm -rf build dist
+	rm -f pexpect/*.pyc 
 	dh_clean
 
 install: build
@@ -33,11 +33,10 @@
 	dh_testroot
 	dh_clean -k
 	dh_installdirs
+	$(MAKE) -f debian/rules $(PYVERS:%=install-python%)
 
-	$(PYTHON2.3) setup.py install --root=debian/python2.3-pexpect \
-            --no-compile
-	$(PYTHON2.4) setup.py install --root=debian/python2.4-pexpect \
-            --no-compile
+install-python%:
+	python$* setup.py install --no-compile --root=$(d)
 
 # Build architecture-independent files here.
 binary-indep: build install
@@ -48,7 +47,9 @@
 	dh_installexamples -i
 	dh_installchangelogs -i
 	dh_link -i
+	dh_pycentral -i
 	dh_python -i
+	echo python:Provides=$(foreach pv,$(shell pyversions -s),$(pv)-pexpect)|sed 's/ /, /g' >> debian/python-clientcookie.substvars
 	dh_compress -i
 	dh_fixperms -i
 	dh_installdeb -i

Modified: packages/pexpect/trunk/pexpect.py
URL: http://svn.debian.org/wsvn/python-modules/packages/pexpect/trunk/pexpect.py?rev=931&op=diff
==============================================================================
--- packages/pexpect/trunk/pexpect.py (original)
+++ packages/pexpect/trunk/pexpect.py Mon Jun 19 11:41:27 2006
@@ -1,55 +1,67 @@
-"""Pexpect is a Python module for spawning child applications;
-controlling them; and responding to expected patterns in their output.
-Pexpect can be used for automating interactive applications such as
-ssh, ftp, passwd, telnet, etc. It can be used to a automate setup scripts
-for duplicating software package installations on different servers.
-It can be used for automated software testing. Pexpect is in the spirit of
-Don Libes' Expect, but Pexpect is pure Python. Other Expect-like
-modules for Python require TCL and Expect or require C extensions to
-be compiled. Pexpect does not use C, Expect, or TCL extensions. It
-should work on any platform that supports the standard Python pty
-module. The Pexpect interface focuses on ease of use so that simple
-tasks are easy.
-
-There are two main interfaces to Pexpect. You can call the function:
-        pexpect.run()
-to execute a command and return the output.
-Do no use this on interactive commands that expect input.
-This is a handy replacment for os.system().
-The more useful interface is the class:
-        pexpect.spawn()
-This creates a spawn instance. This will start the command that you specify.
-You can then interact with the child command through the spawn instance.
-Most commands, including ssh, cannot tell that they are being run inside
-of a script. This works even for commands that ask for passwords or
-other input outside of the normal stdio streams.
-
-Pexpect is Open Source, Free, and all that good stuff.
-License: Python Software Foundation License
-         http://www.opensource.org/licenses/PythonSoftFoundation.html
-
-Noah Spurrier
-Richard Holden
-Marco Molteni
-Kimberley Burchett 
-Robert Stone
-Mike Snitzer
-Marti Raudsepp
-Matt <matt (*) corvil.com>
-Hartmut Goebel
-Chad Schroeder
-Erick Tryzelaar
-Dave Kirby
-Ids vander Molen
-George Todd
-Noel Taylor
-Nicolas D. Cesar
+"""Pexpect is a Python module for spawning child applications and controlling
+them automatically. Pexpect can be used for automating interactive applications
+such as ssh, ftp, passwd, telnet, etc. It can be used to a automate setup
+scripts for duplicating software package installations on different servers. It
+can be used for automated software testing. Pexpect is in the spirit of Don
+Libes' Expect, but Pexpect is pure Python. Other Expect-like modules for Python
+require TCL and Expect or require C extensions to be compiled. Pexpect does not
+use C, Expect, or TCL extensions. It should work on any platform that supports
+the standard Python pty module. The Pexpect interface focuses on ease of use so
+that simple tasks are easy.
+
+There are two main interfaces to Pexpect -- the function, run() and the class,
+spawn. You can call the run() function to execute a command and return the
+output. This is a handy replacement for os.system().
+
+For example:
+    pexpect.run('ls -la')
+
+The more powerful interface is the spawn class. You can use this to spawn an
+external child command and then interact with the child by sending lines and
+expecting responses.
+
+For example:
+    child = pexpect.spawn('scp foo myname at host.example.com:.')
+    child.expect ('Password:')
+    child.sendline (mypassword)
+
+This works even for commands that ask for passwords or other input outside of
+the normal stdio streams.
+
+Credits:
+Noah Spurrier, Richard Holden, Marco Molteni, Kimberley Burchett, Robert Stone,
+Hartmut Goebel, Chad Schroeder, Erick Tryzelaar, Dave Kirby, Ids vander Molen,
+George Todd, Noel Taylor, Nicolas D. Cesar, Alexander Gattin,
+Geoffrey Marshall, Francisco Lourenco, Glen Mabey, Karthik Gurusamy,
+Fernando Perez 
 (Let me know if I forgot anyone.)
 
-$Revision: 1.151 $
-$Date: 2005/11/17 01:19:42 $
+Free, open source, and all that good stuff.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+Pexpect Copyright (c) 2006 Noah Spurrier
+http://pexpect.sourceforge.net/
+
+$Revision: 395 $
+$Date: 2006-05-31 20:07:18 -0700 (Wed, 31 May 2006) $
 """
-
 try:
     import os, sys, time
     import select
@@ -70,8 +82,8 @@
 A critical module was not found. Probably this operating system does not support it.
 Pexpect is intended for UNIX-like operating systems.""")
 
-__version__ = '2.0'
-__revision__ = '$Revision: 1.151 $'
+__version__ = '2.1'
+__revision__ = '$Revision: 395 $'
 __all__ = ['ExceptionPexpect', 'EOF', 'TIMEOUT', 'spawn', 'run', 'which', 'split_command_line',
     '__version__', '__revision__']
 
@@ -93,9 +105,9 @@
         return ''.join(tblist)
     def __filter_not_pexpect(self, trace_list_item):
         if trace_list_item[0].find('pexpect.py') == -1:
-            return 1
+            return True
         else:
-            return 0
+            return False
 class EOF(ExceptionPexpect):
     """Raised when EOF is read from a child.
     """
@@ -111,7 +123,7 @@
 ##class MAXBUFFER(ExceptionPexpect):
 ##    """Raised when a scan buffer fills before matching an expected pattern."""
 
-def run (command, timeout=-1, withexitstatus=0, events=None, extra_args=None):
+def run (command, timeout=-1, withexitstatus=False, events=None, extra_args=None, logfile=None):
     """This function runs the given command; waits for it to finish;
     then returns all output as a string. STDERR is included in output.
     If the full path to the command is not given then the path is searched.
@@ -121,6 +133,17 @@
     If you set withexitstatus to true, then run will return a tuple of
     (command_output, exitstatus). If withexitstatus is false then this
     returns just command_output.
+
+    The run() function can often be used instead of creating a spawn instance.
+    For example, the following code uses spawn:
+        from pexpect import *
+        child = spawn('scp foo myname at host.example.com:.')
+        child.expect ('(?i)password')
+        child.sendline (mypassword)
+    The previous code can be replace with the following, which you may
+    or may not find simpler:
+        from pexpect import *
+        run ('scp foo myname at host.example.com:.', events={'(?i)password': mypassword})
 
     Examples:
     Start the apache daemon on the local machine:
@@ -161,9 +184,9 @@
     a callback function through run() through the locals dictionary passed to a callback.
     """
     if timeout == -1:
-        child = spawn(command, maxread=2000)
+        child = spawn(command, maxread=2000, logfile=logfile)
     else:
-        child = spawn(command, timeout=timeout, maxread=2000)
+        child = spawn(command, timeout=timeout, maxread=2000, logfile=logfile)
     if events is not None:
         patterns = events.keys()
         responses = events.values()
@@ -204,12 +227,12 @@
     else:
         return child_result
 
-class spawn:
+class spawn (object):
     """This is the main class interface for Pexpect.
     Use this class to start and control child applications.
     """
 
-    def __init__(self, command, args=[], timeout=30, maxread=2000, searchwindowsize=None, logfile=None):
+    def __init__(self, command, args=[], timeout=30, maxread=2000, searchwindowsize=None, logfile=None, env=None):
         """This is the constructor. The command parameter may be a string
         that includes a command and any arguments to the command. For example:
             p = pexpect.spawn ('/usr/bin/ftp')
@@ -224,9 +247,11 @@
         send() and sendline().
 
         The maxread attribute sets the read buffer size.
-        This is maximum number of bytes that Pexpect will try to read from a TTY at one time.
-        The default buffer size is 1 (unbuffered). Setting this value higher
-        will help performance in cases where large amounts of output are read back from the child.
+        This is maximum number of bytes that Pexpect will try to read
+        from a TTY at one time.
+        Seeting the maxread size to 1 will turn off buffering.
+        Setting the maxread value higher may help performance in cases
+        where large amounts of output are read back from the child.
         This feature is useful in conjunction with searchwindowsize.
         
         The searchwindowsize attribute sets the how far back in
@@ -252,10 +277,10 @@
             child = pexpect.spawn('some_command')
             child.logfile = sys.stdout
             
-        The delaybeforesend helps overcome weird behavior that many users were experiencing.
+        The delaybeforesend helps overcome a weird behavior that many users were experiencing.
         The typical problem was that a user would expect() a "Password:" prompt and
         then immediately call sendline() to send the password. The user would then
-        see that their password was echoed back to them. Of course, passwords don't
+        see that their password was echoed back to them. Passwords don't
         normally echo. The problem is caused by the fact that most applications
         print out the "Password" prompt and then turn off stdin echo, but if you
         send your password before the application turned off echo, then you get
@@ -289,15 +314,16 @@
         self.stderr = sys.stderr
 
         self.patterns = None
+        self.ignorecase = False
         self.before = None
         self.after = None
         self.match = None
         self.match_index = None
-        self.terminated = 1
+        self.terminated = True
         self.exitstatus = None
         self.signalstatus = None
-        self.status = None
-        self.flag_eof = 0
+        self.status = None # status returned by os.waitpid 
+        self.flag_eof = False
         self.pid = None
         self.child_fd = -1 # initially closed
         self.timeout = timeout
@@ -307,13 +333,29 @@
         self.buffer = '' # This is the read buffer. See maxread.
         self.searchwindowsize = searchwindowsize # Anything before searchwindowsize point is preserved, but not searched.
         self.delaybeforesend = 0.1 # Sets sleep time used just before sending data to child.
-        self.softspace = 0 # File-like object.
+        self.delayafterclose = 0.1 # Sets delay in close() method to allow kernel time to update process status.
+        self.delayafterterminate = 0.1 # Sets delay in terminate() method to allow kernel time to update process status.
+        self.softspace = False # File-like object.
         self.name = '<' + repr(self) + '>' # File-like object.
         self.encoding = None # File-like object.
-        self.closed = 1 # File-like object.
-        
+        self.closed = True # File-like object.
+        self.env = env
+        self.__irix_hack = sys.platform.lower().find('irix') >= 0 # This flags if we are running on irix
+        self.use_native_pty_fork = not (sys.platform.lower().find('solaris') >= 0) # Solaris uses internal __fork_pty(). All other use pty.fork().
+
+        # allow dummy instances for subclasses that may not use command or args.
+        if command is None:
+            self.command = None
+            self.args = None
+            self.name = '<pexpect factory incomplete>'
+            return
+
+        # If command is an int type then it may represent a file descriptor.
+        if type(command) == type(0):
+            raise ExceptionPexpect ('Command is an int type. If this is a file descriptor then maybe you want to use fdpexpect.fdspawn which takes an existing file descriptor instead of a command string.')
+
         if type (args) != type([]):
-            raise TypeError ('The second argument, args, must be a list.')
+            raise TypeError ('The argument, args, must be a list.')
 
         if args == []:
             self.args = split_command_line(command)
@@ -324,7 +366,7 @@
             self.command = command
 
         command_with_path = which(self.command)
-        if command_with_path == None:
+        if command_with_path is None:
             raise ExceptionPexpect ('The command was not found or was not executable: %s.' % self.command)
         self.command = command_with_path
         self.args[0] = self.command
@@ -339,9 +381,8 @@
         If the child file descriptor was opened outside of this class
         (passed to the constructor) then this does not close it.
         """
-        if self.closed:
-            return
-        self.close()
+        if not self.closed:
+            self.close()
 
     def __str__(self):
         """This returns the current state of the pexpect object as a string.
@@ -369,12 +410,16 @@
         s.append('flag_eof: ' + str(self.flag_eof))
         s.append('pid: ' + str(self.pid))
         s.append('child_fd: ' + str(self.child_fd))
+        s.append('closed: ' + str(self.closed))
         s.append('timeout: ' + str(self.timeout))
         s.append('delimiter: ' + str(self.delimiter))
         s.append('logfile: ' + str(self.logfile))
         s.append('maxread: ' + str(self.maxread))
+        s.append('ignorecase: ' + str(self.ignorecase))
         s.append('searchwindowsize: ' + str(self.searchwindowsize))
         s.append('delaybeforesend: ' + str(self.delaybeforesend))
+        s.append('delayafterclose: ' + str(self.delayafterclose))
+        s.append('delayafterterminate: ' + str(self.delayafterterminate))
         return '\n'.join(s)
 
     def __spawn(self):
@@ -391,19 +436,26 @@
         # That may not necessarily be bad because you may haved spawned a child
         # that performs some task; creates no stdout output; and then dies.
 
-        assert self.pid == None, 'The pid member should be None.'
-        assert self.command != None, 'The command member should not be None.'
-
-        try:
-            self.pid, self.child_fd = pty.fork()
-        except OSError, e:
-            raise ExceptionPexpect('Pexpect: pty.fork() failed: ' + str(e))
+        assert self.pid is None, 'The pid member should be None.'
+        assert self.command is not None, 'The command member should not be None.'
+
+        if self.use_native_pty_fork:
+            try:
+                self.pid, self.child_fd = pty.fork()
+            except OSError, e:
+                raise ExceptionPexpect('Error! pty.fork() failed: ' + str(e))
+        else: # Use internal __fork_pty
+            self.pid, self.child_fd = self.__fork_pty() 
 
         if self.pid == 0: # Child
-            try: # Some platforms do not like setwinsize (Cygwin).
+            try: 
                 self.child_fd = sys.stdout.fileno() # used by setwinsize()
                 self.setwinsize(24, 80)
-            except:
+            except: 
+                # Some platforms do not like setwinsize (Cygwin).
+                # This will cause problem when running applications that
+                # are very picky about window size.
+                # This is a serious limitation, but not a show stopper.
                 pass
             # Do not allow child to inherit open file descriptors from parent.
             max_fd = resource.getrlimit(resource.RLIMIT_NOFILE)[0]
@@ -418,30 +470,106 @@
             # (specifically, Tomcat).
             signal.signal(signal.SIGHUP, signal.SIG_IGN)
 
-            os.execv(self.command, self.args)
+            if self.env is None:
+                os.execv(self.command, self.args)
+            else:
+                os.execvpe(self.command, self.args, self.env)
 
         # Parent
-        self.terminated = 0
-        self.closed = 0
-
+        self.terminated = False
+        self.closed = False
+
+    def __fork_pty(self):
+        """This implements a substitute for the forkpty system call.
+        This should be more portable than the pty.fork() function.
+        Specifically, this should work on Solaris.
+        
+        Modified 10.06.05 by Geoff Marshall:
+            Implemented __fork_pty() method to resolve the issue with Python's 
+            pty.fork() not supporting Solaris, particularly ssh.
+        Based on patch to posixmodule.c authored by Noah Spurrier:
+            http://mail.python.org/pipermail/python-dev/2003-May/035281.html
+        """
+        parent_fd, child_fd = os.openpty()
+        if parent_fd < 0 or child_fd < 0:
+            raise ExceptionPexpect, "Error! Could not open pty with os.openpty()."
+        
+        pid = os.fork()
+        if pid < 0:
+            raise ExceptionPexpect, "Error! Failed os.fork()."
+        elif pid == 0:
+            # Child.
+            os.close(parent_fd)
+            self.__pty_make_controlling_tty(child_fd)
+            
+            os.dup2(child_fd, 0)
+            os.dup2(child_fd, 1)
+            os.dup2(child_fd, 2)
+            
+            if child_fd > 2:
+                os.close(child_fd)
+        else:
+            # Parent.
+            os.close(child_fd)
+        
+        return pid, parent_fd
+                
+    def __pty_make_controlling_tty(self, tty_fd):
+        """This makes the pseudo-terminal the controlling tty.
+        This should be more portable than the pty.fork() function.
+        Specifically, this should work on Solaris.
+        """
+        child_name = os.ttyname(tty_fd)
+        
+        # Disconnect from controlling tty if still connected.
+        fd = os.open("/dev/tty", os.O_RDWR | os.O_NOCTTY);
+        if fd >= 0:
+            os.close(fd)
+            
+        os.setsid()
+        
+        # Verify we are disconnected from controlling tty
+        try:
+            fd = os.open("/dev/tty", os.O_RDWR | os.O_NOCTTY);
+            if fd >= 0:
+                os.close(fd)
+                raise ExceptionPexpect, "Error! We are not disconnected from a controlling tty."
+        except:
+            # Good! We are disconnected from a controlling tty.
+            pass
+        
+        # Verify we can open child pty.
+        fd = os.open(child_name, os.O_RDWR);
+        if fd < 0:
+            raise ExceptionPexpect, "Error! Could not open child pty, " + child_name
+        else:
+            os.close(fd)
+
+        # Verify we now have a controlling tty.
+        fd = os.open("/dev/tty", os.O_WRONLY)
+        if fd < 0:
+            raise ExceptionPexpect, "Error! Could not open controlling tty, /dev/tty"
+        else:
+            os.close(fd)
+         
     def fileno (self):   # File-like object.
         """This returns the file descriptor of the pty for the child.
         """
         return self.child_fd
 
-    def close (self, force=0):   # File-like object.
+    def close (self, force=True):   # File-like object.
         """This closes the connection with the child application.
         Note that calling close() more than once is valid.
         This emulates standard Python behavior with files.
-        Set force to 1 if you want to make sure that the child is terminated
+        Set force to True if you want to make sure that the child is terminated
         (SIGKILL is sent if the child ignores SIGHUP and SIGINT).
         """
-        if self.child_fd != -1:
+        if not self.closed:
             self.flush()
             os.close (self.child_fd)
             self.child_fd = -1
-            self.closed = 1
-            time.sleep(0.1) # Give kernel time to update process status.
+            self.closed = True
+            time.sleep(self.delayafterclose) # Give kernel time to update process status.
             if self.isalive():
                 if not self.terminate(force):
                     raise ExceptionPexpect ('close() could not terminate the child using terminate()')
@@ -452,11 +580,11 @@
         pass
 
     def isatty (self):   # File-like object.
-        """This returns 1 if the file descriptor is open and connected to a tty(-like) device, else 0.
+        """This returns True if the file descriptor is open and connected to a tty(-like) device, else False.
         """
         return os.isatty(self.child_fd)
 
-    def setecho (self, on):
+    def setecho (self, state):
         """This sets the terminal echo mode on or off.
         Note that anything the child sent before the echo will be lost, so
         you should be sure that your input buffer is empty before you setecho.
@@ -465,7 +593,7 @@
             p.sendline ('1234') # We will see this twice (once from tty echo and again from cat).
             p.expect (['1234'])
             p.expect (['1234'])
-            p.setecho(0) # Turn off tty echo
+            p.setecho(False) # Turn off tty echo
             p.sendline ('abcd') # We will set this only once (echoed by cat).
             p.sendline ('wxyz') # We will set this only once (echoed by cat)
             p.expect (['abcd'])
@@ -474,7 +602,7 @@
         will be lost:
             p = pexpect.spawn('cat')
             p.sendline ('1234') # We will see this twice (once from tty echo and again from cat).
-            p.setecho(0) # Turn off tty echo
+            p.setecho(False) # Turn off tty echo
             p.sendline ('abcd') # We will set this only once (echoed by cat).
             p.sendline ('wxyz') # We will set this only once (echoed by cat)
             p.expect (['1234'])
@@ -484,14 +612,14 @@
         """
         self.child_fd
         new = termios.tcgetattr(self.child_fd)
-        if on:
+        if state:
             new[3] = new[3] | termios.ECHO
         else:
             new[3] = new[3] & ~termios.ECHO
         # I tried TCSADRAIN and TCSAFLUSH, but these were inconsistent
         # and blocked on some platforms. TCSADRAIN is probably ideal if it worked.
         termios.tcsetattr(self.child_fd, termios.TCSANOW, new)
-
+    
     def read_nonblocking (self, size = 1, timeout = -1):
         """This reads at most size characters from the child application.
         It includes a timeout. If the read does not complete within the
@@ -514,7 +642,7 @@
         This is a wrapper around os.read().
         It uses select.select() to implement a timeout. 
         """
-        if self.child_fd == -1:
+        if self.closed:
             raise ValueError ('I/O operation on closed file in read_nonblocking().')
 
         if timeout == -1:
@@ -526,24 +654,25 @@
         # For this case, I test isalive() before doing any reading.
         # If isalive() is false, then I pretend that this is the same as EOF.
         if not self.isalive():
-            r, w, e = select.select([self.child_fd], [], [], 0) # timeout of 0 means "poll"
+            r,w,e = self.__select([self.child_fd], [], [], 0) # timeout of 0 means "poll"
             if not r:
-                self.flag_eof = 1
+                self.flag_eof = True
                 raise EOF ('End Of File (EOF) in read_nonblocking(). Braindead platform.')
-        elif sys.platform.lower().find('irix') >= 0:
+        elif self.__irix_hack:
             # This is a hack for Irix. It seems that Irix requires a long delay before checking isalive.
-            # This adds a 2 second delay, but only when the child is terminated
-            r, w, e = select.select([self.child_fd], [], [], 2)
+            # This adds a 2 second delay, but only when the child is terminated.
+            r, w, e = self.__select([self.child_fd], [], [], 2)
             if not r and not self.isalive():
-                self.flag_eof = 1
+                self.flag_eof = True
                 raise EOF ('End Of File (EOF) in read_nonblocking(). Pokey platform.')
             
-        r, w, e = select.select([self.child_fd], [], [], timeout)
+        r,w,e = self.__select([self.child_fd], [], [], timeout)
+        
         if not r:
             if not self.isalive():
                 # Some platforms, such as Irix, will claim that their processes are alive;
                 # then timeout on the select; and then finally admit that they are not alive.
-                self.flag_eof = 1
+                self.flag_eof = True
                 raise EOF ('End of File (EOF) in read_nonblocking(). Very pokey platform.')
             else:
                 raise TIMEOUT ('Timeout exceeded in read_nonblocking().')
@@ -552,13 +681,13 @@
             try:
                 s = os.read(self.child_fd, size)
             except OSError, e: # Linux does this
-                self.flag_eof = 1
+                self.flag_eof = True
                 raise EOF ('End Of File (EOF) in read_nonblocking(). Exception style platform.')
             if s == '': # BSD style
-                self.flag_eof = 1
+                self.flag_eof = True
                 raise EOF ('End Of File (EOF) in read_nonblocking(). Empty string style platform.')
 
-            if self.logfile != None:
+            if self.logfile is not None:
                 self.logfile.write (s)
                 self.logfile.flush()
 
@@ -596,12 +725,13 @@
     def readline (self, size = -1):    # File-like object.
         """This reads and returns one entire line. A trailing newline is kept in
         the string, but may be absent when a file ends with an incomplete line. 
-        Note: This readline() looks for a \\r\\n pair even on UNIX because this is 
-        what the pseudo tty device returns. So contrary to what you may be used to
-        you will receive a newline as \\r\\n.
+        Note: This readline() looks for a \\r\\n pair even on UNIX because
+        this is what the pseudo tty device returns. So contrary to what you
+        may expect you will receive the newline as \\r\\n.
         An empty string is returned when EOF is hit immediately.
         Currently, the size agument is mostly ignored, so this behavior is not
-        standard for a file-like object. If size is 0 then an empty string is returned.
+        standard for a file-like object. If size is 0 then an empty string
+        is returned.
         """
         if size == 0:
             return ''
@@ -612,7 +742,7 @@
             return self.before
 
     def __iter__ (self):    # File-like object.
-        """This is to support interators over a file-like object.
+        """This is to support iterators over a file-like object.
         """
         return self
 
@@ -629,7 +759,7 @@
         the lines thus read. The optional "sizehint" argument is ignored.
         """        
         lines = []
-        while 1:
+        while True:
             line = self.readline()
             if not line:
                 break
@@ -656,7 +786,7 @@
         If a log file was set then the data is also written to the log.
         """
         time.sleep(self.delaybeforesend)
-        if self.logfile != None:
+        if self.logfile is not None:
             self.logfile.write (str)
             self.logfile.flush()
         c = os.write(self.child_fd, str)
@@ -698,50 +828,76 @@
             termios.tcsetattr(fd, termios.TCSADRAIN, old)
 
     def eof (self):
-        """This returns 1 if the EOF exception was raised at some point.
+        """This returns True if the EOF exception was ever raised.
         """
         return self.flag_eof
 
-    def terminate(self, force=0):
+    def terminate(self, force=False):
         """This forces a child process to terminate.
-        It starts nicely with SIGHUP and SIGINT. If "force" is 1 then
+        It starts nicely with SIGHUP and SIGINT. If "force" is True then
         moves onto SIGKILL.
-        This returns true if the child was terminated.
-        This returns false if the child could not be terminated.
+        This returns True if the child was terminated.
+        This returns False if the child could not be terminated.
         """
         if not self.isalive():
-            return 1
+            return True
         self.kill(signal.SIGHUP)
-        time.sleep(0.1)
+        time.sleep(self.delayafterterminate)
         if not self.isalive():
-            return 1
+            return True
         self.kill(signal.SIGCONT)
-        time.sleep(0.1)
+        time.sleep(self.delayafterterminate)
         if not self.isalive():
-            return 1
+            return True
         self.kill(signal.SIGINT)
-        time.sleep(0.1)
+        time.sleep(self.delayafterterminate)
         if not self.isalive():
-            return 1
+            return True
         if force:
             self.kill(signal.SIGKILL)
-            time.sleep(0.1)
+            time.sleep(self.delayafterterminate)
             if not self.isalive():
-                return 1
+                return True
             else:
-                return 0
-        return 0
-        #raise ExceptionPexpect ('terminate() could not terminate child process. Try terminate(force=1)?')
-        
+                return False
+        return False
+        #raise ExceptionPexpect ('terminate() could not terminate child process. Try terminate(force=True)?')
+     
+    def wait(self):
+        """This waits until the child exits. This is a blocking call.
+            This will not read any data from the child, so this will block forever
+            if the child has unread output and has terminated. In other words, the child
+            may have printed output then called exit(); but, technically, the child is
+            still alive until its output is read.
+        """
+        if self.isalive():
+            pid, status = os.waitpid(self.pid, 0)
+        else:
+            raise ExceptionPexpect ('Cannot wait for dead child process.')
+        self.exitstatus = os.WEXITSTATUS(status)
+        if os.WIFEXITED (status):
+            self.status = status
+            self.exitstatus = os.WEXITSTATUS(status)
+            self.signalstatus = None
+            self.terminated = True
+        elif os.WIFSIGNALED (status):
+            self.status = status
+            self.exitstatus = None
+            self.signalstatus = os.WTERMSIG(status)
+            self.terminated = True
+        elif os.WIFSTOPPED (status):
+            raise ExceptionPexpect ('Wait was called for a child process that is stopped. This is not supported. Is some other process attempting job control with our child pid?')
+        return self.exitstatus
+   
     def isalive(self):
         """This tests if the child process is running or not.
         This is non-blocking. If the child was terminated then this
         will read the exitstatus or signalstatus of the child.
-        This returns 1 if the child process appears to be running or 0 if not.
+        This returns True if the child process appears to be running or False if not.
         It can take literally SECONDS for Solaris to return the right status.
         """
         if self.terminated:
-            return 0
+            return False
 
         if self.flag_eof:
             # This is for Linux, which requires the blocking form of waitpid to get
@@ -776,28 +932,24 @@
             # for Irix which seems to require a blocking call on waitpid or select, so I let read_nonblocking
             # take care of this situation (unfortunately, this requires waiting through the timeout).
             if pid == 0:
-                return 1
+                return True
 
         if pid == 0:
-            return 1
+            return True
 
         if os.WIFEXITED (status):
             self.status = status
             self.exitstatus = os.WEXITSTATUS(status)
             self.signalstatus = None
-            self.terminated = 1
-            return 0
+            self.terminated = True
         elif os.WIFSIGNALED (status):
             self.status = status
             self.exitstatus = None
             self.signalstatus = os.WTERMSIG(status)
-            self.terminated = 1
-            return 0
+            self.terminated = True
         elif os.WIFSTOPPED (status):
             raise ExceptionPexpect ('isalive() encountered condition where child process is stopped. This is not supported. Is some other process attempting job control with our child pid?')
-
-        raise ExceptionPexpect ('isalive() reached unexpected condition where waitpid matched child pid, but status was not matched by WIFEXITED, WIFSIGNALED, or WIFSTOPPED.')
-
+        return False
 
     def kill(self, sig):
         """This sends the given signal to the child application.
@@ -834,10 +986,13 @@
         if type(patterns) is not types.ListType:
             patterns = [patterns]
 
+        compile_flags = re.DOTALL # Allow dot to match \n
+        if self.ignorecase:
+            compile_flags = compile_flags | re.IGNORECASE
         compiled_pattern_list = []
         for p in patterns:
             if type(p) is types.StringType:
-                compiled_pattern_list.append(re.compile(p, re.DOTALL))
+                compiled_pattern_list.append(re.compile(p, compile_flags))
             elif p is EOF:
                 compiled_pattern_list.append(EOF)
             elif p is TIMEOUT:
@@ -850,15 +1005,15 @@
         return compiled_pattern_list
  
     def expect(self, pattern, timeout = -1, searchwindowsize=None):
+
         """This seeks through the stream until a pattern is matched.
         The pattern is overloaded and may take several types including a list.
-        The pattern can be a StringType, EOF, a compiled re, or
-        a list of those types. Strings will be compiled to re types.
-        This returns the index into the pattern list. If the pattern was
-        not a list this returns index 0 on a successful match.
-        This may raise exceptions for EOF or TIMEOUT.
-        To avoid the EOF or TIMEOUT exceptions add EOF or TIMEOUT to
-        the pattern list.
+        The pattern can be a StringType, EOF, a compiled re, or a list of
+        those types. Strings will be compiled to re types. This returns the
+        index into the pattern list. If the pattern was not a list this
+        returns index 0 on a successful match. This may raise exceptions for
+        EOF or TIMEOUT. To avoid the EOF or TIMEOUT exceptions add
+        EOF or TIMEOUT to the pattern list.
 
         After a match is found the instance attributes
         'before', 'after' and 'match' will be set.
@@ -910,7 +1065,7 @@
 
     def expect_list(self, pattern_list, timeout = -1, searchwindowsize = -1):
         """This takes a list of compiled regular expressions and returns 
-        the index into the pattern_list that matched the child's output.
+        the index into the pattern_list that matched the child output.
         The list may also contain EOF or TIMEOUT (which are not
         compiled regular expressions). This method is similar to
         the expect() method except that expect_list() does not
@@ -920,18 +1075,19 @@
         If timeout==-1 then the self.timeout value is used.
         If searchwindowsize==-1 then the self.searchwindowsize value is used.
         """
+
         self.patterns = pattern_list
 
         if timeout == -1:
             timeout = self.timeout
-        if timeout != None:
+        if timeout is not None:
             end_time = time.time() + timeout 
         if searchwindowsize == -1:
             searchwindowsize = self.searchwindowsize
 
         try:
             incoming = self.buffer
-            while 1: # Keep reading until exception or return.
+            while True: # Keep reading until exception or return.
                 # Sequence through the list of patterns looking for a match.
                 first_match = -1
                 for cre in pattern_list:
@@ -958,6 +1114,7 @@
                     raise TIMEOUT ('Timeout exceeded in expect_list().')
                 # Still have time left, so read more data
                 c = self.read_nonblocking (self.maxread, timeout)
+                time.sleep (0.0001)
                 incoming = incoming + c
                 if timeout is not None:
                     timeout = end_time - time.time()
@@ -992,19 +1149,19 @@
             raise
 
     def getwinsize(self):
-        """This returns the window size of the child tty.
+        """This returns the terminal window size of the child tty.
         The return value is a tuple of (rows, cols).
         """
         if 'TIOCGWINSZ' in dir(termios):
             TIOCGWINSZ = termios.TIOCGWINSZ
         else:
-            TIOCGWINSZ = 1074295912L # Assume
+            TIOCGWINSZ = 1074295912L # assume if not defined
         s = struct.pack('HHHH', 0, 0, 0, 0)
         x = fcntl.ioctl(self.fileno(), TIOCGWINSZ, s)
         return struct.unpack('HHHH', x)[0:2]
 
     def setwinsize(self, r, c):
-        """This sets the window size of the child tty.
+        """This sets the terminal window size of the child tty.
         This will cause a SIGWINCH signal to be sent to the child.
         This does not change the physical window size.
         It changes the size reported to TTY-aware applications like
@@ -1028,15 +1185,25 @@
         s = struct.pack('HHHH', r, c, 0, 0)
         fcntl.ioctl(self.fileno(), TIOCSWINSZ, s)
 
-    def interact(self, escape_character = chr(29)):
+    def interact(self, escape_character = chr(29), input_filter = None, output_filter = None):
         """This gives control of the child process to the interactive user
         (the human at the keyboard).
         Keystrokes are sent to the child process, and the stdout and stderr
         output of the child process is printed.
-        When the user types the escape_character this method will stop.
-        The default for escape_character is ^] (ASCII 29).
         This simply echos the child stdout and child stderr to the real
         stdout and it echos the real stdin to the child stdin.
+        When the user types the escape_character this method will stop.
+        The default for escape_character is ^]. This should not be confused
+        with ASCII 27 -- the ESC character. ASCII 29 was chosen
+        for historical merit because this is the character used
+        by 'telnet' as the escape character. The escape_character will
+        not be sent to the child process.
+
+        You may pass in optional input and output filter functions.
+        These functions should take a string and return a string.
+        The output_filter will be passed all the output from the child process.
+        The input_filter will be passed all the keyboard input from the user.
+        The input_filter is run BEFORE the check for the escape_character.
 
         Note that if you change the window size of the parent
         the SIGWINCH signal will not be passed through to the child.
@@ -1048,7 +1215,7 @@
                 a = struct.unpack('hhhh', fcntl.ioctl(sys.stdout.fileno(), termios.TIOCGWINSZ , s))
                 global p
                 p.setwinsize(a[0],a[1])
-            p = pexpect.spawn('/bin/bash') # Note this is global
+            p = pexpect.spawn('/bin/bash') # Note this is global and used in sigwinch_passthrough.
             signal.signal(signal.SIGWINCH, sigwinch_passthrough)
             p.interact()
         """
@@ -1059,7 +1226,7 @@
         mode = tty.tcgetattr(self.STDIN_FILENO)
         tty.setraw(self.STDIN_FILENO)
         try:
-            self.__interact_copy(escape_character)
+            self.__interact_copy(escape_character, input_filter, output_filter)
         finally:
             tty.tcsetattr(self.STDIN_FILENO, tty.TCSAFLUSH, mode)
 
@@ -1073,26 +1240,49 @@
         """This is used by the interact() method.
         """
         return os.read(fd, 1000)
-    def __interact_copy(self, escape_character = None):
+    def __interact_copy(self, escape_character = None, input_filter = None, output_filter = None):
         """This is used by the interact() method.
         """
         while self.isalive():
-            try:
-                r, w, e = select.select([self.child_fd, self.STDIN_FILENO], [], [])
-            except select.errno, e:
-                if e[0] != errno.EINTR:
-                    raise
+            r,w,e = self.__select([self.child_fd, self.STDIN_FILENO], [], [])
             if self.child_fd in r:
                 data = self.__interact_read(self.child_fd)
-                if self.logfile != None:
+                if output_filter: data = output_filter(data)
+                if self.logfile is not None:
                     self.logfile.write (data)
                     self.logfile.flush()
                 os.write(self.STDOUT_FILENO, data)
             if self.STDIN_FILENO in r:
                 data = self.__interact_read(self.STDIN_FILENO)
+                if input_filter: data = input_filter(data)
+                i = data.rfind(escape_character)
+                if i != -1:
+                    data = data[:i]
+                    self.__interact_writen(self.child_fd, data)
+                    break
                 self.__interact_writen(self.child_fd, data)
-                if escape_character in data:
-                    break
+    def __select (self, iwtd, owtd, ewtd, timeout=None):
+        """This is a wrapper around select.select() that ignores signals.
+        If select.select raises a select.error exception and errno is an EINTR error then
+        it is ignored. Mainly this is used to ignore sigwinch (terminal resize).
+        """
+        # if select() is interrupted by a signal (errno==EINTR) then
+        # we loop back and enter the select() again.
+        if timeout is not None:
+            end_time = time.time() + timeout 
+        while True:
+            try:
+                return select.select (iwtd, owtd, ewtd, timeout)
+            except select.error, e:
+                if e[0] == errno.EINTR:
+                    # if we loop back we have to subtract the amount of time we already waited.
+                    if timeout is not None:
+                        timeout = end_time - time.time()
+                        if timeout < 0:
+                            return ([],[],[])
+                else: # something else caused the select.error, so this really is an exception
+                    raise
+
 ##############################################################################
 # The following methods are no longer supported or allowed..                
     def setmaxread (self, maxread):

Modified: packages/pexpect/trunk/pxssh.py
URL: http://svn.debian.org/wsvn/python-modules/packages/pexpect/trunk/pxssh.py?rev=931&op=diff
==============================================================================
--- packages/pexpect/trunk/pxssh.py (original)
+++ packages/pexpect/trunk/pxssh.py Mon Jun 19 11:41:27 2006
@@ -1,54 +1,59 @@
-"""This class extends pexpect.spawn to specialize setting up SSH connections.
-This adds methods for login, logout, and expecting the prompt.
-
-TODO: 
-* set_unique_prompt() is using a hard-coded constant for PROMPT.
-  That should be configurable.
-* login() needs a state machine or at least a clear flow chart of the login process.
-* login() needs some ability to fall-back to a fail-safe login method on timeout.
-  If he login is taking too long then I should 'punt' and try setting the prompt anyway.
-  Perhaps use some sort of prompt challange-response.
-"""
 from pexpect import *
-import os, sys, getopt, shutil
-from time import sleep
-
-
-# used to set shell command-line prompt to something more unique.
-PROMPT = "\[PEXPECT\]\$ "
-# SUBTLE HACK ALERT!
-# Note that the command to set the prompt uses a slightly different string
-# than the regular expression to match it. This is because when you set the
-# prompt the command will echo back, but we don't want to match the echoed
-# command. So if we make the set command slightly different than the regex
-# we eliminate the problem. To make the set command different we add a
-# backslash in front of $. The $ doesn't need to be escaped, but it doesn't
-# hurt and serves to make the set command different than the regex.
+#import os, sys, getopt, shutil
 
 class pxssh (spawn):
-    """This extends the spawn class to specialize for running 'ssh' command-line client.
-        This adds methods to login, logout, and expect_prompt.
+    """This class extends pexpect.spawn to specialize setting up SSH connections.
+    This adds methods for login, logout, and expecting the prompt.
+    It does various hacky things to handle any situation in the SSH login process.
+    For example, if the session is your first login, then it automatically
+    accepts the certificate; or if you have public key authentication setup
+    and you don't need a password then this is OK too.
+
+    Example usage that runs 'ls -l' on server and prints the result:
+        import pxssh
+        s = pxssh.pxssh()
+        if not s.login ('localhost', 'myusername', 'mypassword'):
+            print "SSH session failed on login."
+            print str(s)
+        else:
+            print "SSH session login successful"
+            s.sendline ('ls -l')
+            s.prompt()           # match the prompt
+            print s.before     # print everything before the prompt.
+            s.logout()
     """
-    def __init__(self):
-        self.PROMPT = "\[PEXPECT\]\$ "
-        pass
-    def logout(self):
-        """This sends exit. If there are stopped jobs then this sends exit twice.
+
+    def __init__ (self):
+        # SUBTLE HACK ALERT!
+        # Note that the command to set the prompt uses a slightly different string
+        # than the regular expression to match it. This is because when you set the
+        # prompt the command will echo back, but we don't want to match the echoed
+        # command. So if we make the set command slightly different than the regex
+        # we eliminate the problem. To make the set command different we add a
+        # backslash in front of $. The $ doesn't need to be escaped, but it doesn't
+        # hurt and serves to make the set command different than the regex.
+        self.PROMPT = "\[PEXPECT\][\$\#] " # used to match the command-line prompt.
+        # used to set shell command-line prompt to something more unique.
+        self.PROMPT_SET_SH = "PS1='[PEXPECT]\$ '"
+        self.PROMPT_SET_CSH = "set prompt='[PEXPECT]\$ '"
+
+    ### TODO: This is getting messy and I'm pretty sure this isn't perfect.
+    ### TODO: I need to draw a better flow chart for this.
+    def login (self,server,username,password='',terminal_type='ansi',original_prompts=r"][#$]|~[#$]|bash.*?[#$]|[#$] ",login_timeout=10):
+        """This logs the user into the given server. By default the prompt is
+        rather optimistic and should be considered more of an example. It's
+        better to try to match the prompt as exactly as possible to prevent
+        any false matches by server strings such as a "Message Of The Day" or
+        something. The closer you can make the original_prompt match your real prompt
+        then the better. A timeout will not necessarily cause the login to fail.
+        In the case of a timeout we assume that the prompt was so weird that
+        we could not match it. We still try to reset the prompt to something
+        more unique. If that still fails then we return False.
         """
-        self.sendline("exit")
-        index = self.expect([EOF, "(?i)there are stopped jobs"])
-        if index==1:
-            self.sendline("exit")
-            self.expect(EOF)
-
-    # I need to draw a better flow chart for this.
-    # This is getting messy and I'm pretty sure this isn't perfect.
-    def login(self,server,username,password,terminal_type='ansi'):
-        original_prompts = r"][#$]|~[#$]|bash.*?[#$]"
         cmd = "ssh -l %s %s" % (username, server)
-        self = spawn(cmd, timeout=300)
+        spawn.__init__(self, cmd, timeout=login_timeout)
         #, "(?i)no route to host"])
-        i = self.expect(["(?i)are you sure you want to continue connecting", original_prompts, "(?i)password", "(?i)permission denied", "(?i)terminal type", TIMEOUT])
+        i = self.expect(["(?i)are you sure you want to continue connecting", original_prompts, "(?i)password", "(?i)permission denied", "(?i)terminal type", TIMEOUT, "(?i)connection closed by remote host"])
         if i==0: # New certificate -- always accept it. This is what you if SSH does not have the remote host's public key stored in the cache.
             self.sendline("yes")
             i = self.expect(["(?i)are you sure you want to continue connecting", original_prompts, "(?i)password", "(?i)permission denied", "(?i)terminal type", TIMEOUT])
@@ -64,12 +69,13 @@
             self.close()
             return False
         elif i==1: # can occur if you have a public key pair set to authenticate. 
-            ### May NOT be OK if expect false matched a prompt.
+            ### TODO: May NOT be OK if expect() matched a false prompt.
             pass
         elif i==2: # password prompt again
-            # Some ssh servers will ask again for password, others print permission denied right away.
-            # If you get the password prompt again then it means we didn't get the password right
-            # the first time. 
+            # For incorrect passwords, some ssh servers will
+            # ask for the password again, others return 'denied' right away.
+            # If we get the password prompt again then this means
+            # we didn't get the password right the first time. 
             self.close()
             return False
         elif i==3: # permission denied -- password was bad.
@@ -82,30 +88,46 @@
             # This is tricky... presume that we are at the command-line prompt.
             # It may be that the prompt was so weird that we couldn't match it.
             pass
+        elif i==6: # Connection closed by remote host
+            self.close()
+            return False
         else: # Unexpected 
             self.close()
             return False
-        # We appear to have logged in -- reset command line prompt to something more unique.
+        # We appear to be in -- reset prompt to something more unique.
         if not self.set_unique_prompt():
             self.close()
             return False
         return True
 
-    def prompt (self):
-        """This expects the prompt.
+    def logout (self):
+        """This sends exit. If there are stopped jobs then this sends exit twice.
         """
-        i = self.expect(self.PROMPT)
+        self.sendline("exit")
+        index = self.expect([EOF, "(?i)there are stopped jobs"])
+        if index==1:
+            self.sendline("exit")
+            self.expect(EOF)
+
+    def prompt (self, timeout=20):
+        """This expects the prompt. This returns True if the prompt was matched.
+        This returns False if there was a timeout.
+        """
+        i = self.expect([self.PROMPT, TIMEOUT], timeout=timeout)
+        if i==1:
+            return False
+        return True
         
     def set_unique_prompt (self, optional_prompt=None):
         """This attempts to reset the shell prompt to something more unique.
-            This makes it easier to match in the future.
+            This makes it easier to match unambiguously.
         """
         if optional_prompt is not None:
             self.prompt = optional_prompt
-        self.sendline ("PS1='[PEXPECT]\$ '") # In case of sh-style
+        self.sendline (self.PROMPT_SET_SH) # sh-style
         i = self.expect ([TIMEOUT, self.PROMPT], timeout=10)
         if i == 0: # csh-style
-            self.sendline ("set prompt='[PEXPECT]\$ '")
+            self.sendline (self.PROMPT_SET_CSH)
             i = self.expect ([TIMEOUT, self.PROMPT], timeout=10)
             if i == 0:
                 return 0

Modified: packages/pexpect/trunk/screen.py
URL: http://svn.debian.org/wsvn/python-modules/packages/pexpect/trunk/screen.py?rev=931&op=diff
==============================================================================
--- packages/pexpect/trunk/screen.py (original)
+++ packages/pexpect/trunk/screen.py Mon Jun 19 11:41:27 2006
@@ -1,6 +1,6 @@
 '''
-$Revision: 1.4 $
-$Date: 2002/08/28 19:07:03 $
+$Revision: 372 $
+$Date: 2006-03-05 18:19:39 -0800 (Sun, 05 Mar 2006) $
 '''
 
 import copy
@@ -26,8 +26,8 @@
 SPACE = chr(32) # Space or blank character.
 
 def constrain (n, min, max):
-    '''This returns n constrained to the min and max bounds.
-    '''
+    """This returns n constrained to the min and max bounds.
+    """
     if n < min:
         return min
     if n > max:
@@ -35,6 +35,14 @@
     return n
 
 class screen:
+    """This maintains the state of a virtual text screen.
+        This maintains a cursor position and handles
+        scrolling as characters are added.
+        This supports most of the methods needed by an
+        ANSI text screen.
+        Row and column indexes are 1-based (not zero-based,
+        like arrays).
+    """
     def __init__ (self, r=24,c=80):
         self.rows = r
         self.cols = c
@@ -47,12 +55,14 @@
         self.w = [ [SPACE] * self.cols for c in range(self.rows)]
 
     def __str__ (self):
-        s = ''
-        for r in range (1, self.rows + 1):
-            for c in range (1, self.cols + 1):
-                s = s + self.get_abs(r,c)
-            s = s + '\n'
-        return s
+        return '\n'.join ([ ''.join(c) for c in self.w ])
+
+    def dump (self):
+        """This returns a copy of the screen as a string.
+            This is similar to __str__ except that lines
+            are not terminated with line feeds.
+        """
+        return ''.join ([ ''.join(c) for c in self.w ])
 
     def fill (self, ch=SPACE):
         self.fill_region (1,1,self.rows,self.cols, ch)
@@ -82,12 +92,18 @@
         if old_r == self.cur_r:
             self.scroll_up ()
             self.erase_line()
+
     def crlf (self):
         '''This advances the cursor with CRLF properties.
         The cursor will line wrap and the screen may scroll.
         '''
         self.cr ()
         self.lf ()
+
+    def newline (self):
+        """This is an alias for crlf().
+        """
+        self.crlf()
 
     def put_abs (self, r, c, ch):
         '''Screen array starts at 1 index.'''
@@ -96,6 +112,8 @@
         ch = str(ch)[0]
         self.w[r-1][c-1] = ch
     def put (self, ch):
+        """This puts a characters at the current cursor position.
+        """
         self.put_abs (self.cur_r, self.cur_c, ch)
 
     def insert_abs (self, r, c, ch):

Modified: packages/pexpect/trunk/setup.py
URL: http://svn.debian.org/wsvn/python-modules/packages/pexpect/trunk/setup.py?rev=931&op=diff
==============================================================================
--- packages/pexpect/trunk/setup.py (original)
+++ packages/pexpect/trunk/setup.py Mon Jun 19 11:41:27 2006
@@ -1,16 +1,16 @@
 '''
-$Revision: 1.18 $
-$Date: 2005/11/13 01:31:46 $
+$Revision: 393 $
+$Date: 2006-05-30 18:00:23 -0700 (Tue, 30 May 2006) $
 '''
 from distutils.core import setup
 setup (name='pexpect',
-    version='2.0',
-    py_modules=['pexpect'],
+    version='2.1',
+    py_modules=['pexpect', 'pxssh', 'fdpexpect'],
     description='Pexpect is a pure Python Expect. It allows easy control of other applications.',
     author='Noah Spurrier',
     author_email='noah at noah.org',
     url='http://pexpect.sourceforge.net/',
-    license='Python Software Foundation License',
+    license='MIT license',
     platforms='UNIX',
 )
 




More information about the Python-modules-commits mailing list