summaryrefslogtreecommitdiffstats
path: root/third_party/pexpect
diff options
context:
space:
mode:
authorbulach@chromium.org <bulach@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-11-13 16:35:15 +0000
committerbulach@chromium.org <bulach@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-11-13 16:35:15 +0000
commit2dbd513b86a1105f684c1fe2b031e5e937c53c52 (patch)
tree3947ef34c3b48b8b9795e087907fdd7137923861 /third_party/pexpect
parent7d489649a0912884680165e9705848fae5ba33e0 (diff)
downloadchromium_src-2dbd513b86a1105f684c1fe2b031e5e937c53c52.zip
chromium_src-2dbd513b86a1105f684c1fe2b031e5e937c53c52.tar.gz
chromium_src-2dbd513b86a1105f684c1fe2b031e5e937c53c52.tar.bz2
Roll third_party/pexpect 509:533
The author kindly updated the license headers as requested by nduca. One of the files requires more context for the license to be detected, so increase it to 100 (instead of the default 60). BUG=156113 TEST=tools/checklicenses/checklicenses.py --root . -vv third_party/pexpect Review URL: https://chromiumcodereview.appspot.com/11360098 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@167398 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'third_party/pexpect')
-rw-r--r--third_party/pexpect/ANSI.py106
-rwxr-xr-xthird_party/pexpect/FSM.py24
-rw-r--r--third_party/pexpect/LICENSE32
-rw-r--r--third_party/pexpect/README52
-rw-r--r--third_party/pexpect/README.chromium2
-rw-r--r--third_party/pexpect/fdpexpect.py20
-rw-r--r--third_party/pexpect/pexpect.py809
-rw-r--r--third_party/pexpect/pxssh.py86
-rw-r--r--third_party/pexpect/screen.py22
9 files changed, 686 insertions, 467 deletions
diff --git a/third_party/pexpect/ANSI.py b/third_party/pexpect/ANSI.py
index 537017e..69f8c54 100644
--- a/third_party/pexpect/ANSI.py
+++ b/third_party/pexpect/ANSI.py
@@ -1,8 +1,26 @@
-"""This implements an ANSI terminal emulator as a subclass of screen.
+"""This implements an ANSI (VT100) terminal emulator as a subclass of screen.
+
+PEXPECT LICENSE
+
+ This license is approved by the OSI and FSF as GPL-compatible.
+ http://opensource.org/licenses/isc-license.txt
+
+ Copyright (c) 2012, Noah Spurrier <noah@noah.org>
+ PERMISSION TO USE, COPY, MODIFY, AND/OR DISTRIBUTE THIS SOFTWARE FOR ANY
+ PURPOSE WITH OR WITHOUT FEE IS HEREBY GRANTED, PROVIDED THAT THE ABOVE
+ COPYRIGHT NOTICE AND THIS PERMISSION NOTICE APPEAR IN ALL COPIES.
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-$Id: ANSI.py 491 2007-12-16 20:04:57Z noah $
"""
+
# references:
+# http://en.wikipedia.org/wiki/ANSI_escape_code
# http://www.retards.org/terminals/vt102.html
# http://vt100.net/docs/vt102-ug/contents.html
# http://vt100.net/docs/vt220-rm/
@@ -13,16 +31,19 @@ import FSM
import copy
import string
-def Emit (fsm):
+#
+# The 'Do.*' functions are helper functions for the ANSI class.
+#
+def DoEmit (fsm):
screen = fsm.memory[0]
screen.write_ch(fsm.input_symbol)
-def StartNumber (fsm):
+def DoStartNumber (fsm):
fsm.memory.append (fsm.input_symbol)
-def BuildNumber (fsm):
+def DoBuildNumber (fsm):
ns = fsm.memory.pop()
ns = ns + fsm.input_symbol
@@ -114,11 +135,12 @@ def DoEraseEndOfLine (fsm):
def DoEraseLine (fsm):
+ arg = int(fsm.memory.pop())
screen = fsm.memory[0]
if arg == 0:
- screen.end_of_line()
+ screen.erase_end_of_line()
elif arg == 1:
- screen.start_of_line()
+ screen.erase_start_of_line()
elif arg == 2:
screen.erase_line()
@@ -150,7 +172,7 @@ def DoMode (fsm):
mode = fsm.memory.pop() # Should be 4
# screen.setReplaceMode ()
-def Log (fsm):
+def DoLog (fsm):
screen = fsm.memory[0]
fsm.memory = [screen]
@@ -159,16 +181,21 @@ def Log (fsm):
fout.close()
class term (screen.screen):
- """This is a placeholder.
- In theory I might want to add other terminal types.
- """
+
+ """This class is an abstract, generic terminal.
+ This does nothing. This is a placeholder that
+ provides a common base class for other terminals
+ such as an ANSI terminal. """
+
def __init__ (self, r=24, c=80):
+
screen.screen.__init__(self, r,c)
class ANSI (term):
- """This class encapsulates a generic terminal. It filters a stream and
- maintains the state of a screen object. """
+ """This class implements an ANSI (VT100) terminal.
+ It is a stream filter that recognizes ANSI terminal
+ escape sequences and maintains the state of a screen object. """
def __init__ (self, r=24,c=80):
@@ -176,10 +203,10 @@ class ANSI (term):
#self.screen = screen (24,80)
self.state = FSM.FSM ('INIT',[self])
- self.state.set_default_transition (Log, 'INIT')
- self.state.add_transition_any ('INIT', Emit, 'INIT')
+ self.state.set_default_transition (DoLog, 'INIT')
+ self.state.add_transition_any ('INIT', DoEmit, 'INIT')
self.state.add_transition ('\x1b', 'INIT', None, 'ESC')
- self.state.add_transition_any ('ESC', Log, 'INIT')
+ self.state.add_transition_any ('ESC', DoLog, 'INIT')
self.state.add_transition ('(', 'ESC', None, 'G0SCS')
self.state.add_transition (')', 'ESC', None, 'G1SCS')
self.state.add_transition_list ('AB012', 'G0SCS', None, 'INIT')
@@ -204,8 +231,8 @@ class ANSI (term):
self.state.add_transition ('r', 'ELB', DoEnableScroll, 'INIT')
self.state.add_transition ('m', 'ELB', None, 'INIT')
self.state.add_transition ('?', 'ELB', None, 'MODECRAP')
- self.state.add_transition_list (string.digits, 'ELB', StartNumber, 'NUMBER_1')
- self.state.add_transition_list (string.digits, 'NUMBER_1', BuildNumber, 'NUMBER_1')
+ self.state.add_transition_list (string.digits, 'ELB', DoStartNumber, 'NUMBER_1')
+ self.state.add_transition_list (string.digits, 'NUMBER_1', DoBuildNumber, 'NUMBER_1')
self.state.add_transition ('D', 'NUMBER_1', DoBack, 'INIT')
self.state.add_transition ('B', 'NUMBER_1', DoDown, 'INIT')
self.state.add_transition ('C', 'NUMBER_1', DoForward, 'INIT')
@@ -217,22 +244,22 @@ class ANSI (term):
### number;number;number before it. I've never seen more than two,
### but the specs say it's allowed. crap!
self.state.add_transition ('m', 'NUMBER_1', None, 'INIT')
- ### LED control. Same problem as 'm' code.
- self.state.add_transition ('q', 'NUMBER_1', None, 'INIT')
-
- # \E[?47h appears to be "switch to alternate screen"
- # \E[?47l restores alternate screen... I think.
- self.state.add_transition_list (string.digits, 'MODECRAP', StartNumber, 'MODECRAP_NUM')
- self.state.add_transition_list (string.digits, 'MODECRAP_NUM', BuildNumber, 'MODECRAP_NUM')
+ ### LED control. Same implementation problem as 'm' code.
+ self.state.add_transition ('q', 'NUMBER_1', None, 'INIT')
+
+ # \E[?47h switch to alternate screen
+ # \E[?47l restores to normal screen from alternate screen.
+ self.state.add_transition_list (string.digits, 'MODECRAP', DoStartNumber, 'MODECRAP_NUM')
+ self.state.add_transition_list (string.digits, 'MODECRAP_NUM', DoBuildNumber, 'MODECRAP_NUM')
self.state.add_transition ('l', 'MODECRAP_NUM', None, 'INIT')
self.state.add_transition ('h', 'MODECRAP_NUM', None, 'INIT')
#RM Reset Mode Esc [ Ps l none
self.state.add_transition (';', 'NUMBER_1', None, 'SEMICOLON')
- self.state.add_transition_any ('SEMICOLON', Log, 'INIT')
- self.state.add_transition_list (string.digits, 'SEMICOLON', StartNumber, 'NUMBER_2')
- self.state.add_transition_list (string.digits, 'NUMBER_2', BuildNumber, 'NUMBER_2')
- self.state.add_transition_any ('NUMBER_2', Log, 'INIT')
+ self.state.add_transition_any ('SEMICOLON', DoLog, 'INIT')
+ self.state.add_transition_list (string.digits, 'SEMICOLON', DoStartNumber, 'NUMBER_2')
+ self.state.add_transition_list (string.digits, 'NUMBER_2', DoBuildNumber, 'NUMBER_2')
+ self.state.add_transition_any ('NUMBER_2', DoLog, 'INIT')
self.state.add_transition ('H', 'NUMBER_2', DoHome, 'INIT')
self.state.add_transition ('f', 'NUMBER_2', DoHome, 'INIT')
self.state.add_transition ('r', 'NUMBER_2', DoScrollRegion, 'INIT')
@@ -241,7 +268,16 @@ class ANSI (term):
### but the specs say it's allowed. crap!
self.state.add_transition ('m', 'NUMBER_2', None, 'INIT')
### LED control. Same problem as 'm' code.
- self.state.add_transition ('q', 'NUMBER_2', None, 'INIT')
+ self.state.add_transition ('q', 'NUMBER_2', None, 'INIT')
+ self.state.add_transition (';', 'NUMBER_2', None, 'SEMICOLON_X')
+
+ # Create a state for 'q' and 'm' which allows an infinite number of ignored numbers
+ self.state.add_transition_any ('SEMICOLON_X', DoLog, 'INIT')
+ self.state.add_transition_list (string.digits, 'SEMICOLON_X', None, 'NUMBER_X')
+ self.state.add_transition_any ('NUMBER_X', DoLog, 'INIT')
+ self.state.add_transition ('m', 'NUMBER_X', None, 'INIT')
+ self.state.add_transition ('q', 'NUMBER_X', None, 'INIT')
+ self.state.add_transition (';', 'NUMBER_2', None, 'SEMICOLON_X')
def process (self, c):
@@ -262,24 +298,22 @@ class ANSI (term):
def write_ch (self, ch):
- """This puts a character at the current cursor position. cursor
- position if moved forward with wrap-around, but no scrolling is done if
+ """This puts a character at the current cursor position. The cursor
+ position is 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 cr() and lf(), respectively.
ch = ch[0]
if ch == '\r':
- # self.crlf()
+ self.cr()
return
if ch == '\n':
self.crlf()
return
if ch == chr(screen.BS):
self.cursor_back()
- self.put_abs(self.cur_r, self.cur_c, ' ')
return
-
if ch not in string.printable:
fout = open ('log', 'a')
fout.write ('Nonprint: ' + str(ord(ch)) + '\n')
diff --git a/third_party/pexpect/FSM.py b/third_party/pexpect/FSM.py
index 751eb37..c9085dc 100755
--- a/third_party/pexpect/FSM.py
+++ b/third_party/pexpect/FSM.py
@@ -64,6 +64,24 @@ current_state then the FSM will raise an exception. This may be desirable, but
you can always prevent this just by defining a default transition.
Noah Spurrier 20020822
+
+PEXPECT LICENSE
+
+ This license is approved by the OSI and FSF as GPL-compatible.
+ http://opensource.org/licenses/isc-license.txt
+
+ Copyright (c) 2012, Noah Spurrier <noah@noah.org>
+ PERMISSION TO USE, COPY, MODIFY, AND/OR DISTRIBUTE THIS SOFTWARE FOR ANY
+ PURPOSE WITH OR WITHOUT FEE IS HEREBY GRANTED, PROVIDED THAT THE ABOVE
+ COPYRIGHT NOTICE AND THIS PERMISSION NOTICE APPEAR IN ALL COPIES.
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
"""
class ExceptionFSM(Exception):
@@ -237,7 +255,7 @@ class FSM:
# process an RPN expression. Run this module from the command line. You will
# get a prompt > for input. Enter an RPN Expression. Numbers may be integers.
# Operators are * / + - Use the = sign to evaluate and print the expression.
-# For example:
+# For example:
#
# 167 3 2 2 * * * 1 - =
#
@@ -249,7 +267,7 @@ class FSM:
import sys, os, traceback, optparse, time, string
#
-# These define the actions.
+# These define the actions.
# Note that "memory" is a list being used as a stack.
#
@@ -311,7 +329,7 @@ def main():
if __name__ == '__main__':
try:
start_time = time.time()
- parser = optparse.OptionParser(formatter=optparse.TitledHelpFormatter(), usage=globals()['__doc__'], version='$Id: FSM.py 490 2007-12-07 15:46:24Z noah $')
+ parser = optparse.OptionParser(formatter=optparse.TitledHelpFormatter(), usage=globals()['__doc__'], version='$Id: FSM.py 533 2012-10-20 02:19:33Z noah $')
parser.add_option ('-v', '--verbose', action='store_true', default=False, help='verbose output')
(options, args) = parser.parse_args()
if options.verbose: print time.asctime()
diff --git a/third_party/pexpect/LICENSE b/third_party/pexpect/LICENSE
index e611443..18ff9db 100644
--- a/third_party/pexpect/LICENSE
+++ b/third_party/pexpect/LICENSE
@@ -1,21 +1,17 @@
-Free, open source, and all that good stuff.
-Pexpect Copyright (c) 2008 Noah Spurrier
+PEXPECT LICENSE
-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:
+ This license is approved by the OSI and FSF as GPL-compatible.
+ http://opensource.org/licenses/isc-license.txt
-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.
+ Copyright (c) 2012, Noah Spurrier <noah@noah.org>
+ PERMISSION TO USE, COPY, MODIFY, AND/OR DISTRIBUTE THIS SOFTWARE FOR ANY
+ PURPOSE WITH OR WITHOUT FEE IS HEREBY GRANTED, PROVIDED THAT THE ABOVE
+ COPYRIGHT NOTICE AND THIS PERMISSION NOTICE APPEAR IN ALL COPIES.
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
diff --git a/third_party/pexpect/README b/third_party/pexpect/README
index 3101dc8..85298c4 100644
--- a/third_party/pexpect/README
+++ b/third_party/pexpect/README
@@ -8,38 +8,34 @@ Don Libes' Expect. Pexpect allows your script to spawn a child application and
control it as if a human were typing commands.
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. Unlike other Expect-like modules for
-Python, Pexpect does not require TCL or Expect nor does it require C
-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.
+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. Unlike other Expect-like modules for Python, Pexpect
+does not require TCL or Expect nor does it require C 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.
If you want to work with the development version of the source code then please
read the DEVELOPERS document in the root of the source code tree.
Free, open source, and all that good stuff.
-Pexpect Copyright (c) 2008 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/
+PEXPECT LICENSE
+
+ This license is approved by the OSI and FSF as GPL-compatible.
+ http://opensource.org/licenses/isc-license.txt
+
+ Copyright (c) 2012, Noah Spurrier <noah@noah.org>
+ PERMISSION TO USE, COPY, MODIFY, AND/OR DISTRIBUTE THIS SOFTWARE FOR ANY
+ PURPOSE WITH OR WITHOUT FEE IS HEREBY GRANTED, PROVIDED THAT THE ABOVE
+ COPYRIGHT NOTICE AND THIS PERMISSION NOTICE APPEAR IN ALL COPIES.
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
diff --git a/third_party/pexpect/README.chromium b/third_party/pexpect/README.chromium
index 810cc7e..68ab678 100644
--- a/third_party/pexpect/README.chromium
+++ b/third_party/pexpect/README.chromium
@@ -3,7 +3,7 @@ Short Name: pexpect
URL: http://www.noah.org/python/pexpect/
Version: 2.3
Date: 2008-01-05
-Revision: r509
+Revision: r533
License: MIT
License File: LICENSE
Security Critical: no
diff --git a/third_party/pexpect/fdpexpect.py b/third_party/pexpect/fdpexpect.py
index 0ece98e..248f6e2 100644
--- a/third_party/pexpect/fdpexpect.py
+++ b/third_party/pexpect/fdpexpect.py
@@ -1,7 +1,23 @@
"""This is like pexpect, but will work on any file descriptor that you pass it.
-So you are reponsible for opening and close the file descriptor.
+You are reponsible for opening and close the file descriptor.
+
+PEXPECT LICENSE
+
+ This license is approved by the OSI and FSF as GPL-compatible.
+ http://opensource.org/licenses/isc-license.txt
+
+ Copyright (c) 2012, Noah Spurrier <noah@noah.org>
+ PERMISSION TO USE, COPY, MODIFY, AND/OR DISTRIBUTE THIS SOFTWARE FOR ANY
+ PURPOSE WITH OR WITHOUT FEE IS HEREBY GRANTED, PROVIDED THAT THE ABOVE
+ COPYRIGHT NOTICE AND THIS PERMISSION NOTICE APPEAR IN ALL COPIES.
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-$Id: fdpexpect.py 505 2007-12-26 21:33:50Z noah $
"""
from pexpect import *
diff --git a/third_party/pexpect/pexpect.py b/third_party/pexpect/pexpect.py
index 67c6389..ade20b2 100644
--- a/third_party/pexpect/pexpect.py
+++ b/third_party/pexpect/pexpect.py
@@ -9,62 +9,64 @@ 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
+There are two main interfaces to the Pexpect system; these are the function,
+run() and the class, spawn. The spawn class is more powerful. The run()
+function is simpler than spawn, and is good for quickly calling program. When
+you call the run() function it executes a given program and then returns 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.
+The spawn class is the more powerful interface to the Pexpect system. You can
+use this to spawn a child program then interact with it by sending input and
+expecting responses (waiting for patterns in the child's output).
For example::
- child = pexpect.spawn('scp foo myname@host.example.com:.')
- child.expect ('Password:')
- child.sendline (mypassword)
+ child = pexpect.spawn('scp foo user@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.
+the normal stdio streams. For example, ssh reads input directly from the TTY
+device which bypasses stdin.
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, Corey Minyard, Jon Cohen, Guillaume Chazarain, Andrew Ryan, Nick
-Craig-Wood, Andrew Stone, Jorgen Grahn (Let me know if I forgot anyone.)
-
-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) 2008 Noah Spurrier
+Jacques-Etienne Baudoux, Geoffrey Marshall, Francisco Lourenco, Glen Mabey,
+Karthik Gurusamy, Fernando Perez, Corey Minyard, Jon Cohen, Guillaume
+Chazarain, Andrew Ryan, Nick Craig-Wood, Andrew Stone, Jorgen Grahn, John
+Spiegel, Jan Grant, and Shane Kerr. Let me know if I forgot anyone.
+
+Pexpect is free, open source, and all that good stuff.
http://pexpect.sourceforge.net/
-$Id: pexpect.py 507 2007-12-27 02:40:52Z noah $
+PEXPECT LICENSE
+
+ This license is approved by the OSI and FSF as GPL-compatible.
+ http://opensource.org/licenses/isc-license.txt
+
+ Copyright (c) 2012, Noah Spurrier <noah@noah.org>
+ PERMISSION TO USE, COPY, MODIFY, AND/OR DISTRIBUTE THIS SOFTWARE FOR ANY
+ PURPOSE WITH OR WITHOUT FEE IS HEREBY GRANTED, PROVIDED THAT THE ABOVE
+ COPYRIGHT NOTICE AND THIS PERMISSION NOTICE APPEAR IN ALL COPIES.
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
"""
try:
- import os, sys, time
+ import os
+ import sys
+ import time
import select
import string
import re
@@ -78,17 +80,18 @@ try:
import errno
import traceback
import signal
-except ImportError, e:
- raise ImportError (str(e) + """
+except ImportError as e:
+ raise ImportError(str(e) + """
A critical module was not found. Probably this operating system does not
support it. Pexpect is intended for UNIX-like operating systems.""")
-__version__ = '2.3'
-__revision__ = '$Revision: 399 $'
+__version__ = '2.6'
+__revision__ = '1'
__all__ = ['ExceptionPexpect', 'EOF', 'TIMEOUT', 'spawn', 'run', 'which',
'split_command_line', '__version__', '__revision__']
+
# Exception classes used by this module.
class ExceptionPexpect(Exception):
@@ -124,9 +127,12 @@ class ExceptionPexpect(Exception):
else:
return False
+
class EOF(ExceptionPexpect):
- """Raised when EOF is read from a child. This usually means the child has exited."""
+ """Raised when EOF is read from a child.
+ This usually means the child has exited."""
+
class TIMEOUT(ExceptionPexpect):
@@ -139,9 +145,11 @@ class TIMEOUT(ExceptionPexpect):
## may never match a pattern.
## """
##class MAXBUFFER(ExceptionPexpect):
-## """Raised when a scan buffer fills before matching an expected pattern."""
+## """Raised when a buffer fills before matching an expected pattern."""
+
-def run (command, timeout=-1, withexitstatus=False, events=None, extra_args=None, logfile=None, cwd=None, env=None):
+def run(command, timeout=-1, withexitstatus=False, events=None,
+ extra_args=None, logfile=None, cwd=None, env=None):
"""
This function runs the given command; waits for it to finish; then
@@ -149,7 +157,7 @@ def run (command, timeout=-1, withexitstatus=False, events=None, extra_args=None
path to the command is not given then the path is searched.
Note that lines are terminated by CR/LF (\\r\\n) combination even on
- UNIX-like systems because this is the standard for pseudo ttys. If you set
+ UNIX-like systems because this is the standard for pseudottys. 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.
@@ -158,14 +166,14 @@ def run (command, timeout=-1, withexitstatus=False, events=None, extra_args=None
For example, the following code uses spawn::
from pexpect import *
- child = spawn('scp foo myname@host.example.com:.')
- child.expect ('(?i)password')
- child.sendline (mypassword)
+ child = spawn('scp foo user@example.com:.')
+ child.expect('(?i)password')
+ child.sendline(mypassword)
The previous code can be replace with the following::
from pexpect import *
- run ('scp foo myname@host.example.com:.', events={'(?i)password': mypassword})
+ run('scp foo user@example.com:.', events={'(?i)password': mypassword})
Examples
========
@@ -173,17 +181,17 @@ def run (command, timeout=-1, withexitstatus=False, events=None, extra_args=None
Start the apache daemon on the local machine::
from pexpect import *
- run ("/usr/local/apache/bin/apachectl start")
+ run("/usr/local/apache/bin/apachectl start")
Check in a file using SVN::
from pexpect import *
- run ("svn ci -m 'automatic commit' my_file.py")
+ run("svn ci -m 'automatic commit' my_file.py")
Run a command and capture exit status::
from pexpect import *
- (command_output, exitstatus) = run ('ls -l /bin', withexitstatus=1)
+ (command_output, exitstatus) = run('ls -l /bin', withexitstatus=1)
Tricky Examples
===============
@@ -191,7 +199,8 @@ def run (command, timeout=-1, withexitstatus=False, events=None, extra_args=None
The following will run SSH and execute 'ls -l' on the remote machine. The
password 'secret' will be sent if the '(?i)password' pattern is ever seen::
- run ("ssh username@machine.example.com 'ls -l'", events={'(?i)password':'secret\\n'})
+ run("ssh username@machine.example.com 'ls -l'",
+ events={'(?i)password':'secret\\n'})
This will start mencoder to rip a video from DVD. This will also display
progress ticks every 5 seconds as it runs. For example::
@@ -199,7 +208,8 @@ def run (command, timeout=-1, withexitstatus=False, events=None, extra_args=None
from pexpect import *
def print_ticks(d):
print d['event_count'],
- run ("mencoder dvd://1 -o video.avi -oac copy -ovc copy", events={TIMEOUT:print_ticks}, timeout=5)
+ run("mencoder dvd://1 -o video.avi -oac copy -ovc copy",
+ events={TIMEOUT:print_ticks}, timeout=5)
The 'events' argument should be a dictionary of patterns and responses.
Whenever one of the patterns is seen in the command out run() will send the
@@ -218,25 +228,29 @@ def run (command, timeout=-1, withexitstatus=False, events=None, extra_args=None
if timeout == -1:
child = spawn(command, maxread=2000, logfile=logfile, cwd=cwd, env=env)
else:
- child = spawn(command, timeout=timeout, maxread=2000, logfile=logfile, cwd=cwd, env=env)
+ child = spawn(command, timeout=timeout, maxread=2000, logfile=logfile,
+ cwd=cwd, env=env)
if events is not None:
- patterns = events.keys()
- responses = events.values()
+ patterns = list(events.keys())
+ responses = list(events.values())
else:
- patterns=None # We assume that EOF or TIMEOUT will save us.
- responses=None
+ # This assumes EOF or TIMEOUT will eventually cause run to terminate.
+ patterns = None
+ responses = None
child_result_list = []
event_count = 0
- while 1:
+ while True:
try:
- index = child.expect (patterns)
+ index = child.expect(patterns)
if type(child.after) in types.StringTypes:
child_result_list.append(child.before + child.after)
- else: # child.after may have been a TIMEOUT or EOF, so don't cat those.
+ else:
+ # child.after may have been a TIMEOUT or EOF,
+ # which we don't want appended to the list.
child_result_list.append(child.before)
if type(responses[index]) in types.StringTypes:
child.send(responses[index])
- elif type(responses[index]) is types.FunctionType:
+ elif isinstance(responses[index], types.FunctionType):
callback_result = responses[index](locals())
sys.stdout.flush()
if type(callback_result) in types.StringTypes:
@@ -244,12 +258,12 @@ def run (command, timeout=-1, withexitstatus=False, events=None, extra_args=None
elif callback_result:
break
else:
- raise TypeError ('The callback must be a string or function type.')
+ raise TypeError('The callback must be a string or function.')
event_count = event_count + 1
- except TIMEOUT, e:
+ except TIMEOUT as e:
child_result_list.append(child.before)
break
- except EOF, e:
+ except EOF as e:
child_result_list.append(child.before)
break
child_result = ''.join(child_result_list)
@@ -259,25 +273,27 @@ def run (command, timeout=-1, withexitstatus=False, events=None, extra_args=None
else:
return child_result
-class spawn (object):
+
+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, cwd=None, env=None):
+ def __init__(self, command, args=[], timeout=30, maxread=2000,
+ searchwindowsize=None, logfile=None, cwd=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::
- child = pexpect.spawn ('/usr/bin/ftp')
- child = pexpect.spawn ('/usr/bin/ssh user@example.com')
- child = pexpect.spawn ('ls -latr /tmp')
+ child = pexpect.spawn('/usr/bin/ftp')
+ child = pexpect.spawn('/usr/bin/ssh user@example.com')
+ child = pexpect.spawn('ls -latr /tmp')
You may also construct it with a list of arguments like so::
- child = pexpect.spawn ('/usr/bin/ftp', [])
- child = pexpect.spawn ('/usr/bin/ssh', ['user@example.com'])
- child = pexpect.spawn ('ls', ['-latr', '/tmp'])
+ child = pexpect.spawn('/usr/bin/ftp', [])
+ child = pexpect.spawn('/usr/bin/ssh', ['user@example.com'])
+ child = pexpect.spawn('ls', ['-latr', '/tmp'])
After this the child application will be created and will be ready to
talk to. For normal use, see expect() and send() and sendline().
@@ -287,7 +303,7 @@ class spawn (object):
If you want to run a command and pipe it through another command then
you must also start a shell. For example::
- child = pexpect.spawn('/bin/bash -c "ls -l | grep LOG > log_list.txt"')
+ child = pexpect.spawn('/bin/bash -c "ls -l | grep LOG > logs.txt"')
child.expect(pexpect.EOF)
The second form of spawn (where you pass a list of arguments) is useful
@@ -295,7 +311,7 @@ class spawn (object):
argument list. This can make syntax more clear. For example, the
following is equivalent to the previous example::
- shell_cmd = 'ls -l | grep LOG > log_list.txt'
+ shell_cmd = 'ls -l | grep LOG > logs.txt'
child = pexpect.spawn('/bin/bash', ['-c', shell_cmd])
child.expect(pexpect.EOF)
@@ -336,12 +352,12 @@ class spawn (object):
the input from the child and output sent to the child. Sometimes you
don't want to see everything you write to the child. You only want to
log what the child sends back. For example::
-
+
child = pexpect.spawn('some_command')
child.logfile_read = sys.stdout
To separately log output sent to the child use logfile_send::
-
+
self.logfile_send = fout
The delaybeforesend helps overcome a weird behavior that many users
@@ -390,43 +406,56 @@ class spawn (object):
self.terminated = True
self.exitstatus = None
self.signalstatus = None
- self.status = None # status returned by os.waitpid
+ # status returned by os.waitpid
+ self.status = None
self.flag_eof = False
self.pid = None
- self.child_fd = -1 # initially closed
+ # the chile filedescriptor is initially closed
+ self.child_fd = -1
self.timeout = timeout
self.delimiter = EOF
self.logfile = logfile
- self.logfile_read = None # input from child (read_nonblocking)
- self.logfile_send = None # output to send (send, sendline)
- self.maxread = maxread # max bytes to read at one time into buffer
- self.buffer = '' # This is the read buffer. See maxread.
- self.searchwindowsize = searchwindowsize # Anything before searchwindowsize point is preserved, but not searched.
- # Most Linux machines don't like delaybeforesend to be below 0.03 (30 ms).
- self.delaybeforesend = 0.05 # Sets sleep time used just before sending data to child. Time in seconds.
- self.delayafterclose = 0.1 # Sets delay in close() method to allow kernel time to update process status. Time in seconds.
- self.delayafterterminate = 0.1 # Sets delay in terminate() method to allow kernel time to update process status. Time in seconds.
- self.softspace = False # File-like object.
- self.name = '<' + repr(self) + '>' # File-like object.
- self.encoding = None # File-like object.
- self.closed = True # File-like object.
+ # input from child (read_nonblocking)
+ self.logfile_read = None
+ # output to send (send, sendline)
+ self.logfile_send = None
+ # max bytes to read at one time into buffer
+ self.maxread = maxread
+ # This is the read buffer. See maxread.
+ self.buffer = ''
+ # Data before searchwindowsize point is preserved, but not searched.
+ self.searchwindowsize = searchwindowsize
+ # Delay used before sending data to child. Time in seconds.
+ # Most Linux machines don't like this to be below 0.03 (30 ms).
+ self.delaybeforesend = 0.05
+ # Used by close() to give kernel time to update process status.
+ # Time in seconds.
+ self.delayafterclose = 0.1
+ # Used by terminate() to give kernel time to update process status.
+ # Time in seconds.
+ self.delayafterterminate = 0.1
+ self.softspace = False
+ self.name = '<' + repr(self) + '>'
+ self.encoding = None
+ self.closed = True
self.cwd = cwd
self.env = env
- self.__irix_hack = (sys.platform.lower().find('irix')>=0) # This flags if we are running on irix
+ # This flags if we are running on irix
+ self.__irix_hack = (sys.platform.lower().find('irix') >= 0)
# Solaris uses internal __fork_pty(). All others use pty.fork().
- if (sys.platform.lower().find('solaris')>=0) or (sys.platform.lower().find('sunos5')>=0):
+ if ((sys.platform.lower().find('solaris') >= 0)
+ or (sys.platform.lower().find('sunos5') >= 0)):
self.use_native_pty_fork = False
else:
self.use_native_pty_fork = True
-
- # allow dummy instances for subclasses that may not use command or args.
+ # Support subclasses that do not use command or args.
if command is None:
self.command = None
self.args = None
self.name = '<pexpect factory incomplete>'
else:
- self._spawn (command, args)
+ self._spawn(command, args)
def __del__(self):
@@ -443,7 +472,7 @@ class spawn (object):
# -- Fernando Perez
try:
self.close()
- except AttributeError:
+ except:
pass
def __str__(self):
@@ -480,7 +509,7 @@ class spawn (object):
s.append('delayafterterminate: ' + str(self.delayafterterminate))
return '\n'.join(s)
- def _spawn(self,command,args=[]):
+ def _spawn(self, command, args=[]):
"""This starts the given command in a child process. This does all the
fork/exec type of stuff for a pty. This is called by __init__. If args
@@ -493,46 +522,54 @@ class spawn (object):
# So the only way you can tell if the child process started
# or not is to try to read from the file descriptor. If you get
# EOF immediately then it means that the child is already dead.
- # That may not necessarily be bad because you may haved spawned a child
+ # That may not necessarily be bad because you may have spawned a child
# that performs some task; creates no stdout output; and then dies.
# 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 isinstance(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 argument, args, must be a list.')
+ if not isinstance(args, type([])):
+ raise TypeError('The argument, args, must be a list.')
if args == []:
self.args = split_command_line(command)
self.command = self.args[0]
else:
- self.args = args[:] # work with a copy
- self.args.insert (0, command)
+ # Make a shallow copy of the args list.
+ self.args = args[:]
+ self.args.insert(0, command)
self.command = command
command_with_path = which(self.command)
if command_with_path is None:
- raise ExceptionPexpect ('The command was not found or was not executable: %s.' % self.command)
+ raise ExceptionPexpect('The command was not found or was not ' +
+ 'executable: %s.' % self.command)
self.command = command_with_path
self.args[0] = self.command
- self.name = '<' + ' '.join (self.args) + '>'
+ self.name = '<' + ' '.join(self.args) + '>'
- assert self.pid is None, 'The pid member should be None.'
- assert self.command is not None, 'The command member should not be None.'
+ assert self.pid is None, 'The pid member must be None.'
+ assert self.command is not None, 'The command member must 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
+ except OSError as e:
+ raise ExceptionPexpect('pty.fork() failed: ' + str(e))
+ else:
+ # Use internal __fork_pty
self.pid, self.child_fd = self.__fork_pty()
- if self.pid == 0: # Child
+ if self.pid == 0:
+ # Child
try:
- self.child_fd = sys.stdout.fileno() # used by setwinsize()
+ # used by setwinsize()
+ self.child_fd = sys.stdout.fileno()
self.setwinsize(24, 80)
except:
# Some platforms do not like setwinsize (Cygwin).
@@ -542,9 +579,9 @@ class spawn (object):
pass
# Do not allow child to inherit open file descriptors from parent.
max_fd = resource.getrlimit(resource.RLIMIT_NOFILE)[0]
- for i in range (3, max_fd):
+ for i in range(3, max_fd):
try:
- os.close (i)
+ os.close(i)
except OSError:
pass
@@ -581,11 +618,11 @@ class spawn (object):
parent_fd, child_fd = os.openpty()
if parent_fd < 0 or child_fd < 0:
- raise ExceptionPexpect, "Error! Could not open pty with os.openpty()."
+ raise ExceptionPexpect("Could not open with os.openpty().")
pid = os.fork()
if pid < 0:
- raise ExceptionPexpect, "Error! Failed os.fork()."
+ raise ExceptionPexpect("Failed os.fork().")
elif pid == 0:
# Child.
os.close(parent_fd)
@@ -611,45 +648,51 @@ class spawn (object):
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)
+ # Disconnect from controlling tty. Harmless if not already connected.
+ try:
+ fd = os.open("/dev/tty", os.O_RDWR | os.O_NOCTTY)
+ if fd >= 0:
+ os.close(fd)
+ except:
+ # Already disconnected. This happens if running inside cron.
+ pass
os.setsid()
# Verify we are disconnected from controlling tty
+ # by attempting to open it again.
try:
- fd = os.open("/dev/tty", os.O_RDWR | os.O_NOCTTY);
+ 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."
+ raise ExceptionPexpect('Failed to disconnect from ' +
+ 'controlling tty. It is still possible to open /dev/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);
+ fd = os.open(child_name, os.O_RDWR)
if fd < 0:
- raise ExceptionPexpect, "Error! Could not open child pty, " + child_name
+ raise ExceptionPexpect("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"
+ raise ExceptionPexpect("Could not open controlling tty, /dev/tty")
else:
os.close(fd)
- def fileno (self): # File-like object.
+ def fileno(self):
"""This returns the file descriptor of the pty for the child.
"""
return self.child_fd
- def close (self, force=True): # File-like object.
+ def close(self, force=True):
"""This closes the connection with the child application. Note that
calling close() more than once is valid. This emulates standard Python
@@ -659,30 +702,31 @@ class spawn (object):
if not self.closed:
self.flush()
- os.close (self.child_fd)
- time.sleep(self.delayafterclose) # Give kernel time to update process status.
+ os.close(self.child_fd)
+ # Give kernel time to update process status.
+ time.sleep(self.delayafterclose)
if self.isalive():
if not self.terminate(force):
- raise ExceptionPexpect ('close() could not terminate the child using terminate()')
+ raise ExceptionPexpect('Could not terminate the child.')
self.child_fd = -1
self.closed = True
#self.pid = None
- def flush (self): # File-like object.
+ def flush(self):
"""This does nothing. It is here to support the interface for a
File-like object. """
pass
- def isatty (self): # File-like object.
+ def isatty(self):
"""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 waitnoecho (self, timeout=-1):
+ def waitnoecho(self, timeout=-1):
"""This waits until the terminal ECHO flag is set False. This returns
True if the echo mode is off. This returns False if the ECHO flag was
@@ -692,19 +736,18 @@ class spawn (object):
example, instead of expecting the "password:" prompt you can wait for
the child to set ECHO off::
- p = pexpect.spawn ('ssh user@example.com')
+ p = pexpect.spawn('ssh user@example.com')
p.waitnoecho()
p.sendline(mypassword)
- If timeout is None then this method to block forever until ECHO flag is
- False.
-
+ If timeout==-1 then this method will use the value in self.timeout.
+ If timeout==None then this method to block until ECHO flag is False.
"""
if timeout == -1:
timeout = self.timeout
if timeout is not None:
- end_time = time.time() + timeout
+ end_time = time.time() + timeout
while True:
if not self.getecho():
return True
@@ -714,7 +757,7 @@ class spawn (object):
timeout = end_time - time.time()
time.sleep(0.1)
- def getecho (self):
+ def getecho(self):
"""This returns the terminal echo mode. This returns True if echo is
on or False if echo is off. Child applications that are expecting you
@@ -725,35 +768,35 @@ class spawn (object):
return True
return False
- def setecho (self, state):
+ 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 call setecho(). For example, the
following will work as expected::
- p = pexpect.spawn('cat')
- p.sendline ('1234') # We will see this twice (once from tty echo and again from cat).
- p.expect (['1234'])
- p.expect (['1234'])
+ p = pexpect.spawn('cat') # Echo is on by default.
+ p.sendline('1234') # We expect see this twice from the child...
+ p.expect(['1234']) # ... once from the tty echo...
+ p.expect(['1234']) # ... and again from cat itself.
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'])
- p.expect (['wxyz'])
+ 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'])
+ p.expect(['wxyz'])
The following WILL NOT WORK because the lines sent before the setecho
will be lost::
p = pexpect.spawn('cat')
- p.sendline ('1234') # We will see this twice (once from tty echo and again from cat).
+ p.sendline('1234')
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'])
- p.expect (['1234'])
- p.expect (['abcd'])
- p.expect (['wxyz'])
+ 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'])
+ p.expect(['1234'])
+ p.expect(['abcd'])
+ p.expect(['wxyz'])
"""
self.child_fd
@@ -762,11 +805,12 @@ class spawn (object):
attr[3] = attr[3] | termios.ECHO
else:
attr[3] = attr[3] & ~termios.ECHO
- # I tried TCSADRAIN and TCSAFLUSH, but these were inconsistent
- # and blocked on some platforms. TCSADRAIN is probably ideal if it worked.
+ # I tried TCSADRAIN and TCSAFLUSH, but
+ # these were inconsistent and blocked on some platforms.
+ # TCSADRAIN would probably be ideal if it worked.
termios.tcsetattr(self.child_fd, termios.TCSANOW, attr)
- def read_nonblocking (self, size = 1, timeout = -1):
+ 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 timeout
@@ -774,10 +818,10 @@ class spawn (object):
then an EOF exception will be raised. If a log file was set using
setlog() then all data will also be written to the log file.
- If timeout is None then the read may block indefinitely. If timeout is -1
- then the self.timeout value is used. If timeout is 0 then the child is
- polled and if there was no data immediately ready then this will raise
- a TIMEOUT exception.
+ If timeout is None then the read may block indefinitely.
+ If timeout is -1 then the self.timeout value is used. If timeout is 0
+ then the child is polled and if there is no data immediately ready
+ then this will raise a TIMEOUT exception.
The timeout refers only to the amount of time to read at least one
character. This is not effected by the 'size' parameter, so if you call
@@ -789,7 +833,7 @@ class spawn (object):
implement the timeout. """
if self.closed:
- raise ValueError ('I/O operation on closed file in read_nonblocking().')
+ raise ValueError('I/O operation on closed file.')
if timeout == -1:
timeout = self.timeout
@@ -800,51 +844,54 @@ class spawn (object):
# 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 = self.__select([self.child_fd], [], [], 0) # timeout of 0 means "poll"
+ # timeout of 0 means "poll"
+ r, w, e = self.__select([self.child_fd], [], [], 0)
if not r:
self.flag_eof = True
- raise EOF ('End Of File (EOF) in read_nonblocking(). Braindead platform.')
+ raise EOF('End Of File (EOF). Braindead platform.')
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.
+ # Irix takes a long time before it realizes a child was terminated.
+ # FIXME So does this mean Irix systems are forced to always have
+ # FIXME a 2 second delay when calling read_nonblocking? That sucks.
r, w, e = self.__select([self.child_fd], [], [], 2)
if not r and not self.isalive():
self.flag_eof = True
- raise EOF ('End Of File (EOF) in read_nonblocking(). Pokey platform.')
+ raise EOF('End Of File (EOF). Slow platform.')
- r,w,e = self.__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.
+ # Some platforms, such as Irix, will claim that their
+ # processes are alive; timeout on the select; and
+ # then finally admit that they are not alive.
self.flag_eof = True
- raise EOF ('End of File (EOF) in read_nonblocking(). Very pokey platform.')
+ raise EOF('End of File (EOF). Very slow platform.')
else:
- raise TIMEOUT ('Timeout exceeded in read_nonblocking().')
+ raise TIMEOUT('Timeout exceeded.')
if self.child_fd in r:
try:
s = os.read(self.child_fd, size)
- except OSError, e: # Linux does this
+ except OSError as e:
+ # Linux does this
self.flag_eof = True
- raise EOF ('End Of File (EOF) in read_nonblocking(). Exception style platform.')
- if s == '': # BSD style
+ raise EOF('End Of File (EOF). Exception style platform.')
+ if s == '':
+ # BSD style
self.flag_eof = True
- raise EOF ('End Of File (EOF) in read_nonblocking(). Empty string style platform.')
-
+ raise EOF('End Of File (EOF). Empty string style platform.')
if self.logfile is not None:
- self.logfile.write (s)
+ self.logfile.write(s)
self.logfile.flush()
if self.logfile_read is not None:
- self.logfile_read.write (s)
+ self.logfile_read.write(s)
self.logfile_read.flush()
-
return s
- raise ExceptionPexpect ('Reached an unexpected state in read_nonblocking().')
+ raise ExceptionPexpect('Reached an unexpected state.')
- def read (self, size = -1): # File-like object.
+ def read(self, size=-1):
"""This reads at most "size" bytes from the file (less if the read hits
EOF before obtaining size bytes). If the size argument is negative or
@@ -855,7 +902,8 @@ class spawn (object):
if size == 0:
return ''
if size < 0:
- self.expect (self.delimiter) # delimiter default is EOF
+ # delimiter default is EOF
+ self.expect(self.delimiter)
return self.before
# I could have done this more directly by not using expect(), but
@@ -866,38 +914,43 @@ class spawn (object):
# Note, it's OK if size==-1 in the regex. That just means it
# will never match anything in which case we stop only on EOF.
cre = re.compile('.{%d}' % size, re.DOTALL)
- index = self.expect ([cre, self.delimiter]) # delimiter default is EOF
+ # delimiter default is EOF
+ index = self.expect([cre, self.delimiter])
if index == 0:
- return self.after ### self.before should be ''. Should I assert this?
+ ### FIXME self.before should be ''. Should I assert this?
+ return self.after
return self.before
- def readline (self, size = -1): # File-like object.
+ def readline(self, size=-1):
+
+ """This reads and returns one entire line. The newline at the end of
+ line is returned as part of the string, unless the file ends without a
+ newline. An empty string is returned if EOF is encountered immediately.
+ This looks for a newline as a CR/LF pair (\\r\\n) even on UNIX because
+ this is what the pseudotty device returns. So contrary to what you may
+ expect you will receive newlines as \\r\\n.
- """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 expect you will receive the newline as \\r\\n. An empty string
- is returned when EOF is hit immediately. Currently, the size argument is
- mostly ignored, so this behavior is not standard for a file-like
- object. If size is 0 then an empty string is returned. """
+ If the size argument is 0 then an empty string is returned. In all
+ other cases the size argument is ignored, which is not standard
+ behavior for a file-like object. """
if size == 0:
return ''
- index = self.expect (['\r\n', self.delimiter]) # delimiter default is EOF
+ # delimiter default is EOF
+ index = self.expect(['\r\n', self.delimiter])
if index == 0:
return self.before + '\r\n'
else:
return self.before
- def __iter__ (self): # File-like object.
+ def __iter__(self):
"""This is to support iterators over a file-like object.
"""
return self
- def next (self): # File-like object.
+ def __next__(self):
"""This is to support iterators over a file-like object.
"""
@@ -907,10 +960,10 @@ class spawn (object):
raise StopIteration
return result
- def readlines (self, sizehint = -1): # File-like object.
+ def readlines(self, sizehint=-1):
"""This reads until EOF using readline() and returns a list containing
- the lines thus read. The optional "sizehint" argument is ignored. """
+ the lines thus read. The optional 'sizehint' argument is ignored. """
lines = []
while True:
@@ -920,14 +973,14 @@ class spawn (object):
lines.append(line)
return lines
- def write(self, s): # File-like object.
+ def write(self, s):
"""This is similar to send() except that there is no return value.
"""
- self.send (s)
+ self.send(s)
- def writelines (self, sequence): # File-like object.
+ def writelines(self, sequence):
"""This calls write() for each element in the sequence. The sequence
can be any iterable object producing strings, typically a list of
@@ -935,7 +988,7 @@ class spawn (object):
"""
for s in sequence:
- self.write (s)
+ self.write(s)
def send(self, s):
@@ -945,21 +998,21 @@ class spawn (object):
time.sleep(self.delaybeforesend)
if self.logfile is not None:
- self.logfile.write (s)
+ self.logfile.write(s)
self.logfile.flush()
if self.logfile_send is not None:
- self.logfile_send.write (s)
+ self.logfile_send.write(s)
self.logfile_send.flush()
- c = os.write(self.child_fd, s)
+ c = os.write(self.child_fd, s.encode("utf-8"))
return c
def sendline(self, s=''):
- """This is like send(), but it adds a line feed (os.linesep). This
+ """This is like send(), but it adds a linefeed (os.linesep). This
returns the number of bytes written. """
n = self.send(s)
- n = n + self.send (os.linesep)
+ n = n + self.send(os.linesep)
return n
def sendcontrol(self, char):
@@ -974,19 +1027,19 @@ class spawn (object):
char = char.lower()
a = ord(char)
- if a>=97 and a<=122:
+ if a >= 97 and a <= 122:
a = a - ord('a') + 1
- return self.send (chr(a))
- d = {'@':0, '`':0,
- '[':27, '{':27,
- '\\':28, '|':28,
- ']':29, '}': 29,
- '^':30, '~':30,
- '_':31,
- '?':127}
+ return self.send(chr(a))
+ d = {'@': 0, '`': 0,
+ '[': 27, '{': 27,
+ '\\': 28, '|': 28,
+ ']': 29, '}': 29,
+ '^': 30, '~': 30,
+ '_': 31,
+ '?': 127}
if char not in d:
return 0
- return self.send (chr(d[char]))
+ return self.send(chr(d[char]))
def sendeof(self):
@@ -1005,14 +1058,14 @@ class spawn (object):
#fd = sys.stdin.fileno()
#old = termios.tcgetattr(fd) # remember current state
#attr = termios.tcgetattr(fd)
- #attr[3] = attr[3] | termios.ICANON # ICANON must be set to recognize EOF
+ #attr[3] = attr[3] | termios.ICANON # ICANON must be set to see EOF
#try: # use try/finally to ensure state gets restored
# termios.tcsetattr(fd, termios.TCSADRAIN, attr)
# if hasattr(termios, 'CEOF'):
- # os.write (self.child_fd, '%c' % termios.CEOF)
+ # os.write(self.child_fd, '%c' % termios.CEOF)
# else:
# # Silly platform does not define CEOF so assume CTRL-D
- # os.write (self.child_fd, '%c' % 4)
+ # os.write(self.child_fd, '%c' % 4)
#finally: # restore state
# termios.tcsetattr(fd, termios.TCSADRAIN, old)
if hasattr(termios, 'VEOF'):
@@ -1032,9 +1085,9 @@ class spawn (object):
else:
# platform does not define VINTR so assume CTRL-C
char = chr(3)
- self.send (char)
+ self.send(char)
- def eof (self):
+ def eof(self):
"""This returns True if the EOF exception was ever raised.
"""
@@ -1071,7 +1124,7 @@ class spawn (object):
else:
return False
return False
- except OSError, e:
+ except OSError as e:
# I think there are kernel timing issues that sometimes cause
# this to happen. I think isalive() reports True, but the
# process is dead to the kernel.
@@ -1087,26 +1140,29 @@ class spawn (object):
"""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. """
+ may have printed output then called exit(), but, the child is
+ technically still alive until its output is read by the parent. """
if self.isalive():
pid, status = os.waitpid(self.pid, 0)
else:
- raise ExceptionPexpect ('Cannot wait for dead child process.')
+ raise ExceptionPexpect('Cannot wait for dead child process.')
self.exitstatus = os.WEXITSTATUS(status)
- if os.WIFEXITED (status):
+ if os.WIFEXITED(status):
self.status = status
self.exitstatus = os.WEXITSTATUS(status)
self.signalstatus = None
self.terminated = True
- elif os.WIFSIGNALED (status):
+ 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?')
+ elif os.WIFSTOPPED(status):
+ # You can't call wait() on a child process in the stopped state.
+ raise ExceptionPexpect('Called wait() on a stopped child ' +
+ 'process. This is not supported. Is some other ' +
+ 'process attempting job control with our child pid?')
return self.exitstatus
def isalive(self):
@@ -1121,55 +1177,70 @@ class spawn (object):
return False
if self.flag_eof:
- # This is for Linux, which requires the blocking form of waitpid to get
- # status of a defunct process. This is super-lame. The flag_eof would have
- # been set in read_nonblocking(), so this should be safe.
+ # This is for Linux, which requires the blocking form
+ # of waitpid to # get status of a defunct process.
+ # This is super-lame. The flag_eof would have been set
+ # in read_nonblocking(), so this should be safe.
waitpid_options = 0
else:
waitpid_options = os.WNOHANG
try:
pid, status = os.waitpid(self.pid, waitpid_options)
- except OSError, e: # No child processes
+ except OSError as e:
+ # No child processes
if e[0] == errno.ECHILD:
- raise ExceptionPexpect ('isalive() encountered condition where "terminated" is 0, but there was no child process. Did someone else call waitpid() on our process?')
+ raise ExceptionPexpect('isalive() encountered condition ' +
+ 'where "terminated" is 0, but there was no child ' +
+ 'process. Did someone else call waitpid() ' +
+ 'on our process?')
else:
raise e
- # I have to do this twice for Solaris. I can't even believe that I figured this out...
- # If waitpid() returns 0 it means that no child process wishes to
- # report, and the value of status is undefined.
+ # I have to do this twice for Solaris.
+ # I can't even believe that I figured this out...
+ # If waitpid() returns 0 it means that no child process
+ # wishes to report, and the value of status is undefined.
if pid == 0:
try:
- pid, status = os.waitpid(self.pid, waitpid_options) ### os.WNOHANG) # Solaris!
- except OSError, e: # This should never happen...
+ ### os.WNOHANG) # Solaris!
+ pid, status = os.waitpid(self.pid, waitpid_options)
+ except OSError as e:
+ # This should never happen...
if e[0] == errno.ECHILD:
- raise ExceptionPexpect ('isalive() encountered condition that should never happen. There was no child process. Did someone else call waitpid() on our process?')
+ raise ExceptionPexpect('isalive() encountered condition ' +
+ 'that should never happen. There was no child ' +
+ 'process. Did someone else call waitpid() ' +
+ 'on our process?')
else:
raise e
- # If pid is still 0 after two calls to waitpid() then
- # the process really is alive. This seems to work on all platforms, except
- # 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 is still 0 after two calls to waitpid() then the process
+ # really is alive. This seems to work on all platforms, except 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 True
if pid == 0:
return True
- if os.WIFEXITED (status):
+ if os.WIFEXITED(status):
self.status = status
self.exitstatus = os.WEXITSTATUS(status)
self.signalstatus = None
self.terminated = True
- elif os.WIFSIGNALED (status):
+ elif os.WIFSIGNALED(status):
self.status = status
self.exitstatus = None
self.signalstatus = os.WTERMSIG(status)
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?')
+ 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?')
return False
def kill(self, sig):
@@ -1209,10 +1280,11 @@ class spawn (object):
if patterns is None:
return []
- if type(patterns) is not types.ListType:
+ if not isinstance(patterns, list):
patterns = [patterns]
- compile_flags = re.DOTALL # Allow dot to match \n
+ # Allow dot to match \n
+ compile_flags = re.DOTALL
if self.ignorecase:
compile_flags = compile_flags | re.IGNORECASE
compiled_pattern_list = []
@@ -1223,14 +1295,16 @@ class spawn (object):
compiled_pattern_list.append(EOF)
elif p is TIMEOUT:
compiled_pattern_list.append(TIMEOUT)
- elif type(p) is type(re.compile('')):
+ elif isinstance(p, type(re.compile(''))):
compiled_pattern_list.append(p)
else:
- raise TypeError ('Argument must be one of StringTypes, EOF, TIMEOUT, SRE_Pattern, or a list of those type. %s' % str(type(p)))
+ raise TypeError('Argument must be one of StringTypes, ' +
+ 'EOF, TIMEOUT, SRE_Pattern, or a list of those ' +
+ 'type. %s' % str(type(p)))
return compiled_pattern_list
- def expect(self, pattern, timeout = -1, searchwindowsize=None):
+ def expect(self, pattern, timeout=-1, searchwindowsize=-1):
"""This seeks through the stream until a pattern is matched. The
pattern is overloaded and may take several types. The pattern can be a
@@ -1242,21 +1316,21 @@ class spawn (object):
list. That will cause expect to match an EOF or TIMEOUT condition
instead of raising an exception.
- If you pass a list of patterns and more than one matches, the first match
- in the stream is chosen. If more than one pattern matches at that point,
- the leftmost in the pattern list is chosen. For example::
+ If you pass a list of patterns and more than one matches, the first
+ match in the stream is chosen. If more than one pattern matches at that
+ point, the leftmost in the pattern list is chosen. For example::
# the input is 'foobar'
- index = p.expect (['bar', 'foo', 'foobar'])
- # returns 1 ('foo') even though 'foobar' is a "better" match
+ index = p.expect(['bar', 'foo', 'foobar'])
+ # returns 1('foo') even though 'foobar' is a "better" match
Please note, however, that buffering can affect this behavior, since
input arrives in unpredictable chunks. For example::
# the input is 'foobar'
- index = p.expect (['foobar', 'foo'])
- # returns 0 ('foobar') if all input is available at once,
- # but returs 1 ('foo') if parts of the final 'bar' arrive late
+ index = p.expect(['foobar', 'foo'])
+ # returns 0('foobar') if all input is available at once,
+ # but returs 1('foo') if parts of the final 'bar' arrive late
After a match is found the instance attributes 'before', 'after' and
'match' will be set. You can see all the data read before the match in
@@ -1273,7 +1347,7 @@ class spawn (object):
exception type. The attribute 'match' will be None. This allows you to
write code like this::
- index = p.expect (['good', 'bad', pexpect.EOF, pexpect.TIMEOUT])
+ index = p.expect(['good', 'bad', pexpect.EOF, pexpect.TIMEOUT])
if index == 0:
do_something()
elif index == 1:
@@ -1286,7 +1360,7 @@ class spawn (object):
instead of code like this::
try:
- index = p.expect (['good', 'bad'])
+ index = p.expect(['good', 'bad'])
if index == 0:
do_something()
elif index == 1:
@@ -1301,20 +1375,21 @@ class spawn (object):
child to finish. For example::
p = pexpect.spawn('/bin/ls')
- p.expect (pexpect.EOF)
+ p.expect(pexpect.EOF)
print p.before
If you are trying to optimize for speed then see expect_list().
"""
compiled_pattern_list = self.compile_pattern_list(pattern)
- return self.expect_list(compiled_pattern_list, timeout, searchwindowsize)
+ return self.expect_list(compiled_pattern_list,
+ timeout, searchwindowsize)
- def expect_list(self, pattern_list, timeout = -1, searchwindowsize = -1):
+ 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 output. The list may
- also contain EOF or TIMEOUT (which are not compiled regular
+ 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 recompile the pattern list on every call. This
may help if you are trying to optimize for speed, otherwise just use
@@ -1322,9 +1397,10 @@ class spawn (object):
the self.timeout value is used. If searchwindowsize==-1 then the
self.searchwindowsize value is used. """
- return self.expect_loop(searcher_re(pattern_list), timeout, searchwindowsize)
+ return self.expect_loop(searcher_re(pattern_list),
+ timeout, searchwindowsize)
- def expect_exact(self, pattern_list, timeout = -1, searchwindowsize = -1):
+ def expect_exact(self, pattern_list, timeout=-1, searchwindowsize=-1):
"""This is similar to expect(), but uses plain string matching instead
of compiled regular expressions in 'pattern_list'. The 'pattern_list'
@@ -1338,15 +1414,17 @@ class spawn (object):
This method is also useful when you don't want to have to worry about
escaping regular expression characters that you want to match."""
- if type(pattern_list) in types.StringTypes or pattern_list in (TIMEOUT, EOF):
+ if (type(pattern_list) in types.StringTypes or
+ pattern_list in (TIMEOUT, EOF)):
pattern_list = [pattern_list]
- return self.expect_loop(searcher_string(pattern_list), timeout, searchwindowsize)
+ return self.expect_loop(searcher_string(pattern_list),
+ timeout, searchwindowsize)
- def expect_loop(self, searcher, timeout = -1, searchwindowsize = -1):
+ def expect_loop(self, searcher, timeout=-1, searchwindowsize=-1):
"""This is the common loop used inside expect. The 'searcher' should be
- an instance of searcher_re or searcher_string, which describes how and what
- to search for in the input.
+ an instance of searcher_re or searcher_string, which describes how and
+ what to search for in the input.
See expect() for other arguments, return value and exceptions. """
@@ -1355,33 +1433,34 @@ class spawn (object):
if timeout == -1:
timeout = self.timeout
if timeout is not None:
- end_time = time.time() + timeout
+ end_time = time.time() + timeout
if searchwindowsize == -1:
searchwindowsize = self.searchwindowsize
try:
incoming = self.buffer
freshlen = len(incoming)
- while True: # Keep reading until exception or return.
+ while True:
+ # Keep reading until exception or return.
index = searcher.search(incoming, freshlen, searchwindowsize)
if index >= 0:
- self.buffer = incoming[searcher.end : ]
- self.before = incoming[ : searcher.start]
- self.after = incoming[searcher.start : searcher.end]
+ self.buffer = incoming[searcher.end:]
+ self.before = incoming[: searcher.start]
+ self.after = incoming[searcher.start: searcher.end]
self.match = searcher.match
self.match_index = index
return self.match_index
# No match at this point
if timeout < 0 and timeout is not None:
- raise TIMEOUT ('Timeout exceeded in expect_any().')
+ raise TIMEOUT('Timeout exceeded in expect_any().')
# Still have time left, so read more data
- c = self.read_nonblocking (self.maxread, timeout)
+ c = self.read_nonblocking(self.maxread, timeout)
freshlen = len(c)
- time.sleep (0.0001)
+ time.sleep(0.0001)
incoming = incoming + c
if timeout is not None:
timeout = end_time - time.time()
- except EOF, e:
+ except EOF as e:
self.buffer = ''
self.before = incoming
self.after = EOF
@@ -1393,8 +1472,8 @@ class spawn (object):
else:
self.match = None
self.match_index = None
- raise EOF (str(e) + '\n' + str(self))
- except TIMEOUT, e:
+ raise EOF(str(e) + '\n' + str(self))
+ except TIMEOUT as e:
self.buffer = incoming
self.before = incoming
self.after = TIMEOUT
@@ -1406,7 +1485,7 @@ class spawn (object):
else:
self.match = None
self.match_index = None
- raise TIMEOUT (str(e) + '\n' + str(self))
+ raise TIMEOUT(str(e) + '\n' + str(self))
except:
self.before = incoming
self.after = None
@@ -1419,12 +1498,12 @@ class spawn (object):
"""This returns the terminal window size of the child tty. The return
value is a tuple of (rows, cols). """
- TIOCGWINSZ = getattr(termios, 'TIOCGWINSZ', 1074295912L)
+ TIOCGWINSZ = getattr(termios, 'TIOCGWINSZ', 1074295912)
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):
+ def setwinsize(self, rows, cols):
"""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
@@ -1441,13 +1520,15 @@ class spawn (object):
# Newer versions of Linux have totally different values for TIOCSWINSZ.
# Note that this fix is a hack.
TIOCSWINSZ = getattr(termios, 'TIOCSWINSZ', -2146929561)
- if TIOCSWINSZ == 2148037735L: # L is not required in Python >= 2.2.
- TIOCSWINSZ = -2146929561 # Same bits, but with sign.
+ if TIOCSWINSZ == 2148037735:
+ # Same bits, but with sign.
+ TIOCSWINSZ = -2146929561
# Note, assume ws_xpixel and ws_ypixel are zero.
- s = struct.pack('HHHH', r, c, 0, 0)
+ s = struct.pack('HHHH', rows, cols, 0, 0)
fcntl.ioctl(self.fileno(), TIOCSWINSZ, s)
- def interact(self, escape_character = chr(29), input_filter = None, output_filter = None):
+ 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
@@ -1474,16 +1555,18 @@ class spawn (object):
import pexpect, struct, fcntl, termios, signal, sys
def sigwinch_passthrough (sig, data):
s = struct.pack("HHHH", 0, 0, 0, 0)
- a = struct.unpack('hhhh', fcntl.ioctl(sys.stdout.fileno(), termios.TIOCGWINSZ , s))
+ 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 and used in sigwinch_passthrough.
+ # Note this 'p' global and used in sigwinch_passthrough.
+ p = pexpect.spawn('/bin/bash')
signal.signal(signal.SIGWINCH, sigwinch_passthrough)
p.interact()
"""
# Flush the buffer.
- self.stdout.write (self.buffer)
+ self.stdout.write(self.buffer)
self.stdout.flush()
self.buffer = ''
mode = tty.tcgetattr(self.STDIN_FILENO)
@@ -1509,23 +1592,26 @@ class spawn (object):
return os.read(fd, 1000)
- def __interact_copy(self, escape_character = None, input_filter = None, output_filter = None):
+ def __interact_copy(self, escape_character=None,
+ input_filter=None, output_filter=None):
"""This is used by the interact() method.
"""
while self.isalive():
- r,w,e = self.__select([self.child_fd, self.STDIN_FILENO], [], [])
+ 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 output_filter: data = output_filter(data)
+ if output_filter:
+ data = output_filter(data)
if self.logfile is not None:
- self.logfile.write (data)
+ 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)
+ if input_filter:
+ data = input_filter(data)
i = data.rfind(escape_character)
if i != -1:
data = data[:i]
@@ -1533,7 +1619,7 @@ class spawn (object):
break
self.__interact_writen(self.child_fd, data)
- def __select (self, iwtd, owtd, ewtd, timeout=None):
+ 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
@@ -1546,41 +1632,51 @@ class spawn (object):
end_time = time.time() + timeout
while True:
try:
- return select.select (iwtd, owtd, ewtd, timeout)
- except select.error, e:
+ return select.select(iwtd, owtd, ewtd, timeout)
+ except select.error as e:
if e[0] == errno.EINTR:
- # if we loop back we have to subtract the amount of time we already waited.
+ # 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
+ return([], [], [])
+ else:
+ # something else caused the select.error, so
+ # this actually is an exception.
raise
##############################################################################
# The following methods are no longer supported or allowed.
- def setmaxread (self, maxread):
+ def setmaxread(self, maxread):
"""This method is no longer supported or allowed. I don't like getters
and setters without a good reason. """
- raise ExceptionPexpect ('This method is no longer supported or allowed. Just assign a value to the maxread member variable.')
+ raise ExceptionPexpect('This method is no longer supported ' +
+ 'or allowed. Just assign a value to the ' +
+ 'maxread member variable.')
- def setlog (self, fileobject):
+ def setlog(self, fileobject):
"""This method is no longer supported or allowed.
"""
- raise ExceptionPexpect ('This method is no longer supported or allowed. Just assign a value to the logfile member variable.')
+ raise ExceptionPexpect('This method is no longer supported ' +
+ 'or allowed. Just assign a value to the logfile ' +
+ 'member variable.')
##############################################################################
# End of spawn class
##############################################################################
-class searcher_string (object):
+
+class searcher_string(object):
"""This is a plain string search helper for the spawn.expect_any() method.
+ This helper class is for speed. For more powerful regex patterns
+ see the helper class, searcher_re.
Attributes:
@@ -1593,6 +1689,7 @@ class searcher_string (object):
start - index into the buffer, first byte of match
end - index into the buffer, first byte after match
match - the matching string itself
+
"""
def __init__(self, strings):
@@ -1603,7 +1700,7 @@ class searcher_string (object):
self.eof_index = -1
self.timeout_index = -1
self._strings = []
- for n, s in zip(range(len(strings)), strings):
+ for n, s in zip(list(range(len(strings))), strings):
if s is EOF:
self.eof_index = n
continue
@@ -1617,12 +1714,13 @@ class searcher_string (object):
"""This returns a human-readable string that represents the state of
the object."""
- ss = [ (ns[0],' %d: "%s"' % ns) for ns in self._strings ]
- ss.append((-1,'searcher_string:'))
+ ss = [(ns[0], ' %d: "%s"' % ns) for ns in self._strings]
+ ss.append((-1, 'searcher_string:'))
if self.eof_index >= 0:
- ss.append ((self.eof_index,' %d: EOF' % self.eof_index))
+ ss.append((self.eof_index, ' %d: EOF' % self.eof_index))
if self.timeout_index >= 0:
- ss.append ((self.timeout_index,' %d: TIMEOUT' % self.timeout_index))
+ ss.append((self.timeout_index,
+ ' %d: TIMEOUT' % self.timeout_index))
ss.sort()
ss = zip(*ss)[1]
return '\n'.join(ss)
@@ -1653,12 +1751,12 @@ class searcher_string (object):
# rescanning until we've read three more bytes.
#
# Sadly, I don't know enough about this interesting topic. /grahn
-
+
for index, s in self._strings:
if searchwindowsize is None:
# the match, if any, can only be in the fresh data,
# or at the very end of the old data
- offset = -(freshlen+len(s))
+ offset = -(freshlen + len(s))
else:
# better obey searchwindowsize
offset = -searchwindowsize
@@ -1673,10 +1771,12 @@ class searcher_string (object):
self.end = self.start + len(self.match)
return best_index
-class searcher_re (object):
+
+class searcher_re(object):
"""This is regular expression string search helper for the
- spawn.expect_any() method.
+ spawn.expect_any() method. This helper class is for powerful
+ pattern matching. For speed, see the helper class, searcher_string.
Attributes:
@@ -1701,7 +1801,7 @@ class searcher_re (object):
self.eof_index = -1
self.timeout_index = -1
self._searches = []
- for n, s in zip(range(len(patterns)), patterns):
+ for n, s in zip(list(range(len(patterns))), patterns):
if s is EOF:
self.eof_index = n
continue
@@ -1715,12 +1815,14 @@ class searcher_re (object):
"""This returns a human-readable string that represents the state of
the object."""
- ss = [ (n,' %d: re.compile("%s")' % (n,str(s.pattern))) for n,s in self._searches]
- ss.append((-1,'searcher_re:'))
+ ss = [(n, ' %d: re.compile("%s")' %
+ (n, str(s.pattern))) for n, s in self._searches]
+ ss.append((-1, 'searcher_re:'))
if self.eof_index >= 0:
- ss.append ((self.eof_index,' %d: EOF' % self.eof_index))
+ ss.append((self.eof_index, ' %d: EOF' % self.eof_index))
if self.timeout_index >= 0:
- ss.append ((self.timeout_index,' %d: TIMEOUT' % self.timeout_index))
+ ss.append((self.timeout_index, ' %d: TIMEOUT' %
+ self.timeout_index))
ss.sort()
ss = zip(*ss)[1]
return '\n'.join(ss)
@@ -1732,7 +1834,7 @@ class searcher_re (object):
'buffer' which have not been searched before.
See class spawn for the 'searchwindowsize' argument.
-
+
If there is a match this returns the index of that string, and sets
'start', 'end' and 'match'. Otherwise, returns -1."""
@@ -1743,7 +1845,7 @@ class searcher_re (object):
if searchwindowsize is None:
searchstart = 0
else:
- searchstart = max(0, len(buffer)-searchwindowsize)
+ searchstart = max(0, len(buffer) - searchwindowsize)
for index, s in self._searches:
match = s.search(buffer, searchstart)
if match is None:
@@ -1760,33 +1862,29 @@ class searcher_re (object):
self.end = self.match.end()
return best_index
-def which (filename):
+
+def which(filename):
"""This takes a given filename; tries to find it in the environment path;
then checks if it is executable. This returns the full path to the filename
if found and executable. Otherwise this returns None."""
- # Special case where filename already contains a path.
+ # Special case where filename contains an explicit path.
if os.path.dirname(filename) != '':
- if os.access (filename, os.X_OK):
+ if os.access(filename, os.X_OK):
return filename
-
- if not os.environ.has_key('PATH') or os.environ['PATH'] == '':
+ if 'PATH' not in os.environ or os.environ['PATH'] == '':
p = os.defpath
else:
p = os.environ['PATH']
-
- # Oddly enough this was the one line that made Pexpect
- # incompatible with Python 1.5.2.
- #pathlist = p.split (os.pathsep)
- pathlist = string.split (p, os.pathsep)
-
+ pathlist = string.split(p, os.pathsep)
for path in pathlist:
- f = os.path.join(path, filename)
- if os.access(f, os.X_OK):
- return f
+ ff = os.path.join(path, filename)
+ if os.access(ff, os.X_OK):
+ return ff
return None
+
def split_command_line(command_line):
"""This splits a command line into a list of arguments. It splits arguments
@@ -1802,21 +1900,26 @@ def split_command_line(command_line):
state_esc = 1
state_singlequote = 2
state_doublequote = 3
- state_whitespace = 4 # The state of consuming whitespace between commands.
+ # The state when consuming whitespace between commands.
+ state_whitespace = 4
state = state_basic
for c in command_line:
if state == state_basic or state == state_whitespace:
- if c == '\\': # Escape the next character
+ if c == '\\':
+ # Escape the next character
state = state_esc
- elif c == r"'": # Handle single quote
+ elif c == r"'":
+ # Handle single quote
state = state_singlequote
- elif c == r'"': # Handle double quote
+ elif c == r'"':
+ # Handle double quote
state = state_doublequote
elif c.isspace():
# Add arg to arg_list if we aren't in the middle of whitespace.
if state == state_whitespace:
- None # Do nothing.
+ # Do nothing.
+ None
else:
arg_list.append(arg)
arg = ''
@@ -1842,4 +1945,4 @@ def split_command_line(command_line):
arg_list.append(arg)
return arg_list
-# vi:ts=4:sw=4:expandtab:ft=python:
+# vi:set sr et ts=4 sw=4 ft=python :
diff --git a/third_party/pexpect/pxssh.py b/third_party/pexpect/pxssh.py
index d3f46ab..b1354b4 100644
--- a/third_party/pexpect/pxssh.py
+++ b/third_party/pexpect/pxssh.py
@@ -1,12 +1,29 @@
"""This class extends pexpect.spawn to specialize setting up SSH connections.
This adds methods for login, logout, and expecting the shell prompt.
-$Id: pxssh.py 487 2007-08-29 22:33:29Z noah $
+PEXPECT LICENSE
+
+ This license is approved by the OSI and FSF as GPL-compatible.
+ http://opensource.org/licenses/isc-license.txt
+
+ Copyright (c) 2012, Noah Spurrier <noah@noah.org>
+ PERMISSION TO USE, COPY, MODIFY, AND/OR DISTRIBUTE THIS SOFTWARE FOR ANY
+ PURPOSE WITH OR WITHOUT FEE IS HEREBY GRANTED, PROVIDED THAT THE ABOVE
+ COPYRIGHT NOTICE AND THIS PERMISSION NOTICE APPEAR IN ALL COPIES.
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
"""
from pexpect import *
import pexpect
import time
+import os
__all__ = ['ExceptionPxssh', 'pxssh']
@@ -30,10 +47,10 @@ class pxssh (spawn):
shells.
Example that runs a few commands on a remote server and prints the result::
-
+
import pxssh
import getpass
- try:
+ try:
s = pxssh.pxssh()
hostname = raw_input('hostname: ')
username = raw_input('username: ')
@@ -71,11 +88,12 @@ class pxssh (spawn):
"""
def __init__ (self, timeout=30, maxread=2000, searchwindowsize=None, logfile=None, cwd=None, env=None):
+
spawn.__init__(self, None, timeout=timeout, maxread=maxread, searchwindowsize=searchwindowsize, logfile=logfile, cwd=cwd, env=env)
self.name = '<pxssh>'
-
- #SUBTLE HACK ALERT! Note that the command to set the prompt uses a
+
+ #SUBTLE HACK ALERT! Note that the command that SETS 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
@@ -91,14 +109,18 @@ class pxssh (spawn):
# used to set shell command-line prompt to UNIQUE_PROMPT.
self.PROMPT_SET_SH = "PS1='[PEXPECT]\$ '"
self.PROMPT_SET_CSH = "set prompt='[PEXPECT]\$ '"
- self.SSH_OPTS = "-o'RSAAuthentication=no' -o 'PubkeyAuthentication=no'"
+ self.SSH_OPTS = ("-o'RSAAuthentication=no'"
+ + " -o 'PubkeyAuthentication=no'")
+# Disabling host key checking, makes you vulnerable to MITM attacks.
+# + " -o 'StrictHostKeyChecking=no'"
+# + " -o 'UserKnownHostsFile /dev/null' ")
# Disabling X11 forwarding gets rid of the annoying SSH_ASKPASS from
# displaying a GUI password dialog. I have not figured out how to
# disable only SSH_ASKPASS without also disabling X11 forwarding.
# Unsetting SSH_ASKPASS on the remote side doesn't disable it! Annoying!
#self.SSH_OPTS = "-x -o'RSAAuthentication=no' -o 'PubkeyAuthentication=no'"
self.force_password = False
- self.auto_prompt_reset = True
+ self.auto_prompt_reset = True
def levenshtein_distance(self, a,b):
@@ -120,18 +142,25 @@ class pxssh (spawn):
current[j] = min(add, delete, change)
return current[n]
- def synch_original_prompt (self):
+ def sync_original_prompt (self):
"""This attempts to find the prompt. Basically, press enter and record
the response; press enter again and record the response; if the two
- responses are similar then assume we are at the original prompt. """
+ responses are similar then assume we are at the original prompt. This
+ is a slow function. It can take over 10 seconds. """
# All of these timing pace values are magic.
# I came up with these based on what seemed reliable for
# connecting to a heavily loaded machine I have.
+ self.sendline()
+ time.sleep(0.1)
# If latency is worse than these values then this will fail.
- self.read_nonblocking(size=10000,timeout=1) # GAS: Clear out the cache before getting the prompt
+ try:
+ # Clear the buffer before getting the prompt.
+ self.read_nonblocking(size=10000,timeout=1)
+ except TIMEOUT:
+ pass
time.sleep(0.1)
self.sendline()
time.sleep(0.5)
@@ -154,7 +183,7 @@ class pxssh (spawn):
### TODO: This is getting messy and I'm pretty sure this isn't perfect.
### TODO: I need to draw a flow chart for this.
- def login (self,server,username,password='',terminal_type='ansi',original_prompt=r"[#$]",login_timeout=10,port=None,auto_prompt_reset=True):
+ def login (self,server,username,password='',terminal_type='ansi',original_prompt=r"[#$]",login_timeout=10,port=None,auto_prompt_reset=True,ssh_key=None):
"""This logs the user into the given server. It uses the
'original_prompt' to try to find the prompt right after login. When it
@@ -171,7 +200,7 @@ class pxssh (spawn):
to guess when we have reached the prompt. Then we hope for the best and
blindly try to reset the prompt to something more unique. If that fails
then login() raises an ExceptionPxssh exception.
-
+
In some situations it is not possible or desirable to reset the
original prompt. In this case, set 'auto_prompt_reset' to False to
inhibit setting the prompt to the UNIQUE_PROMPT. Remember that pxssh
@@ -184,6 +213,12 @@ class pxssh (spawn):
ssh_options = ssh_options + ' ' + self.SSH_OPTS
if port is not None:
ssh_options = ssh_options + ' -p %s'%(str(port))
+ if ssh_key is not None:
+ try:
+ os.path.isfile(ssh_key)
+ except:
+ raise ExceptionPxssh ('private ssh key does not exist')
+ ssh_options = ssh_options + ' -i %s' % (ssh_key)
cmd = "ssh %s -l %s %s" % (ssh_options, username, server)
# This does not distinguish between a remote server 'password' prompt
@@ -192,7 +227,7 @@ class pxssh (spawn):
i = self.expect(["(?i)are you sure you want to continue connecting", original_prompt, "(?i)(?:password)|(?:passphrase for key)", "(?i)permission denied", "(?i)terminal type", TIMEOUT, "(?i)connection closed by remote host"], timeout=login_timeout)
# First phase
- if i==0:
+ if i==0:
# New certificate -- always accept it.
# This is what you get if SSH does not have the remote host's
# public key stored in the 'known_hosts' cache.
@@ -210,14 +245,14 @@ class pxssh (spawn):
# This is weird. This should not happen twice in a row.
self.close()
raise ExceptionPxssh ('Weird error. Got "are you sure" prompt twice.')
- elif i==1: # can occur if you have a public key pair set to authenticate.
+ elif i==1: # can occur if you have a public key pair set to authenticate.
### TODO: May NOT be OK if expect() got tricked and matched a false prompt.
pass
elif i==2: # password prompt again
# 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.
+ # we didn't get the password right the first time.
self.close()
raise ExceptionPxssh ('password refused')
elif i==3: # permission denied -- password was bad.
@@ -237,10 +272,10 @@ class pxssh (spawn):
elif i==6: # Connection closed by remote host
self.close()
raise ExceptionPxssh ('connection closed')
- else: # Unexpected
+ else: # Unexpected
self.close()
raise ExceptionPxssh ('unexpected login response')
- if not self.synch_original_prompt():
+ if not self.sync_original_prompt():
self.close()
raise ExceptionPxssh ('could not synchronize with original prompt')
# We appear to be in.
@@ -263,20 +298,25 @@ class pxssh (spawn):
self.expect(EOF)
self.close()
- def prompt (self, timeout=20):
+ def prompt (self, timeout=-1):
"""This matches the shell prompt. This is little more than a short-cut
to the expect() method. This returns True if the shell prompt was
- matched. This returns False if there was a timeout. Note that if you
- called login() with auto_prompt_reset set to False then you should have
- manually set the PROMPT attribute to a regex pattern for matching the
- prompt. """
+ matched. This returns False if a timeout was raised. Note that if you
+ called login() with auto_prompt_reset set to False then before calling
+ prompt() you must set the PROMPT attribute to a regex that prompt()
+ will use for matching the prompt. Calling prompt() will erase the
+ contents of the 'before' attribute even if no prompt is ever matched.
+ If timeout is not given or it is set to -1 then self.timeout is used.
+ """
+ if timeout == -1:
+ timeout = self.timeout
i = self.expect([self.PROMPT, TIMEOUT], timeout=timeout)
if i==1:
return False
return True
-
+
def set_unique_prompt (self):
"""This sets the remote prompt to something more unique than # or $.
diff --git a/third_party/pexpect/screen.py b/third_party/pexpect/screen.py
index 13699f9..5c1c336 100644
--- a/third_party/pexpect/screen.py
+++ b/third_party/pexpect/screen.py
@@ -3,7 +3,23 @@ emulation. The screen representation and state is implemented in this class.
Most of the methods are inspired by ANSI screen control codes. The ANSI class
extends this class to add parsing of ANSI escape codes.
-$Id: screen.py 486 2007-07-13 01:04:16Z noah $
+PEXPECT LICENSE
+
+ This license is approved by the OSI and FSF as GPL-compatible.
+ http://opensource.org/licenses/isc-license.txt
+
+ Copyright (c) 2012, Noah Spurrier <noah@noah.org>
+ PERMISSION TO USE, COPY, MODIFY, AND/OR DISTRIBUTE THIS SOFTWARE FOR ANY
+ PURPOSE WITH OR WITHOUT FEE IS HEREBY GRANTED, PROVIDED THAT THE ABOVE
+ COPYRIGHT NOTICE AND THIS PERMISSION NOTICE APPEAR IN ALL COPIES.
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
"""
import copy
@@ -159,7 +175,7 @@ class screen:
r = constrain (r, 1, self.rows)
c = constrain (c, 1, self.cols)
- for ci in range (self.cols, c, -1):
+ for ci in range (self.cols, c, -1):
self.put_abs (r,ci, self.get_abs(r,ci-1))
self.put_abs (r,c,ch)
@@ -168,7 +184,7 @@ class screen:
self.insert_abs (self.cur_r, self.cur_c, ch)
def get_abs (self, r, c):
-
+
r = constrain (r, 1, self.rows)
c = constrain (c, 1, self.cols)
return self.w[r-1][c-1]