annotate pexpect.py @ 63:b342dc9b52eb

add document
author axmo
date Tue, 24 Feb 2009 17:59:45 +0900
parents
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
63
b342dc9b52eb add document
axmo
parents:
diff changeset
1 """Pexpect is a Python module for spawning child applications;
b342dc9b52eb add document
axmo
parents:
diff changeset
2 controlling them; and responding to expected patterns in their output.
b342dc9b52eb add document
axmo
parents:
diff changeset
3 Pexpect can be used for automating interactive applications such as
b342dc9b52eb add document
axmo
parents:
diff changeset
4 ssh, ftp, passwd, telnet, etc. It can be used to a automate setup scripts
b342dc9b52eb add document
axmo
parents:
diff changeset
5 for duplicating software package installations on different servers.
b342dc9b52eb add document
axmo
parents:
diff changeset
6 It can be used for automated software testing. Pexpect is in the spirit of
b342dc9b52eb add document
axmo
parents:
diff changeset
7 Don Libes' Expect, but Pexpect is pure Python. Other Expect-like
b342dc9b52eb add document
axmo
parents:
diff changeset
8 modules for Python require TCL and Expect or require C extensions to
b342dc9b52eb add document
axmo
parents:
diff changeset
9 be compiled. Pexpect does not use C, Expect, or TCL extensions. It
b342dc9b52eb add document
axmo
parents:
diff changeset
10 should work on any platform that supports the standard Python pty
b342dc9b52eb add document
axmo
parents:
diff changeset
11 module. The Pexpect interface focuses on ease of use so that simple
b342dc9b52eb add document
axmo
parents:
diff changeset
12 tasks are easy.
b342dc9b52eb add document
axmo
parents:
diff changeset
13
b342dc9b52eb add document
axmo
parents:
diff changeset
14 There are two main interfaces to Pexpect. You can call the function:
b342dc9b52eb add document
axmo
parents:
diff changeset
15 pexpect.run()
b342dc9b52eb add document
axmo
parents:
diff changeset
16 to execute a command and return the output.
b342dc9b52eb add document
axmo
parents:
diff changeset
17 Do no use this on interactive commands that expect input.
b342dc9b52eb add document
axmo
parents:
diff changeset
18 This is a handy replacment for os.system().
b342dc9b52eb add document
axmo
parents:
diff changeset
19 The more useful interface is the class:
b342dc9b52eb add document
axmo
parents:
diff changeset
20 pexpect.spawn()
b342dc9b52eb add document
axmo
parents:
diff changeset
21 This creates a spawn instance. This will start the command that you specify.
b342dc9b52eb add document
axmo
parents:
diff changeset
22 You can then interact with the child command through the spawn instance.
b342dc9b52eb add document
axmo
parents:
diff changeset
23 Most commands, including ssh, cannot tell that they are being run inside
b342dc9b52eb add document
axmo
parents:
diff changeset
24 of a script. This works even for commands that ask for passwords or
b342dc9b52eb add document
axmo
parents:
diff changeset
25 other input outside of the normal stdio streams.
b342dc9b52eb add document
axmo
parents:
diff changeset
26
b342dc9b52eb add document
axmo
parents:
diff changeset
27 Pexpect is Open Source, Free, and all that good stuff.
b342dc9b52eb add document
axmo
parents:
diff changeset
28 License: Python Software Foundation License
b342dc9b52eb add document
axmo
parents:
diff changeset
29 http://www.opensource.org/licenses/PythonSoftFoundation.html
b342dc9b52eb add document
axmo
parents:
diff changeset
30
b342dc9b52eb add document
axmo
parents:
diff changeset
31 Noah Spurrier
b342dc9b52eb add document
axmo
parents:
diff changeset
32 Richard Holden
b342dc9b52eb add document
axmo
parents:
diff changeset
33 Marco Molteni
b342dc9b52eb add document
axmo
parents:
diff changeset
34 Kimberley Burchett
b342dc9b52eb add document
axmo
parents:
diff changeset
35 Robert Stone
b342dc9b52eb add document
axmo
parents:
diff changeset
36 Mike Snitzer
b342dc9b52eb add document
axmo
parents:
diff changeset
37 Marti Raudsepp
b342dc9b52eb add document
axmo
parents:
diff changeset
38 Matt <matt (*) corvil.com>
b342dc9b52eb add document
axmo
parents:
diff changeset
39 Hartmut Goebel
b342dc9b52eb add document
axmo
parents:
diff changeset
40 Chad Schroeder
b342dc9b52eb add document
axmo
parents:
diff changeset
41 Erick Tryzelaar
b342dc9b52eb add document
axmo
parents:
diff changeset
42 Dave Kirby
b342dc9b52eb add document
axmo
parents:
diff changeset
43 Ids vander Molen
b342dc9b52eb add document
axmo
parents:
diff changeset
44 George Todd
b342dc9b52eb add document
axmo
parents:
diff changeset
45 Noel Taylor
b342dc9b52eb add document
axmo
parents:
diff changeset
46 Nicolas D. Cesar
b342dc9b52eb add document
axmo
parents:
diff changeset
47 (Let me know if I forgot anyone.)
b342dc9b52eb add document
axmo
parents:
diff changeset
48
b342dc9b52eb add document
axmo
parents:
diff changeset
49 $Revision: 1.1.1.1 $
b342dc9b52eb add document
axmo
parents:
diff changeset
50 $Date: 2006/04/01 06:03:29 $
b342dc9b52eb add document
axmo
parents:
diff changeset
51 """
b342dc9b52eb add document
axmo
parents:
diff changeset
52
b342dc9b52eb add document
axmo
parents:
diff changeset
53 try:
b342dc9b52eb add document
axmo
parents:
diff changeset
54 import os, sys, time
b342dc9b52eb add document
axmo
parents:
diff changeset
55 import select
b342dc9b52eb add document
axmo
parents:
diff changeset
56 import string
b342dc9b52eb add document
axmo
parents:
diff changeset
57 import re
b342dc9b52eb add document
axmo
parents:
diff changeset
58 import struct
b342dc9b52eb add document
axmo
parents:
diff changeset
59 import resource
b342dc9b52eb add document
axmo
parents:
diff changeset
60 import types
b342dc9b52eb add document
axmo
parents:
diff changeset
61 import pty
b342dc9b52eb add document
axmo
parents:
diff changeset
62 import tty
b342dc9b52eb add document
axmo
parents:
diff changeset
63 import termios
b342dc9b52eb add document
axmo
parents:
diff changeset
64 import fcntl
b342dc9b52eb add document
axmo
parents:
diff changeset
65 import errno
b342dc9b52eb add document
axmo
parents:
diff changeset
66 import traceback
b342dc9b52eb add document
axmo
parents:
diff changeset
67 import signal
b342dc9b52eb add document
axmo
parents:
diff changeset
68 except ImportError, e:
b342dc9b52eb add document
axmo
parents:
diff changeset
69 raise ImportError (str(e) + """
b342dc9b52eb add document
axmo
parents:
diff changeset
70 A critical module was not found. Probably this operating system does not support it.
b342dc9b52eb add document
axmo
parents:
diff changeset
71 Pexpect is intended for UNIX-like operating systems.""")
b342dc9b52eb add document
axmo
parents:
diff changeset
72
b342dc9b52eb add document
axmo
parents:
diff changeset
73 __version__ = '2.0'
b342dc9b52eb add document
axmo
parents:
diff changeset
74 __revision__ = '$Revision: 1.1.1.1 $'
b342dc9b52eb add document
axmo
parents:
diff changeset
75 __all__ = ['ExceptionPexpect', 'EOF', 'TIMEOUT', 'spawn', 'run', 'which', 'split_command_line',
b342dc9b52eb add document
axmo
parents:
diff changeset
76 '__version__', '__revision__']
b342dc9b52eb add document
axmo
parents:
diff changeset
77
b342dc9b52eb add document
axmo
parents:
diff changeset
78 # Exception classes used by this module.
b342dc9b52eb add document
axmo
parents:
diff changeset
79 class ExceptionPexpect(Exception):
b342dc9b52eb add document
axmo
parents:
diff changeset
80 """Base class for all exceptions raised by this module.
b342dc9b52eb add document
axmo
parents:
diff changeset
81 """
b342dc9b52eb add document
axmo
parents:
diff changeset
82 def __init__(self, value):
b342dc9b52eb add document
axmo
parents:
diff changeset
83 self.value = value
b342dc9b52eb add document
axmo
parents:
diff changeset
84 def __str__(self):
b342dc9b52eb add document
axmo
parents:
diff changeset
85 return str(self.value)
b342dc9b52eb add document
axmo
parents:
diff changeset
86 def get_trace(self):
b342dc9b52eb add document
axmo
parents:
diff changeset
87 """This returns an abbreviated stack trace with lines that only concern the caller.
b342dc9b52eb add document
axmo
parents:
diff changeset
88 In other words, the stack trace inside the Pexpect module is not included.
b342dc9b52eb add document
axmo
parents:
diff changeset
89 """
b342dc9b52eb add document
axmo
parents:
diff changeset
90 tblist = traceback.extract_tb(sys.exc_info()[2])
b342dc9b52eb add document
axmo
parents:
diff changeset
91 tblist = filter(self.__filter_not_pexpect, tblist)
b342dc9b52eb add document
axmo
parents:
diff changeset
92 tblist = traceback.format_list(tblist)
b342dc9b52eb add document
axmo
parents:
diff changeset
93 return ''.join(tblist)
b342dc9b52eb add document
axmo
parents:
diff changeset
94 def __filter_not_pexpect(self, trace_list_item):
b342dc9b52eb add document
axmo
parents:
diff changeset
95 if trace_list_item[0].find('pexpect.py') == -1:
b342dc9b52eb add document
axmo
parents:
diff changeset
96 return 1
b342dc9b52eb add document
axmo
parents:
diff changeset
97 else:
b342dc9b52eb add document
axmo
parents:
diff changeset
98 return 0
b342dc9b52eb add document
axmo
parents:
diff changeset
99 class EOF(ExceptionPexpect):
b342dc9b52eb add document
axmo
parents:
diff changeset
100 """Raised when EOF is read from a child.
b342dc9b52eb add document
axmo
parents:
diff changeset
101 """
b342dc9b52eb add document
axmo
parents:
diff changeset
102 class TIMEOUT(ExceptionPexpect):
b342dc9b52eb add document
axmo
parents:
diff changeset
103 """Raised when a read time exceeds the timeout.
b342dc9b52eb add document
axmo
parents:
diff changeset
104 """
b342dc9b52eb add document
axmo
parents:
diff changeset
105 ##class TIMEOUT_PATTERN(TIMEOUT):
b342dc9b52eb add document
axmo
parents:
diff changeset
106 ## """Raised when the pattern match time exceeds the timeout.
b342dc9b52eb add document
axmo
parents:
diff changeset
107 ## This is different than a read TIMEOUT because the child process may
b342dc9b52eb add document
axmo
parents:
diff changeset
108 ## give output, thus never give a TIMEOUT, but the output
b342dc9b52eb add document
axmo
parents:
diff changeset
109 ## may never match a pattern.
b342dc9b52eb add document
axmo
parents:
diff changeset
110 ## """
b342dc9b52eb add document
axmo
parents:
diff changeset
111 ##class MAXBUFFER(ExceptionPexpect):
b342dc9b52eb add document
axmo
parents:
diff changeset
112 ## """Raised when a scan buffer fills before matching an expected pattern."""
b342dc9b52eb add document
axmo
parents:
diff changeset
113
b342dc9b52eb add document
axmo
parents:
diff changeset
114 def run (command, timeout=-1, withexitstatus=0, events=None, extra_args=None):
b342dc9b52eb add document
axmo
parents:
diff changeset
115 """This function runs the given command; waits for it to finish;
b342dc9b52eb add document
axmo
parents:
diff changeset
116 then returns all output as a string. STDERR is included in output.
b342dc9b52eb add document
axmo
parents:
diff changeset
117 If the full path to the command is not given then the path is searched.
b342dc9b52eb add document
axmo
parents:
diff changeset
118
b342dc9b52eb add document
axmo
parents:
diff changeset
119 Note that lines are terminated by CR/LF (\\r\\n) combination
b342dc9b52eb add document
axmo
parents:
diff changeset
120 even on UNIX-like systems because this is the standard for pseudo ttys.
b342dc9b52eb add document
axmo
parents:
diff changeset
121 If you set withexitstatus to true, then run will return a tuple of
b342dc9b52eb add document
axmo
parents:
diff changeset
122 (command_output, exitstatus). If withexitstatus is false then this
b342dc9b52eb add document
axmo
parents:
diff changeset
123 returns just command_output.
b342dc9b52eb add document
axmo
parents:
diff changeset
124
b342dc9b52eb add document
axmo
parents:
diff changeset
125 Examples:
b342dc9b52eb add document
axmo
parents:
diff changeset
126 Start the apache daemon on the local machine:
b342dc9b52eb add document
axmo
parents:
diff changeset
127 from pexpect import *
b342dc9b52eb add document
axmo
parents:
diff changeset
128 run ("/usr/local/apache/bin/apachectl start")
b342dc9b52eb add document
axmo
parents:
diff changeset
129 Check in a file using SVN:
b342dc9b52eb add document
axmo
parents:
diff changeset
130 from pexpect import *
b342dc9b52eb add document
axmo
parents:
diff changeset
131 run ("svn ci -m 'automatic commit' my_file.py")
b342dc9b52eb add document
axmo
parents:
diff changeset
132 Run a command and capture exit status:
b342dc9b52eb add document
axmo
parents:
diff changeset
133 from pexpect import *
b342dc9b52eb add document
axmo
parents:
diff changeset
134 (command_output, exitstatus) = run ('ls -l /bin', withexitstatus=1)
b342dc9b52eb add document
axmo
parents:
diff changeset
135
b342dc9b52eb add document
axmo
parents:
diff changeset
136 Tricky Examples:
b342dc9b52eb add document
axmo
parents:
diff changeset
137 The following will run SSH and execute 'ls -l' on the remote machine.
b342dc9b52eb add document
axmo
parents:
diff changeset
138 The password 'secret' will be sent if the '(?i)password' pattern is ever seen.
b342dc9b52eb add document
axmo
parents:
diff changeset
139 run ("ssh username@machine.example.com 'ls -l'", events={'(?i)password':'secret\n'})
b342dc9b52eb add document
axmo
parents:
diff changeset
140
b342dc9b52eb add document
axmo
parents:
diff changeset
141 This will start mencoder to rip a video from DVD. This will also display
b342dc9b52eb add document
axmo
parents:
diff changeset
142 progress ticks every 5 seconds as it runs.
b342dc9b52eb add document
axmo
parents:
diff changeset
143 from pexpect import *
b342dc9b52eb add document
axmo
parents:
diff changeset
144 def print_ticks(d):
b342dc9b52eb add document
axmo
parents:
diff changeset
145 print d['event_count'],
b342dc9b52eb add document
axmo
parents:
diff changeset
146 run ("mencoder dvd://1 -o video.avi -oac copy -ovc copy", events={TIMEOUT:print_ticks}, timeout=5)
b342dc9b52eb add document
axmo
parents:
diff changeset
147
b342dc9b52eb add document
axmo
parents:
diff changeset
148 The 'events' argument should be a dictionary of patterns and responses.
b342dc9b52eb add document
axmo
parents:
diff changeset
149 Whenever one of the patterns is seen in the command out
b342dc9b52eb add document
axmo
parents:
diff changeset
150 run() will send the associated response string. Note that you should
b342dc9b52eb add document
axmo
parents:
diff changeset
151 put newlines in your string if Enter is necessary.
b342dc9b52eb add document
axmo
parents:
diff changeset
152 The responses may also contain callback functions.
b342dc9b52eb add document
axmo
parents:
diff changeset
153 Any callback is function that takes a dictionary as an argument.
b342dc9b52eb add document
axmo
parents:
diff changeset
154 The dictionary contains all the locals from the run() function, so
b342dc9b52eb add document
axmo
parents:
diff changeset
155 you can access the child spawn object or any other variable defined
b342dc9b52eb add document
axmo
parents:
diff changeset
156 in run() (event_count, child, and extra_args are the most useful).
b342dc9b52eb add document
axmo
parents:
diff changeset
157 A callback may return True to stop the current run process otherwise
b342dc9b52eb add document
axmo
parents:
diff changeset
158 run() continues until the next event.
b342dc9b52eb add document
axmo
parents:
diff changeset
159 A callback may also return a string which will be sent to the child.
b342dc9b52eb add document
axmo
parents:
diff changeset
160 'extra_args' is not used by directly run(). It provides a way to pass data to
b342dc9b52eb add document
axmo
parents:
diff changeset
161 a callback function through run() through the locals dictionary passed to a callback.
b342dc9b52eb add document
axmo
parents:
diff changeset
162 """
b342dc9b52eb add document
axmo
parents:
diff changeset
163 if timeout == -1:
b342dc9b52eb add document
axmo
parents:
diff changeset
164 child = spawn(command, maxread=2000)
b342dc9b52eb add document
axmo
parents:
diff changeset
165 else:
b342dc9b52eb add document
axmo
parents:
diff changeset
166 child = spawn(command, timeout=timeout, maxread=2000)
b342dc9b52eb add document
axmo
parents:
diff changeset
167 if events is not None:
b342dc9b52eb add document
axmo
parents:
diff changeset
168 patterns = events.keys()
b342dc9b52eb add document
axmo
parents:
diff changeset
169 responses = events.values()
b342dc9b52eb add document
axmo
parents:
diff changeset
170 else:
b342dc9b52eb add document
axmo
parents:
diff changeset
171 patterns=None # We assume that EOF or TIMEOUT will save us.
b342dc9b52eb add document
axmo
parents:
diff changeset
172 responses=None
b342dc9b52eb add document
axmo
parents:
diff changeset
173 child_result_list = []
b342dc9b52eb add document
axmo
parents:
diff changeset
174 event_count = 0
b342dc9b52eb add document
axmo
parents:
diff changeset
175 while 1:
b342dc9b52eb add document
axmo
parents:
diff changeset
176 try:
b342dc9b52eb add document
axmo
parents:
diff changeset
177 index = child.expect (patterns)
b342dc9b52eb add document
axmo
parents:
diff changeset
178 if type(child.after) is types.StringType:
b342dc9b52eb add document
axmo
parents:
diff changeset
179 child_result_list.append(child.before + child.after)
b342dc9b52eb add document
axmo
parents:
diff changeset
180 else: # child.after may have been a TIMEOUT or EOF, so don't cat those.
b342dc9b52eb add document
axmo
parents:
diff changeset
181 child_result_list.append(child.before)
b342dc9b52eb add document
axmo
parents:
diff changeset
182 if type(responses[index]) is types.StringType:
b342dc9b52eb add document
axmo
parents:
diff changeset
183 child.send(responses[index])
b342dc9b52eb add document
axmo
parents:
diff changeset
184 elif type(responses[index]) is types.FunctionType:
b342dc9b52eb add document
axmo
parents:
diff changeset
185 callback_result = responses[index](locals())
b342dc9b52eb add document
axmo
parents:
diff changeset
186 sys.stdout.flush()
b342dc9b52eb add document
axmo
parents:
diff changeset
187 if type(callback_result) is types.StringType:
b342dc9b52eb add document
axmo
parents:
diff changeset
188 child.send(callback_result)
b342dc9b52eb add document
axmo
parents:
diff changeset
189 elif callback_result:
b342dc9b52eb add document
axmo
parents:
diff changeset
190 break
b342dc9b52eb add document
axmo
parents:
diff changeset
191 else:
b342dc9b52eb add document
axmo
parents:
diff changeset
192 raise TypeError ('The callback must be a string or function type.')
b342dc9b52eb add document
axmo
parents:
diff changeset
193 event_count = event_count + 1
b342dc9b52eb add document
axmo
parents:
diff changeset
194 except TIMEOUT, e:
b342dc9b52eb add document
axmo
parents:
diff changeset
195 child_result_list.append(child.before)
b342dc9b52eb add document
axmo
parents:
diff changeset
196 break
b342dc9b52eb add document
axmo
parents:
diff changeset
197 except EOF, e:
b342dc9b52eb add document
axmo
parents:
diff changeset
198 child_result_list.append(child.before)
b342dc9b52eb add document
axmo
parents:
diff changeset
199 break
b342dc9b52eb add document
axmo
parents:
diff changeset
200 child_result = ''.join(child_result_list)
b342dc9b52eb add document
axmo
parents:
diff changeset
201 if withexitstatus:
b342dc9b52eb add document
axmo
parents:
diff changeset
202 child.close()
b342dc9b52eb add document
axmo
parents:
diff changeset
203 return (child_result, child.exitstatus)
b342dc9b52eb add document
axmo
parents:
diff changeset
204 else:
b342dc9b52eb add document
axmo
parents:
diff changeset
205 return child_result
b342dc9b52eb add document
axmo
parents:
diff changeset
206
b342dc9b52eb add document
axmo
parents:
diff changeset
207 class spawn:
b342dc9b52eb add document
axmo
parents:
diff changeset
208 """This is the main class interface for Pexpect.
b342dc9b52eb add document
axmo
parents:
diff changeset
209 Use this class to start and control child applications.
b342dc9b52eb add document
axmo
parents:
diff changeset
210 """
b342dc9b52eb add document
axmo
parents:
diff changeset
211
b342dc9b52eb add document
axmo
parents:
diff changeset
212 def __init__(self, command, args=[], timeout=30, maxread=2000, searchwindowsize=None, logfile=None):
b342dc9b52eb add document
axmo
parents:
diff changeset
213 """This is the constructor. The command parameter may be a string
b342dc9b52eb add document
axmo
parents:
diff changeset
214 that includes a command and any arguments to the command. For example:
b342dc9b52eb add document
axmo
parents:
diff changeset
215 p = pexpect.spawn ('/usr/bin/ftp')
b342dc9b52eb add document
axmo
parents:
diff changeset
216 p = pexpect.spawn ('/usr/bin/ssh user@example.com')
b342dc9b52eb add document
axmo
parents:
diff changeset
217 p = pexpect.spawn ('ls -latr /tmp')
b342dc9b52eb add document
axmo
parents:
diff changeset
218 You may also construct it with a list of arguments like so:
b342dc9b52eb add document
axmo
parents:
diff changeset
219 p = pexpect.spawn ('/usr/bin/ftp', [])
b342dc9b52eb add document
axmo
parents:
diff changeset
220 p = pexpect.spawn ('/usr/bin/ssh', ['user@example.com'])
b342dc9b52eb add document
axmo
parents:
diff changeset
221 p = pexpect.spawn ('ls', ['-latr', '/tmp'])
b342dc9b52eb add document
axmo
parents:
diff changeset
222 After this the child application will be created and
b342dc9b52eb add document
axmo
parents:
diff changeset
223 will be ready to talk to. For normal use, see expect() and
b342dc9b52eb add document
axmo
parents:
diff changeset
224 send() and sendline().
b342dc9b52eb add document
axmo
parents:
diff changeset
225
b342dc9b52eb add document
axmo
parents:
diff changeset
226 The maxread attribute sets the read buffer size.
b342dc9b52eb add document
axmo
parents:
diff changeset
227 This is maximum number of bytes that Pexpect will try to read from a TTY at one time.
b342dc9b52eb add document
axmo
parents:
diff changeset
228 The default buffer size is 1 (unbuffered). Setting this value higher
b342dc9b52eb add document
axmo
parents:
diff changeset
229 will help performance in cases where large amounts of output are read back from the child.
b342dc9b52eb add document
axmo
parents:
diff changeset
230 This feature is useful in conjunction with searchwindowsize.
b342dc9b52eb add document
axmo
parents:
diff changeset
231
b342dc9b52eb add document
axmo
parents:
diff changeset
232 The searchwindowsize attribute sets the how far back in
b342dc9b52eb add document
axmo
parents:
diff changeset
233 the incomming seach buffer Pexpect will search for pattern matches.
b342dc9b52eb add document
axmo
parents:
diff changeset
234 Every time Pexpect reads some data from the child it will append the data to
b342dc9b52eb add document
axmo
parents:
diff changeset
235 the incomming buffer. The default is to search from the beginning of the
b342dc9b52eb add document
axmo
parents:
diff changeset
236 imcomming buffer each time new data is read from the child.
b342dc9b52eb add document
axmo
parents:
diff changeset
237 But this is very inefficient if you are running a command that
b342dc9b52eb add document
axmo
parents:
diff changeset
238 generates a large amount of data where you want to match
b342dc9b52eb add document
axmo
parents:
diff changeset
239 The searchwindowsize does not effect the size of the incomming data buffer.
b342dc9b52eb add document
axmo
parents:
diff changeset
240 You will still have access to the full buffer after expect() returns.
b342dc9b52eb add document
axmo
parents:
diff changeset
241
b342dc9b52eb add document
axmo
parents:
diff changeset
242 The logfile member turns on or off logging.
b342dc9b52eb add document
axmo
parents:
diff changeset
243 All input and output will be copied to the given file object.
b342dc9b52eb add document
axmo
parents:
diff changeset
244 Set logfile to None to stop logging. This is the default.
b342dc9b52eb add document
axmo
parents:
diff changeset
245 Set logfile to sys.stdout to echo everything to standard output.
b342dc9b52eb add document
axmo
parents:
diff changeset
246 The logfile is flushed after each write.
b342dc9b52eb add document
axmo
parents:
diff changeset
247 Example 1:
b342dc9b52eb add document
axmo
parents:
diff changeset
248 child = pexpect.spawn('some_command')
b342dc9b52eb add document
axmo
parents:
diff changeset
249 fout = file('mylog.txt','w')
b342dc9b52eb add document
axmo
parents:
diff changeset
250 child.logfile = fout
b342dc9b52eb add document
axmo
parents:
diff changeset
251 Example 2:
b342dc9b52eb add document
axmo
parents:
diff changeset
252 child = pexpect.spawn('some_command')
b342dc9b52eb add document
axmo
parents:
diff changeset
253 child.logfile = sys.stdout
b342dc9b52eb add document
axmo
parents:
diff changeset
254
b342dc9b52eb add document
axmo
parents:
diff changeset
255 The delaybeforesend helps overcome weird behavior that many users were experiencing.
b342dc9b52eb add document
axmo
parents:
diff changeset
256 The typical problem was that a user would expect() a "Password:" prompt and
b342dc9b52eb add document
axmo
parents:
diff changeset
257 then immediately call sendline() to send the password. The user would then
b342dc9b52eb add document
axmo
parents:
diff changeset
258 see that their password was echoed back to them. Of course, passwords don't
b342dc9b52eb add document
axmo
parents:
diff changeset
259 normally echo. The problem is caused by the fact that most applications
b342dc9b52eb add document
axmo
parents:
diff changeset
260 print out the "Password" prompt and then turn off stdin echo, but if you
b342dc9b52eb add document
axmo
parents:
diff changeset
261 send your password before the application turned off echo, then you get
b342dc9b52eb add document
axmo
parents:
diff changeset
262 your password echoed. Normally this wouldn't be a problem when interacting
b342dc9b52eb add document
axmo
parents:
diff changeset
263 with a human at a real heyboard. If you introduce a slight delay just before
b342dc9b52eb add document
axmo
parents:
diff changeset
264 writing then this seems to clear up the problem. This was such a common problem
b342dc9b52eb add document
axmo
parents:
diff changeset
265 for many users that I decided that the default pexpect behavior
b342dc9b52eb add document
axmo
parents:
diff changeset
266 should be to sleep just before writing to the child application.
b342dc9b52eb add document
axmo
parents:
diff changeset
267 1/10th of a second (100 ms) seems to be enough to clear up the problem.
b342dc9b52eb add document
axmo
parents:
diff changeset
268 You can set delaybeforesend to 0 to return to the old behavior.
b342dc9b52eb add document
axmo
parents:
diff changeset
269
b342dc9b52eb add document
axmo
parents:
diff changeset
270 Note that spawn is clever about finding commands on your path.
b342dc9b52eb add document
axmo
parents:
diff changeset
271 It uses the same logic that "which" uses to find executables.
b342dc9b52eb add document
axmo
parents:
diff changeset
272
b342dc9b52eb add document
axmo
parents:
diff changeset
273 If you wish to get the exit status of the child you must call
b342dc9b52eb add document
axmo
parents:
diff changeset
274 the close() method. The exit or signal status of the child will be
b342dc9b52eb add document
axmo
parents:
diff changeset
275 stored in self.exitstatus or self.signalstatus.
b342dc9b52eb add document
axmo
parents:
diff changeset
276 If the child exited normally then exitstatus will store the exit return code and
b342dc9b52eb add document
axmo
parents:
diff changeset
277 signalstatus will be None.
b342dc9b52eb add document
axmo
parents:
diff changeset
278 If the child was terminated abnormally with a signal then signalstatus will store
b342dc9b52eb add document
axmo
parents:
diff changeset
279 the signal value and exitstatus will be None.
b342dc9b52eb add document
axmo
parents:
diff changeset
280 If you need more detail you can also read the self.status member which stores
b342dc9b52eb add document
axmo
parents:
diff changeset
281 the status returned by os.waitpid. You can interpret this using
b342dc9b52eb add document
axmo
parents:
diff changeset
282 os.WIFEXITED/os.WEXITSTATUS or os.WIFSIGNALED/os.TERMSIG.
b342dc9b52eb add document
axmo
parents:
diff changeset
283 """
b342dc9b52eb add document
axmo
parents:
diff changeset
284 self.STDIN_FILENO = pty.STDIN_FILENO
b342dc9b52eb add document
axmo
parents:
diff changeset
285 self.STDOUT_FILENO = pty.STDOUT_FILENO
b342dc9b52eb add document
axmo
parents:
diff changeset
286 self.STDERR_FILENO = pty.STDERR_FILENO
b342dc9b52eb add document
axmo
parents:
diff changeset
287 self.stdin = sys.stdin
b342dc9b52eb add document
axmo
parents:
diff changeset
288 self.stdout = sys.stdout
b342dc9b52eb add document
axmo
parents:
diff changeset
289 self.stderr = sys.stderr
b342dc9b52eb add document
axmo
parents:
diff changeset
290
b342dc9b52eb add document
axmo
parents:
diff changeset
291 self.patterns = None
b342dc9b52eb add document
axmo
parents:
diff changeset
292 self.before = None
b342dc9b52eb add document
axmo
parents:
diff changeset
293 self.after = None
b342dc9b52eb add document
axmo
parents:
diff changeset
294 self.match = None
b342dc9b52eb add document
axmo
parents:
diff changeset
295 self.match_index = None
b342dc9b52eb add document
axmo
parents:
diff changeset
296 self.terminated = 1
b342dc9b52eb add document
axmo
parents:
diff changeset
297 self.exitstatus = None
b342dc9b52eb add document
axmo
parents:
diff changeset
298 self.signalstatus = None
b342dc9b52eb add document
axmo
parents:
diff changeset
299 self.status = None
b342dc9b52eb add document
axmo
parents:
diff changeset
300 self.flag_eof = 0
b342dc9b52eb add document
axmo
parents:
diff changeset
301 self.pid = None
b342dc9b52eb add document
axmo
parents:
diff changeset
302 self.child_fd = -1 # initially closed
b342dc9b52eb add document
axmo
parents:
diff changeset
303 self.timeout = timeout
b342dc9b52eb add document
axmo
parents:
diff changeset
304 self.delimiter = EOF
b342dc9b52eb add document
axmo
parents:
diff changeset
305 self.logfile = logfile
b342dc9b52eb add document
axmo
parents:
diff changeset
306 self.maxread = maxread # Max bytes to read at one time into buffer.
b342dc9b52eb add document
axmo
parents:
diff changeset
307 self.buffer = '' # This is the read buffer. See maxread.
b342dc9b52eb add document
axmo
parents:
diff changeset
308 self.searchwindowsize = searchwindowsize # Anything before searchwindowsize point is preserved, but not searched.
b342dc9b52eb add document
axmo
parents:
diff changeset
309 self.delaybeforesend = 0.1 # Sets sleep time used just before sending data to child.
b342dc9b52eb add document
axmo
parents:
diff changeset
310 self.softspace = 0 # File-like object.
b342dc9b52eb add document
axmo
parents:
diff changeset
311 self.name = '<' + repr(self) + '>' # File-like object.
b342dc9b52eb add document
axmo
parents:
diff changeset
312 self.encoding = None # File-like object.
b342dc9b52eb add document
axmo
parents:
diff changeset
313 self.closed = 1 # File-like object.
b342dc9b52eb add document
axmo
parents:
diff changeset
314
b342dc9b52eb add document
axmo
parents:
diff changeset
315 if type (args) != type([]):
b342dc9b52eb add document
axmo
parents:
diff changeset
316 raise TypeError ('The second argument, args, must be a list.')
b342dc9b52eb add document
axmo
parents:
diff changeset
317
b342dc9b52eb add document
axmo
parents:
diff changeset
318 if args == []:
b342dc9b52eb add document
axmo
parents:
diff changeset
319 self.args = split_command_line(command)
b342dc9b52eb add document
axmo
parents:
diff changeset
320 self.command = self.args[0]
b342dc9b52eb add document
axmo
parents:
diff changeset
321 else:
b342dc9b52eb add document
axmo
parents:
diff changeset
322 self.args = args[:] # work with a copy
b342dc9b52eb add document
axmo
parents:
diff changeset
323 self.args.insert (0, command)
b342dc9b52eb add document
axmo
parents:
diff changeset
324 self.command = command
b342dc9b52eb add document
axmo
parents:
diff changeset
325
b342dc9b52eb add document
axmo
parents:
diff changeset
326 command_with_path = which(self.command)
b342dc9b52eb add document
axmo
parents:
diff changeset
327 if command_with_path == None:
b342dc9b52eb add document
axmo
parents:
diff changeset
328 raise ExceptionPexpect ('The command was not found or was not executable: %s.' % self.command)
b342dc9b52eb add document
axmo
parents:
diff changeset
329 self.command = command_with_path
b342dc9b52eb add document
axmo
parents:
diff changeset
330 self.args[0] = self.command
b342dc9b52eb add document
axmo
parents:
diff changeset
331
b342dc9b52eb add document
axmo
parents:
diff changeset
332 self.name = '<' + ' '.join (self.args) + '>'
b342dc9b52eb add document
axmo
parents:
diff changeset
333 self.__spawn()
b342dc9b52eb add document
axmo
parents:
diff changeset
334
b342dc9b52eb add document
axmo
parents:
diff changeset
335 def __del__(self):
b342dc9b52eb add document
axmo
parents:
diff changeset
336 """This makes sure that no system resources are left open.
b342dc9b52eb add document
axmo
parents:
diff changeset
337 Python only garbage collects Python objects. OS file descriptors
b342dc9b52eb add document
axmo
parents:
diff changeset
338 are not Python objects, so they must be handled explicitly.
b342dc9b52eb add document
axmo
parents:
diff changeset
339 If the child file descriptor was opened outside of this class
b342dc9b52eb add document
axmo
parents:
diff changeset
340 (passed to the constructor) then this does not close it.
b342dc9b52eb add document
axmo
parents:
diff changeset
341 """
b342dc9b52eb add document
axmo
parents:
diff changeset
342 if self.closed:
b342dc9b52eb add document
axmo
parents:
diff changeset
343 return
b342dc9b52eb add document
axmo
parents:
diff changeset
344 self.close()
b342dc9b52eb add document
axmo
parents:
diff changeset
345
b342dc9b52eb add document
axmo
parents:
diff changeset
346 def __str__(self):
b342dc9b52eb add document
axmo
parents:
diff changeset
347 """This returns the current state of the pexpect object as a string.
b342dc9b52eb add document
axmo
parents:
diff changeset
348 """
b342dc9b52eb add document
axmo
parents:
diff changeset
349 s = []
b342dc9b52eb add document
axmo
parents:
diff changeset
350 s.append(repr(self))
b342dc9b52eb add document
axmo
parents:
diff changeset
351 s.append('version: ' + __version__ + ' (' + __revision__ + ')')
b342dc9b52eb add document
axmo
parents:
diff changeset
352 s.append('command: ' + str(self.command))
b342dc9b52eb add document
axmo
parents:
diff changeset
353 s.append('args: ' + str(self.args))
b342dc9b52eb add document
axmo
parents:
diff changeset
354 if self.patterns is None:
b342dc9b52eb add document
axmo
parents:
diff changeset
355 s.append('patterns: None')
b342dc9b52eb add document
axmo
parents:
diff changeset
356 else:
b342dc9b52eb add document
axmo
parents:
diff changeset
357 s.append('patterns:')
b342dc9b52eb add document
axmo
parents:
diff changeset
358 for p in self.patterns:
b342dc9b52eb add document
axmo
parents:
diff changeset
359 if type(p) is type(re.compile('')):
b342dc9b52eb add document
axmo
parents:
diff changeset
360 s.append(' ' + str(p.pattern))
b342dc9b52eb add document
axmo
parents:
diff changeset
361 else:
b342dc9b52eb add document
axmo
parents:
diff changeset
362 s.append(' ' + str(p))
b342dc9b52eb add document
axmo
parents:
diff changeset
363 s.append('buffer (last 100 chars): ' + str(self.buffer)[-100:])
b342dc9b52eb add document
axmo
parents:
diff changeset
364 s.append('before (last 100 chars): ' + str(self.before)[-100:])
b342dc9b52eb add document
axmo
parents:
diff changeset
365 s.append('after: ' + str(self.after))
b342dc9b52eb add document
axmo
parents:
diff changeset
366 s.append('match: ' + str(self.match))
b342dc9b52eb add document
axmo
parents:
diff changeset
367 s.append('match_index: ' + str(self.match_index))
b342dc9b52eb add document
axmo
parents:
diff changeset
368 s.append('exitstatus: ' + str(self.exitstatus))
b342dc9b52eb add document
axmo
parents:
diff changeset
369 s.append('flag_eof: ' + str(self.flag_eof))
b342dc9b52eb add document
axmo
parents:
diff changeset
370 s.append('pid: ' + str(self.pid))
b342dc9b52eb add document
axmo
parents:
diff changeset
371 s.append('child_fd: ' + str(self.child_fd))
b342dc9b52eb add document
axmo
parents:
diff changeset
372 s.append('timeout: ' + str(self.timeout))
b342dc9b52eb add document
axmo
parents:
diff changeset
373 s.append('delimiter: ' + str(self.delimiter))
b342dc9b52eb add document
axmo
parents:
diff changeset
374 s.append('logfile: ' + str(self.logfile))
b342dc9b52eb add document
axmo
parents:
diff changeset
375 s.append('maxread: ' + str(self.maxread))
b342dc9b52eb add document
axmo
parents:
diff changeset
376 s.append('searchwindowsize: ' + str(self.searchwindowsize))
b342dc9b52eb add document
axmo
parents:
diff changeset
377 s.append('delaybeforesend: ' + str(self.delaybeforesend))
b342dc9b52eb add document
axmo
parents:
diff changeset
378 return '\n'.join(s)
b342dc9b52eb add document
axmo
parents:
diff changeset
379
b342dc9b52eb add document
axmo
parents:
diff changeset
380 def __spawn(self):
b342dc9b52eb add document
axmo
parents:
diff changeset
381 """This starts the given command in a child process.
b342dc9b52eb add document
axmo
parents:
diff changeset
382 This does all the fork/exec type of stuff for a pty.
b342dc9b52eb add document
axmo
parents:
diff changeset
383 This is called by __init__.
b342dc9b52eb add document
axmo
parents:
diff changeset
384 """
b342dc9b52eb add document
axmo
parents:
diff changeset
385 # The pid and child_fd of this object get set by this method.
b342dc9b52eb add document
axmo
parents:
diff changeset
386 # Note that it is difficult for this method to fail.
b342dc9b52eb add document
axmo
parents:
diff changeset
387 # You cannot detect if the child process cannot start.
b342dc9b52eb add document
axmo
parents:
diff changeset
388 # So the only way you can tell if the child process started
b342dc9b52eb add document
axmo
parents:
diff changeset
389 # or not is to try to read from the file descriptor. If you get
b342dc9b52eb add document
axmo
parents:
diff changeset
390 # EOF immediately then it means that the child is already dead.
b342dc9b52eb add document
axmo
parents:
diff changeset
391 # That may not necessarily be bad because you may haved spawned a child
b342dc9b52eb add document
axmo
parents:
diff changeset
392 # that performs some task; creates no stdout output; and then dies.
b342dc9b52eb add document
axmo
parents:
diff changeset
393
b342dc9b52eb add document
axmo
parents:
diff changeset
394 assert self.pid == None, 'The pid member should be None.'
b342dc9b52eb add document
axmo
parents:
diff changeset
395 assert self.command != None, 'The command member should not be None.'
b342dc9b52eb add document
axmo
parents:
diff changeset
396
b342dc9b52eb add document
axmo
parents:
diff changeset
397 try:
b342dc9b52eb add document
axmo
parents:
diff changeset
398 self.pid, self.child_fd = pty.fork()
b342dc9b52eb add document
axmo
parents:
diff changeset
399 except OSError, e:
b342dc9b52eb add document
axmo
parents:
diff changeset
400 raise ExceptionPexpect('Pexpect: pty.fork() failed: ' + str(e))
b342dc9b52eb add document
axmo
parents:
diff changeset
401
b342dc9b52eb add document
axmo
parents:
diff changeset
402 if self.pid == 0: # Child
b342dc9b52eb add document
axmo
parents:
diff changeset
403 try: # Some platforms do not like setwinsize (Cygwin).
b342dc9b52eb add document
axmo
parents:
diff changeset
404 self.child_fd = sys.stdout.fileno() # used by setwinsize()
b342dc9b52eb add document
axmo
parents:
diff changeset
405 self.setwinsize(24, 80)
b342dc9b52eb add document
axmo
parents:
diff changeset
406 except:
b342dc9b52eb add document
axmo
parents:
diff changeset
407 pass
b342dc9b52eb add document
axmo
parents:
diff changeset
408 # Do not allow child to inherit open file descriptors from parent.
b342dc9b52eb add document
axmo
parents:
diff changeset
409 max_fd = resource.getrlimit(resource.RLIMIT_NOFILE)[0]
b342dc9b52eb add document
axmo
parents:
diff changeset
410 for i in range (3, max_fd):
b342dc9b52eb add document
axmo
parents:
diff changeset
411 try:
b342dc9b52eb add document
axmo
parents:
diff changeset
412 os.close (i)
b342dc9b52eb add document
axmo
parents:
diff changeset
413 except OSError:
b342dc9b52eb add document
axmo
parents:
diff changeset
414 pass
b342dc9b52eb add document
axmo
parents:
diff changeset
415
b342dc9b52eb add document
axmo
parents:
diff changeset
416 # I don't know why this works, but ignoring SIGHUP fixes a
b342dc9b52eb add document
axmo
parents:
diff changeset
417 # problem when trying to start a Java daemon with sudo
b342dc9b52eb add document
axmo
parents:
diff changeset
418 # (specifically, Tomcat).
b342dc9b52eb add document
axmo
parents:
diff changeset
419 signal.signal(signal.SIGHUP, signal.SIG_IGN)
b342dc9b52eb add document
axmo
parents:
diff changeset
420
b342dc9b52eb add document
axmo
parents:
diff changeset
421 os.execv(self.command, self.args)
b342dc9b52eb add document
axmo
parents:
diff changeset
422
b342dc9b52eb add document
axmo
parents:
diff changeset
423 # Parent
b342dc9b52eb add document
axmo
parents:
diff changeset
424 self.terminated = 0
b342dc9b52eb add document
axmo
parents:
diff changeset
425 self.closed = 0
b342dc9b52eb add document
axmo
parents:
diff changeset
426
b342dc9b52eb add document
axmo
parents:
diff changeset
427 def fileno (self): # File-like object.
b342dc9b52eb add document
axmo
parents:
diff changeset
428 """This returns the file descriptor of the pty for the child.
b342dc9b52eb add document
axmo
parents:
diff changeset
429 """
b342dc9b52eb add document
axmo
parents:
diff changeset
430 return self.child_fd
b342dc9b52eb add document
axmo
parents:
diff changeset
431
b342dc9b52eb add document
axmo
parents:
diff changeset
432 def close (self, force=0): # File-like object.
b342dc9b52eb add document
axmo
parents:
diff changeset
433 """This closes the connection with the child application.
b342dc9b52eb add document
axmo
parents:
diff changeset
434 Note that calling close() more than once is valid.
b342dc9b52eb add document
axmo
parents:
diff changeset
435 This emulates standard Python behavior with files.
b342dc9b52eb add document
axmo
parents:
diff changeset
436 Set force to 1 if you want to make sure that the child is terminated
b342dc9b52eb add document
axmo
parents:
diff changeset
437 (SIGKILL is sent if the child ignores SIGHUP and SIGINT).
b342dc9b52eb add document
axmo
parents:
diff changeset
438 """
b342dc9b52eb add document
axmo
parents:
diff changeset
439 if self.child_fd != -1:
b342dc9b52eb add document
axmo
parents:
diff changeset
440 self.flush()
b342dc9b52eb add document
axmo
parents:
diff changeset
441 os.close (self.child_fd)
b342dc9b52eb add document
axmo
parents:
diff changeset
442 self.child_fd = -1
b342dc9b52eb add document
axmo
parents:
diff changeset
443 self.closed = 1
b342dc9b52eb add document
axmo
parents:
diff changeset
444 time.sleep(0.1) # Give kernel time to update process status.
b342dc9b52eb add document
axmo
parents:
diff changeset
445 if self.isalive():
b342dc9b52eb add document
axmo
parents:
diff changeset
446 if not self.terminate(force):
b342dc9b52eb add document
axmo
parents:
diff changeset
447 raise ExceptionPexpect ('close() could not terminate the child using terminate()')
b342dc9b52eb add document
axmo
parents:
diff changeset
448
b342dc9b52eb add document
axmo
parents:
diff changeset
449 def flush (self): # File-like object.
b342dc9b52eb add document
axmo
parents:
diff changeset
450 """This does nothing. It is here to support the interface for a File-like object.
b342dc9b52eb add document
axmo
parents:
diff changeset
451 """
b342dc9b52eb add document
axmo
parents:
diff changeset
452 pass
b342dc9b52eb add document
axmo
parents:
diff changeset
453
b342dc9b52eb add document
axmo
parents:
diff changeset
454 def isatty (self): # File-like object.
b342dc9b52eb add document
axmo
parents:
diff changeset
455 """This returns 1 if the file descriptor is open and connected to a tty(-like) device, else 0.
b342dc9b52eb add document
axmo
parents:
diff changeset
456 """
b342dc9b52eb add document
axmo
parents:
diff changeset
457 return os.isatty(self.child_fd)
b342dc9b52eb add document
axmo
parents:
diff changeset
458
b342dc9b52eb add document
axmo
parents:
diff changeset
459 def setecho (self, on):
b342dc9b52eb add document
axmo
parents:
diff changeset
460 """This sets the terminal echo mode on or off.
b342dc9b52eb add document
axmo
parents:
diff changeset
461 Note that anything the child sent before the echo will be lost, so
b342dc9b52eb add document
axmo
parents:
diff changeset
462 you should be sure that your input buffer is empty before you setecho.
b342dc9b52eb add document
axmo
parents:
diff changeset
463 For example, the following will work as expected.
b342dc9b52eb add document
axmo
parents:
diff changeset
464 p = pexpect.spawn('cat')
b342dc9b52eb add document
axmo
parents:
diff changeset
465 p.sendline ('1234') # We will see this twice (once from tty echo and again from cat).
b342dc9b52eb add document
axmo
parents:
diff changeset
466 p.expect (['1234'])
b342dc9b52eb add document
axmo
parents:
diff changeset
467 p.expect (['1234'])
b342dc9b52eb add document
axmo
parents:
diff changeset
468 p.setecho(0) # Turn off tty echo
b342dc9b52eb add document
axmo
parents:
diff changeset
469 p.sendline ('abcd') # We will set this only once (echoed by cat).
b342dc9b52eb add document
axmo
parents:
diff changeset
470 p.sendline ('wxyz') # We will set this only once (echoed by cat)
b342dc9b52eb add document
axmo
parents:
diff changeset
471 p.expect (['abcd'])
b342dc9b52eb add document
axmo
parents:
diff changeset
472 p.expect (['wxyz'])
b342dc9b52eb add document
axmo
parents:
diff changeset
473 The following WILL NOT WORK because the lines sent before the setecho
b342dc9b52eb add document
axmo
parents:
diff changeset
474 will be lost:
b342dc9b52eb add document
axmo
parents:
diff changeset
475 p = pexpect.spawn('cat')
b342dc9b52eb add document
axmo
parents:
diff changeset
476 p.sendline ('1234') # We will see this twice (once from tty echo and again from cat).
b342dc9b52eb add document
axmo
parents:
diff changeset
477 p.setecho(0) # Turn off tty echo
b342dc9b52eb add document
axmo
parents:
diff changeset
478 p.sendline ('abcd') # We will set this only once (echoed by cat).
b342dc9b52eb add document
axmo
parents:
diff changeset
479 p.sendline ('wxyz') # We will set this only once (echoed by cat)
b342dc9b52eb add document
axmo
parents:
diff changeset
480 p.expect (['1234'])
b342dc9b52eb add document
axmo
parents:
diff changeset
481 p.expect (['1234'])
b342dc9b52eb add document
axmo
parents:
diff changeset
482 p.expect (['abcd'])
b342dc9b52eb add document
axmo
parents:
diff changeset
483 p.expect (['wxyz'])
b342dc9b52eb add document
axmo
parents:
diff changeset
484 """
b342dc9b52eb add document
axmo
parents:
diff changeset
485 self.child_fd
b342dc9b52eb add document
axmo
parents:
diff changeset
486 new = termios.tcgetattr(self.child_fd)
b342dc9b52eb add document
axmo
parents:
diff changeset
487 if on:
b342dc9b52eb add document
axmo
parents:
diff changeset
488 new[3] = new[3] | termios.ECHO
b342dc9b52eb add document
axmo
parents:
diff changeset
489 else:
b342dc9b52eb add document
axmo
parents:
diff changeset
490 new[3] = new[3] & ~termios.ECHO
b342dc9b52eb add document
axmo
parents:
diff changeset
491 # I tried TCSADRAIN and TCSAFLUSH, but these were inconsistent
b342dc9b52eb add document
axmo
parents:
diff changeset
492 # and blocked on some platforms. TCSADRAIN is probably ideal if it worked.
b342dc9b52eb add document
axmo
parents:
diff changeset
493 termios.tcsetattr(self.child_fd, termios.TCSANOW, new)
b342dc9b52eb add document
axmo
parents:
diff changeset
494
b342dc9b52eb add document
axmo
parents:
diff changeset
495 def read_nonblocking (self, size = 1, timeout = -1):
b342dc9b52eb add document
axmo
parents:
diff changeset
496 """This reads at most size characters from the child application.
b342dc9b52eb add document
axmo
parents:
diff changeset
497 It includes a timeout. If the read does not complete within the
b342dc9b52eb add document
axmo
parents:
diff changeset
498 timeout period then a TIMEOUT exception is raised.
b342dc9b52eb add document
axmo
parents:
diff changeset
499 If the end of file is read then an EOF exception will be raised.
b342dc9b52eb add document
axmo
parents:
diff changeset
500 If a log file was set using setlog() then all data will
b342dc9b52eb add document
axmo
parents:
diff changeset
501 also be written to the log file.
b342dc9b52eb add document
axmo
parents:
diff changeset
502
b342dc9b52eb add document
axmo
parents:
diff changeset
503 If timeout==None then the read may block indefinitely.
b342dc9b52eb add document
axmo
parents:
diff changeset
504 If timeout==-1 then the self.timeout value is used.
b342dc9b52eb add document
axmo
parents:
diff changeset
505 If timeout==0 then the child is polled and
b342dc9b52eb add document
axmo
parents:
diff changeset
506 if there was no data immediately ready then this will raise a TIMEOUT exception.
b342dc9b52eb add document
axmo
parents:
diff changeset
507
b342dc9b52eb add document
axmo
parents:
diff changeset
508 The "timeout" refers only to the amount of time to read at least one character.
b342dc9b52eb add document
axmo
parents:
diff changeset
509 This is not effected by the 'size' parameter, so if you call
b342dc9b52eb add document
axmo
parents:
diff changeset
510 read_nonblocking(size=100, timeout=30) and only one character is
b342dc9b52eb add document
axmo
parents:
diff changeset
511 available right away then one character will be returned immediately.
b342dc9b52eb add document
axmo
parents:
diff changeset
512 It will not wait for 30 seconds for another 99 characters to come in.
b342dc9b52eb add document
axmo
parents:
diff changeset
513
b342dc9b52eb add document
axmo
parents:
diff changeset
514 This is a wrapper around os.read().
b342dc9b52eb add document
axmo
parents:
diff changeset
515 It uses select.select() to implement a timeout.
b342dc9b52eb add document
axmo
parents:
diff changeset
516 """
b342dc9b52eb add document
axmo
parents:
diff changeset
517 if self.child_fd == -1:
b342dc9b52eb add document
axmo
parents:
diff changeset
518 raise ValueError ('I/O operation on closed file in read_nonblocking().')
b342dc9b52eb add document
axmo
parents:
diff changeset
519
b342dc9b52eb add document
axmo
parents:
diff changeset
520 if timeout == -1:
b342dc9b52eb add document
axmo
parents:
diff changeset
521 timeout = self.timeout
b342dc9b52eb add document
axmo
parents:
diff changeset
522
b342dc9b52eb add document
axmo
parents:
diff changeset
523 # Note that some systems such as Solaris do not give an EOF when
b342dc9b52eb add document
axmo
parents:
diff changeset
524 # the child dies. In fact, you can still try to read
b342dc9b52eb add document
axmo
parents:
diff changeset
525 # from the child_fd -- it will block forever or until TIMEOUT.
b342dc9b52eb add document
axmo
parents:
diff changeset
526 # For this case, I test isalive() before doing any reading.
b342dc9b52eb add document
axmo
parents:
diff changeset
527 # If isalive() is false, then I pretend that this is the same as EOF.
b342dc9b52eb add document
axmo
parents:
diff changeset
528 if not self.isalive():
b342dc9b52eb add document
axmo
parents:
diff changeset
529 r, w, e = select.select([self.child_fd], [], [], 0) # timeout of 0 means "poll"
b342dc9b52eb add document
axmo
parents:
diff changeset
530 if not r:
b342dc9b52eb add document
axmo
parents:
diff changeset
531 self.flag_eof = 1
b342dc9b52eb add document
axmo
parents:
diff changeset
532 raise EOF ('End Of File (EOF) in read_nonblocking(). Braindead platform.')
b342dc9b52eb add document
axmo
parents:
diff changeset
533 elif sys.platform.lower().find('irix') >= 0:
b342dc9b52eb add document
axmo
parents:
diff changeset
534 # This is a hack for Irix. It seems that Irix requires a long delay before checking isalive.
b342dc9b52eb add document
axmo
parents:
diff changeset
535 # This adds a 2 second delay, but only when the child is terminated
b342dc9b52eb add document
axmo
parents:
diff changeset
536 r, w, e = select.select([self.child_fd], [], [], 2)
b342dc9b52eb add document
axmo
parents:
diff changeset
537 if not r and not self.isalive():
b342dc9b52eb add document
axmo
parents:
diff changeset
538 self.flag_eof = 1
b342dc9b52eb add document
axmo
parents:
diff changeset
539 raise EOF ('End Of File (EOF) in read_nonblocking(). Pokey platform.')
b342dc9b52eb add document
axmo
parents:
diff changeset
540
b342dc9b52eb add document
axmo
parents:
diff changeset
541 r, w, e = select.select([self.child_fd], [], [], timeout)
b342dc9b52eb add document
axmo
parents:
diff changeset
542 if not r:
b342dc9b52eb add document
axmo
parents:
diff changeset
543 if not self.isalive():
b342dc9b52eb add document
axmo
parents:
diff changeset
544 # Some platforms, such as Irix, will claim that their processes are alive;
b342dc9b52eb add document
axmo
parents:
diff changeset
545 # then timeout on the select; and then finally admit that they are not alive.
b342dc9b52eb add document
axmo
parents:
diff changeset
546 self.flag_eof = 1
b342dc9b52eb add document
axmo
parents:
diff changeset
547 raise EOF ('End of File (EOF) in read_nonblocking(). Very pokey platform.')
b342dc9b52eb add document
axmo
parents:
diff changeset
548 else:
b342dc9b52eb add document
axmo
parents:
diff changeset
549 raise TIMEOUT ('Timeout exceeded in read_nonblocking().')
b342dc9b52eb add document
axmo
parents:
diff changeset
550
b342dc9b52eb add document
axmo
parents:
diff changeset
551 if self.child_fd in r:
b342dc9b52eb add document
axmo
parents:
diff changeset
552 try:
b342dc9b52eb add document
axmo
parents:
diff changeset
553 s = os.read(self.child_fd, size)
b342dc9b52eb add document
axmo
parents:
diff changeset
554 except OSError, e: # Linux does this
b342dc9b52eb add document
axmo
parents:
diff changeset
555 self.flag_eof = 1
b342dc9b52eb add document
axmo
parents:
diff changeset
556 raise EOF ('End Of File (EOF) in read_nonblocking(). Exception style platform.')
b342dc9b52eb add document
axmo
parents:
diff changeset
557 if s == '': # BSD style
b342dc9b52eb add document
axmo
parents:
diff changeset
558 self.flag_eof = 1
b342dc9b52eb add document
axmo
parents:
diff changeset
559 raise EOF ('End Of File (EOF) in read_nonblocking(). Empty string style platform.')
b342dc9b52eb add document
axmo
parents:
diff changeset
560
b342dc9b52eb add document
axmo
parents:
diff changeset
561 if self.logfile != None:
b342dc9b52eb add document
axmo
parents:
diff changeset
562 self.logfile.write (s)
b342dc9b52eb add document
axmo
parents:
diff changeset
563 self.logfile.flush()
b342dc9b52eb add document
axmo
parents:
diff changeset
564
b342dc9b52eb add document
axmo
parents:
diff changeset
565 return s
b342dc9b52eb add document
axmo
parents:
diff changeset
566
b342dc9b52eb add document
axmo
parents:
diff changeset
567 raise ExceptionPexpect ('Reached an unexpected state in read_nonblocking().')
b342dc9b52eb add document
axmo
parents:
diff changeset
568
b342dc9b52eb add document
axmo
parents:
diff changeset
569 def read (self, size = -1): # File-like object.
b342dc9b52eb add document
axmo
parents:
diff changeset
570 """This reads at most "size" bytes from the file
b342dc9b52eb add document
axmo
parents:
diff changeset
571 (less if the read hits EOF before obtaining size bytes).
b342dc9b52eb add document
axmo
parents:
diff changeset
572 If the size argument is negative or omitted,
b342dc9b52eb add document
axmo
parents:
diff changeset
573 read all data until EOF is reached.
b342dc9b52eb add document
axmo
parents:
diff changeset
574 The bytes are returned as a string object.
b342dc9b52eb add document
axmo
parents:
diff changeset
575 An empty string is returned when EOF is encountered immediately.
b342dc9b52eb add document
axmo
parents:
diff changeset
576 """
b342dc9b52eb add document
axmo
parents:
diff changeset
577 if size == 0:
b342dc9b52eb add document
axmo
parents:
diff changeset
578 return ''
b342dc9b52eb add document
axmo
parents:
diff changeset
579 if size < 0:
b342dc9b52eb add document
axmo
parents:
diff changeset
580 self.expect (self.delimiter) # delimiter default is EOF
b342dc9b52eb add document
axmo
parents:
diff changeset
581 return self.before
b342dc9b52eb add document
axmo
parents:
diff changeset
582
b342dc9b52eb add document
axmo
parents:
diff changeset
583 # I could have done this more directly by not using expect(), but
b342dc9b52eb add document
axmo
parents:
diff changeset
584 # I deliberately decided to couple read() to expect() so that
b342dc9b52eb add document
axmo
parents:
diff changeset
585 # I would catch any bugs early and ensure consistant behavior.
b342dc9b52eb add document
axmo
parents:
diff changeset
586 # It's a little less efficient, but there is less for me to
b342dc9b52eb add document
axmo
parents:
diff changeset
587 # worry about if I have to later modify read() or expect().
b342dc9b52eb add document
axmo
parents:
diff changeset
588 # Note, it's OK if size==-1 in the regex. That just means it
b342dc9b52eb add document
axmo
parents:
diff changeset
589 # will never match anything in which case we stop only on EOF.
b342dc9b52eb add document
axmo
parents:
diff changeset
590 cre = re.compile('.{%d}' % size, re.DOTALL)
b342dc9b52eb add document
axmo
parents:
diff changeset
591 index = self.expect ([cre, self.delimiter]) # delimiter default is EOF
b342dc9b52eb add document
axmo
parents:
diff changeset
592 if index == 0:
b342dc9b52eb add document
axmo
parents:
diff changeset
593 return self.after ### self.before should be ''. Should I assert this?
b342dc9b52eb add document
axmo
parents:
diff changeset
594 return self.before
b342dc9b52eb add document
axmo
parents:
diff changeset
595
b342dc9b52eb add document
axmo
parents:
diff changeset
596 def readline (self, size = -1): # File-like object.
b342dc9b52eb add document
axmo
parents:
diff changeset
597 """This reads and returns one entire line. A trailing newline is kept in
b342dc9b52eb add document
axmo
parents:
diff changeset
598 the string, but may be absent when a file ends with an incomplete line.
b342dc9b52eb add document
axmo
parents:
diff changeset
599 Note: This readline() looks for a \\r\\n pair even on UNIX because this is
b342dc9b52eb add document
axmo
parents:
diff changeset
600 what the pseudo tty device returns. So contrary to what you may be used to
b342dc9b52eb add document
axmo
parents:
diff changeset
601 you will receive a newline as \\r\\n.
b342dc9b52eb add document
axmo
parents:
diff changeset
602 An empty string is returned when EOF is hit immediately.
b342dc9b52eb add document
axmo
parents:
diff changeset
603 Currently, the size agument is mostly ignored, so this behavior is not
b342dc9b52eb add document
axmo
parents:
diff changeset
604 standard for a file-like object. If size is 0 then an empty string is returned.
b342dc9b52eb add document
axmo
parents:
diff changeset
605 """
b342dc9b52eb add document
axmo
parents:
diff changeset
606 if size == 0:
b342dc9b52eb add document
axmo
parents:
diff changeset
607 return ''
b342dc9b52eb add document
axmo
parents:
diff changeset
608 index = self.expect (['\r\n', self.delimiter]) # delimiter default is EOF
b342dc9b52eb add document
axmo
parents:
diff changeset
609 if index == 0:
b342dc9b52eb add document
axmo
parents:
diff changeset
610 return self.before + '\r\n'
b342dc9b52eb add document
axmo
parents:
diff changeset
611 else:
b342dc9b52eb add document
axmo
parents:
diff changeset
612 return self.before
b342dc9b52eb add document
axmo
parents:
diff changeset
613
b342dc9b52eb add document
axmo
parents:
diff changeset
614 def __iter__ (self): # File-like object.
b342dc9b52eb add document
axmo
parents:
diff changeset
615 """This is to support interators over a file-like object.
b342dc9b52eb add document
axmo
parents:
diff changeset
616 """
b342dc9b52eb add document
axmo
parents:
diff changeset
617 return self
b342dc9b52eb add document
axmo
parents:
diff changeset
618
b342dc9b52eb add document
axmo
parents:
diff changeset
619 def next (self): # File-like object.
b342dc9b52eb add document
axmo
parents:
diff changeset
620 """This is to support iterators over a file-like object.
b342dc9b52eb add document
axmo
parents:
diff changeset
621 """
b342dc9b52eb add document
axmo
parents:
diff changeset
622 result = self.readline()
b342dc9b52eb add document
axmo
parents:
diff changeset
623 if result == "":
b342dc9b52eb add document
axmo
parents:
diff changeset
624 raise StopIteration
b342dc9b52eb add document
axmo
parents:
diff changeset
625 return result
b342dc9b52eb add document
axmo
parents:
diff changeset
626
b342dc9b52eb add document
axmo
parents:
diff changeset
627 def readlines (self, sizehint = -1): # File-like object.
b342dc9b52eb add document
axmo
parents:
diff changeset
628 """This reads until EOF using readline() and returns a list containing
b342dc9b52eb add document
axmo
parents:
diff changeset
629 the lines thus read. The optional "sizehint" argument is ignored.
b342dc9b52eb add document
axmo
parents:
diff changeset
630 """
b342dc9b52eb add document
axmo
parents:
diff changeset
631 lines = []
b342dc9b52eb add document
axmo
parents:
diff changeset
632 while 1:
b342dc9b52eb add document
axmo
parents:
diff changeset
633 line = self.readline()
b342dc9b52eb add document
axmo
parents:
diff changeset
634 if not line:
b342dc9b52eb add document
axmo
parents:
diff changeset
635 break
b342dc9b52eb add document
axmo
parents:
diff changeset
636 lines.append(line)
b342dc9b52eb add document
axmo
parents:
diff changeset
637 return lines
b342dc9b52eb add document
axmo
parents:
diff changeset
638
b342dc9b52eb add document
axmo
parents:
diff changeset
639 def write(self, str): # File-like object.
b342dc9b52eb add document
axmo
parents:
diff changeset
640 """This is similar to send() except that there is no return value.
b342dc9b52eb add document
axmo
parents:
diff changeset
641 """
b342dc9b52eb add document
axmo
parents:
diff changeset
642 self.send (str)
b342dc9b52eb add document
axmo
parents:
diff changeset
643
b342dc9b52eb add document
axmo
parents:
diff changeset
644 def writelines (self, sequence): # File-like object.
b342dc9b52eb add document
axmo
parents:
diff changeset
645 """This calls write() for each element in the sequence.
b342dc9b52eb add document
axmo
parents:
diff changeset
646 The sequence can be any iterable object producing strings,
b342dc9b52eb add document
axmo
parents:
diff changeset
647 typically a list of strings. This does not add line separators
b342dc9b52eb add document
axmo
parents:
diff changeset
648 There is no return value.
b342dc9b52eb add document
axmo
parents:
diff changeset
649 """
b342dc9b52eb add document
axmo
parents:
diff changeset
650 for str in sequence:
b342dc9b52eb add document
axmo
parents:
diff changeset
651 self.write (str)
b342dc9b52eb add document
axmo
parents:
diff changeset
652
b342dc9b52eb add document
axmo
parents:
diff changeset
653 def send(self, str):
b342dc9b52eb add document
axmo
parents:
diff changeset
654 """This sends a string to the child process.
b342dc9b52eb add document
axmo
parents:
diff changeset
655 This returns the number of bytes written.
b342dc9b52eb add document
axmo
parents:
diff changeset
656 If a log file was set then the data is also written to the log.
b342dc9b52eb add document
axmo
parents:
diff changeset
657 """
b342dc9b52eb add document
axmo
parents:
diff changeset
658 time.sleep(self.delaybeforesend)
b342dc9b52eb add document
axmo
parents:
diff changeset
659 if self.logfile != None:
b342dc9b52eb add document
axmo
parents:
diff changeset
660 self.logfile.write (str)
b342dc9b52eb add document
axmo
parents:
diff changeset
661 self.logfile.flush()
b342dc9b52eb add document
axmo
parents:
diff changeset
662 c = os.write(self.child_fd, str)
b342dc9b52eb add document
axmo
parents:
diff changeset
663 return c
b342dc9b52eb add document
axmo
parents:
diff changeset
664
b342dc9b52eb add document
axmo
parents:
diff changeset
665 def sendline(self, str=''):
b342dc9b52eb add document
axmo
parents:
diff changeset
666 """This is like send(), but it adds a line feed (os.linesep).
b342dc9b52eb add document
axmo
parents:
diff changeset
667 This returns the number of bytes written.
b342dc9b52eb add document
axmo
parents:
diff changeset
668 """
b342dc9b52eb add document
axmo
parents:
diff changeset
669 n = self.send(str)
b342dc9b52eb add document
axmo
parents:
diff changeset
670 n = n + self.send (os.linesep)
b342dc9b52eb add document
axmo
parents:
diff changeset
671 return n
b342dc9b52eb add document
axmo
parents:
diff changeset
672
b342dc9b52eb add document
axmo
parents:
diff changeset
673 def sendeof(self):
b342dc9b52eb add document
axmo
parents:
diff changeset
674 """This sends an EOF to the child.
b342dc9b52eb add document
axmo
parents:
diff changeset
675 This sends a character which causes the pending parent output
b342dc9b52eb add document
axmo
parents:
diff changeset
676 buffer to be sent to the waiting child program without
b342dc9b52eb add document
axmo
parents:
diff changeset
677 waiting for end-of-line. If it is the first character of the
b342dc9b52eb add document
axmo
parents:
diff changeset
678 line, the read() in the user program returns 0, which
b342dc9b52eb add document
axmo
parents:
diff changeset
679 signifies end-of-file. This means to work as expected
b342dc9b52eb add document
axmo
parents:
diff changeset
680 a sendeof() has to be called at the begining of a line.
b342dc9b52eb add document
axmo
parents:
diff changeset
681 This method does not send a newline. It is the responsibility
b342dc9b52eb add document
axmo
parents:
diff changeset
682 of the caller to ensure the eof is sent at the beginning of a line.
b342dc9b52eb add document
axmo
parents:
diff changeset
683 """
b342dc9b52eb add document
axmo
parents:
diff changeset
684 ### Hmmm... how do I send an EOF?
b342dc9b52eb add document
axmo
parents:
diff changeset
685 ###C if ((m = write(pty, *buf, p - *buf)) < 0)
b342dc9b52eb add document
axmo
parents:
diff changeset
686 ###C return (errno == EWOULDBLOCK) ? n : -1;
b342dc9b52eb add document
axmo
parents:
diff changeset
687 fd = sys.stdin.fileno()
b342dc9b52eb add document
axmo
parents:
diff changeset
688 old = termios.tcgetattr(fd) # remember current state
b342dc9b52eb add document
axmo
parents:
diff changeset
689 new = termios.tcgetattr(fd)
b342dc9b52eb add document
axmo
parents:
diff changeset
690 new[3] = new[3] | termios.ICANON # ICANON must be set to recognize EOF
b342dc9b52eb add document
axmo
parents:
diff changeset
691 try: # use try/finally to ensure state gets restored
b342dc9b52eb add document
axmo
parents:
diff changeset
692 termios.tcsetattr(fd, termios.TCSADRAIN, new)
b342dc9b52eb add document
axmo
parents:
diff changeset
693 if 'CEOF' in dir(termios):
b342dc9b52eb add document
axmo
parents:
diff changeset
694 os.write (self.child_fd, '%c' % termios.CEOF)
b342dc9b52eb add document
axmo
parents:
diff changeset
695 else:
b342dc9b52eb add document
axmo
parents:
diff changeset
696 os.write (self.child_fd, '%c' % 4) # Silly platform does not define CEOF so assume CTRL-D
b342dc9b52eb add document
axmo
parents:
diff changeset
697 finally: # restore state
b342dc9b52eb add document
axmo
parents:
diff changeset
698 termios.tcsetattr(fd, termios.TCSADRAIN, old)
b342dc9b52eb add document
axmo
parents:
diff changeset
699
b342dc9b52eb add document
axmo
parents:
diff changeset
700 def eof (self):
b342dc9b52eb add document
axmo
parents:
diff changeset
701 """This returns 1 if the EOF exception was raised at some point.
b342dc9b52eb add document
axmo
parents:
diff changeset
702 """
b342dc9b52eb add document
axmo
parents:
diff changeset
703 return self.flag_eof
b342dc9b52eb add document
axmo
parents:
diff changeset
704
b342dc9b52eb add document
axmo
parents:
diff changeset
705 def terminate(self, force=0):
b342dc9b52eb add document
axmo
parents:
diff changeset
706 """This forces a child process to terminate.
b342dc9b52eb add document
axmo
parents:
diff changeset
707 It starts nicely with SIGHUP and SIGINT. If "force" is 1 then
b342dc9b52eb add document
axmo
parents:
diff changeset
708 moves onto SIGKILL.
b342dc9b52eb add document
axmo
parents:
diff changeset
709 This returns true if the child was terminated.
b342dc9b52eb add document
axmo
parents:
diff changeset
710 This returns false if the child could not be terminated.
b342dc9b52eb add document
axmo
parents:
diff changeset
711 """
b342dc9b52eb add document
axmo
parents:
diff changeset
712 if not self.isalive():
b342dc9b52eb add document
axmo
parents:
diff changeset
713 return 1
b342dc9b52eb add document
axmo
parents:
diff changeset
714 self.kill(signal.SIGHUP)
b342dc9b52eb add document
axmo
parents:
diff changeset
715 time.sleep(0.1)
b342dc9b52eb add document
axmo
parents:
diff changeset
716 if not self.isalive():
b342dc9b52eb add document
axmo
parents:
diff changeset
717 return 1
b342dc9b52eb add document
axmo
parents:
diff changeset
718 self.kill(signal.SIGCONT)
b342dc9b52eb add document
axmo
parents:
diff changeset
719 time.sleep(0.1)
b342dc9b52eb add document
axmo
parents:
diff changeset
720 if not self.isalive():
b342dc9b52eb add document
axmo
parents:
diff changeset
721 return 1
b342dc9b52eb add document
axmo
parents:
diff changeset
722 self.kill(signal.SIGINT)
b342dc9b52eb add document
axmo
parents:
diff changeset
723 time.sleep(0.1)
b342dc9b52eb add document
axmo
parents:
diff changeset
724 if not self.isalive():
b342dc9b52eb add document
axmo
parents:
diff changeset
725 return 1
b342dc9b52eb add document
axmo
parents:
diff changeset
726 if force:
b342dc9b52eb add document
axmo
parents:
diff changeset
727 self.kill(signal.SIGKILL)
b342dc9b52eb add document
axmo
parents:
diff changeset
728 time.sleep(0.1)
b342dc9b52eb add document
axmo
parents:
diff changeset
729 if not self.isalive():
b342dc9b52eb add document
axmo
parents:
diff changeset
730 return 1
b342dc9b52eb add document
axmo
parents:
diff changeset
731 else:
b342dc9b52eb add document
axmo
parents:
diff changeset
732 return 0
b342dc9b52eb add document
axmo
parents:
diff changeset
733 return 0
b342dc9b52eb add document
axmo
parents:
diff changeset
734 #raise ExceptionPexpect ('terminate() could not terminate child process. Try terminate(force=1)?')
b342dc9b52eb add document
axmo
parents:
diff changeset
735
b342dc9b52eb add document
axmo
parents:
diff changeset
736 def isalive(self):
b342dc9b52eb add document
axmo
parents:
diff changeset
737 """This tests if the child process is running or not.
b342dc9b52eb add document
axmo
parents:
diff changeset
738 This is non-blocking. If the child was terminated then this
b342dc9b52eb add document
axmo
parents:
diff changeset
739 will read the exitstatus or signalstatus of the child.
b342dc9b52eb add document
axmo
parents:
diff changeset
740 This returns 1 if the child process appears to be running or 0 if not.
b342dc9b52eb add document
axmo
parents:
diff changeset
741 It can take literally SECONDS for Solaris to return the right status.
b342dc9b52eb add document
axmo
parents:
diff changeset
742 """
b342dc9b52eb add document
axmo
parents:
diff changeset
743 if self.terminated:
b342dc9b52eb add document
axmo
parents:
diff changeset
744 return 0
b342dc9b52eb add document
axmo
parents:
diff changeset
745
b342dc9b52eb add document
axmo
parents:
diff changeset
746 if self.flag_eof:
b342dc9b52eb add document
axmo
parents:
diff changeset
747 # This is for Linux, which requires the blocking form of waitpid to get
b342dc9b52eb add document
axmo
parents:
diff changeset
748 # status of a defunct process. This is super-lame. The flag_eof would have
b342dc9b52eb add document
axmo
parents:
diff changeset
749 # been set in read_nonblocking(), so this should be safe.
b342dc9b52eb add document
axmo
parents:
diff changeset
750 waitpid_options = 0
b342dc9b52eb add document
axmo
parents:
diff changeset
751 else:
b342dc9b52eb add document
axmo
parents:
diff changeset
752 waitpid_options = os.WNOHANG
b342dc9b52eb add document
axmo
parents:
diff changeset
753
b342dc9b52eb add document
axmo
parents:
diff changeset
754 try:
b342dc9b52eb add document
axmo
parents:
diff changeset
755 pid, status = os.waitpid(self.pid, waitpid_options)
b342dc9b52eb add document
axmo
parents:
diff changeset
756 except OSError, e: # No child processes
b342dc9b52eb add document
axmo
parents:
diff changeset
757 if e[0] == errno.ECHILD:
b342dc9b52eb add document
axmo
parents:
diff changeset
758 raise ExceptionPexpect ('isalive() encountered condition where "terminated" is 0, but there was no child process. Did someone else call waitpid() on our process?')
b342dc9b52eb add document
axmo
parents:
diff changeset
759 else:
b342dc9b52eb add document
axmo
parents:
diff changeset
760 raise e
b342dc9b52eb add document
axmo
parents:
diff changeset
761
b342dc9b52eb add document
axmo
parents:
diff changeset
762 # I have to do this twice for Solaris. I can't even believe that I figured this out...
b342dc9b52eb add document
axmo
parents:
diff changeset
763 # If waitpid() returns 0 it means that no child process wishes to
b342dc9b52eb add document
axmo
parents:
diff changeset
764 # report, and the value of status is undefined.
b342dc9b52eb add document
axmo
parents:
diff changeset
765 if pid == 0:
b342dc9b52eb add document
axmo
parents:
diff changeset
766 try:
b342dc9b52eb add document
axmo
parents:
diff changeset
767 pid, status = os.waitpid(self.pid, waitpid_options) ### os.WNOHANG) # Solaris!
b342dc9b52eb add document
axmo
parents:
diff changeset
768 except OSError, e: # This should never happen...
b342dc9b52eb add document
axmo
parents:
diff changeset
769 if e[0] == errno.ECHILD:
b342dc9b52eb add document
axmo
parents:
diff changeset
770 raise ExceptionPexpect ('isalive() encountered condition that should never happen. There was no child process. Did someone else call waitpid() on our process?')
b342dc9b52eb add document
axmo
parents:
diff changeset
771 else:
b342dc9b52eb add document
axmo
parents:
diff changeset
772 raise e
b342dc9b52eb add document
axmo
parents:
diff changeset
773
b342dc9b52eb add document
axmo
parents:
diff changeset
774 # If pid is still 0 after two calls to waitpid() then
b342dc9b52eb add document
axmo
parents:
diff changeset
775 # the process really is alive. This seems to work on all platforms, except
b342dc9b52eb add document
axmo
parents:
diff changeset
776 # for Irix which seems to require a blocking call on waitpid or select, so I let read_nonblocking
b342dc9b52eb add document
axmo
parents:
diff changeset
777 # take care of this situation (unfortunately, this requires waiting through the timeout).
b342dc9b52eb add document
axmo
parents:
diff changeset
778 if pid == 0:
b342dc9b52eb add document
axmo
parents:
diff changeset
779 return 1
b342dc9b52eb add document
axmo
parents:
diff changeset
780
b342dc9b52eb add document
axmo
parents:
diff changeset
781 if pid == 0:
b342dc9b52eb add document
axmo
parents:
diff changeset
782 return 1
b342dc9b52eb add document
axmo
parents:
diff changeset
783
b342dc9b52eb add document
axmo
parents:
diff changeset
784 if os.WIFEXITED (status):
b342dc9b52eb add document
axmo
parents:
diff changeset
785 self.status = status
b342dc9b52eb add document
axmo
parents:
diff changeset
786 self.exitstatus = os.WEXITSTATUS(status)
b342dc9b52eb add document
axmo
parents:
diff changeset
787 self.signalstatus = None
b342dc9b52eb add document
axmo
parents:
diff changeset
788 self.terminated = 1
b342dc9b52eb add document
axmo
parents:
diff changeset
789 return 0
b342dc9b52eb add document
axmo
parents:
diff changeset
790 elif os.WIFSIGNALED (status):
b342dc9b52eb add document
axmo
parents:
diff changeset
791 self.status = status
b342dc9b52eb add document
axmo
parents:
diff changeset
792 self.exitstatus = None
b342dc9b52eb add document
axmo
parents:
diff changeset
793 self.signalstatus = os.WTERMSIG(status)
b342dc9b52eb add document
axmo
parents:
diff changeset
794 self.terminated = 1
b342dc9b52eb add document
axmo
parents:
diff changeset
795 return 0
b342dc9b52eb add document
axmo
parents:
diff changeset
796 elif os.WIFSTOPPED (status):
b342dc9b52eb add document
axmo
parents:
diff changeset
797 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?')
b342dc9b52eb add document
axmo
parents:
diff changeset
798
b342dc9b52eb add document
axmo
parents:
diff changeset
799 raise ExceptionPexpect ('isalive() reached unexpected condition where waitpid matched child pid, but status was not matched by WIFEXITED, WIFSIGNALED, or WIFSTOPPED.')
b342dc9b52eb add document
axmo
parents:
diff changeset
800
b342dc9b52eb add document
axmo
parents:
diff changeset
801
b342dc9b52eb add document
axmo
parents:
diff changeset
802 def kill(self, sig):
b342dc9b52eb add document
axmo
parents:
diff changeset
803 """This sends the given signal to the child application.
b342dc9b52eb add document
axmo
parents:
diff changeset
804 In keeping with UNIX tradition it has a misleading name.
b342dc9b52eb add document
axmo
parents:
diff changeset
805 It does not necessarily kill the child unless
b342dc9b52eb add document
axmo
parents:
diff changeset
806 you send the right signal.
b342dc9b52eb add document
axmo
parents:
diff changeset
807 """
b342dc9b52eb add document
axmo
parents:
diff changeset
808 # Same as os.kill, but the pid is given for you.
b342dc9b52eb add document
axmo
parents:
diff changeset
809 if self.isalive():
b342dc9b52eb add document
axmo
parents:
diff changeset
810 os.kill(self.pid, sig)
b342dc9b52eb add document
axmo
parents:
diff changeset
811
b342dc9b52eb add document
axmo
parents:
diff changeset
812 def compile_pattern_list(self, patterns):
b342dc9b52eb add document
axmo
parents:
diff changeset
813 """This compiles a pattern-string or a list of pattern-strings.
b342dc9b52eb add document
axmo
parents:
diff changeset
814 Patterns must be a StringType, EOF, TIMEOUT, SRE_Pattern, or
b342dc9b52eb add document
axmo
parents:
diff changeset
815 a list of those. Patterns may also be None which results in
b342dc9b52eb add document
axmo
parents:
diff changeset
816 an empty list.
b342dc9b52eb add document
axmo
parents:
diff changeset
817
b342dc9b52eb add document
axmo
parents:
diff changeset
818 This is used by expect() when calling expect_list().
b342dc9b52eb add document
axmo
parents:
diff changeset
819 Thus expect() is nothing more than::
b342dc9b52eb add document
axmo
parents:
diff changeset
820 cpl = self.compile_pattern_list(pl)
b342dc9b52eb add document
axmo
parents:
diff changeset
821 return self.expect_list(clp, timeout)
b342dc9b52eb add document
axmo
parents:
diff changeset
822
b342dc9b52eb add document
axmo
parents:
diff changeset
823 If you are using expect() within a loop it may be more
b342dc9b52eb add document
axmo
parents:
diff changeset
824 efficient to compile the patterns first and then call expect_list().
b342dc9b52eb add document
axmo
parents:
diff changeset
825 This avoid calls in a loop to compile_pattern_list():
b342dc9b52eb add document
axmo
parents:
diff changeset
826 cpl = self.compile_pattern_list(my_pattern)
b342dc9b52eb add document
axmo
parents:
diff changeset
827 while some_condition:
b342dc9b52eb add document
axmo
parents:
diff changeset
828 ...
b342dc9b52eb add document
axmo
parents:
diff changeset
829 i = self.expect_list(clp, timeout)
b342dc9b52eb add document
axmo
parents:
diff changeset
830 ...
b342dc9b52eb add document
axmo
parents:
diff changeset
831 """
b342dc9b52eb add document
axmo
parents:
diff changeset
832 if patterns is None:
b342dc9b52eb add document
axmo
parents:
diff changeset
833 return []
b342dc9b52eb add document
axmo
parents:
diff changeset
834 if type(patterns) is not types.ListType:
b342dc9b52eb add document
axmo
parents:
diff changeset
835 patterns = [patterns]
b342dc9b52eb add document
axmo
parents:
diff changeset
836
b342dc9b52eb add document
axmo
parents:
diff changeset
837 compiled_pattern_list = []
b342dc9b52eb add document
axmo
parents:
diff changeset
838 for p in patterns:
b342dc9b52eb add document
axmo
parents:
diff changeset
839 if type(p) is types.StringType:
b342dc9b52eb add document
axmo
parents:
diff changeset
840 compiled_pattern_list.append(re.compile(p, re.DOTALL))
b342dc9b52eb add document
axmo
parents:
diff changeset
841 elif p is EOF:
b342dc9b52eb add document
axmo
parents:
diff changeset
842 compiled_pattern_list.append(EOF)
b342dc9b52eb add document
axmo
parents:
diff changeset
843 elif p is TIMEOUT:
b342dc9b52eb add document
axmo
parents:
diff changeset
844 compiled_pattern_list.append(TIMEOUT)
b342dc9b52eb add document
axmo
parents:
diff changeset
845 elif type(p) is type(re.compile('')):
b342dc9b52eb add document
axmo
parents:
diff changeset
846 compiled_pattern_list.append(p)
b342dc9b52eb add document
axmo
parents:
diff changeset
847 else:
b342dc9b52eb add document
axmo
parents:
diff changeset
848 raise TypeError ('Argument must be one of StringType, EOF, TIMEOUT, SRE_Pattern, or a list of those type. %s' % str(type(p)))
b342dc9b52eb add document
axmo
parents:
diff changeset
849
b342dc9b52eb add document
axmo
parents:
diff changeset
850 return compiled_pattern_list
b342dc9b52eb add document
axmo
parents:
diff changeset
851
b342dc9b52eb add document
axmo
parents:
diff changeset
852 def expect(self, pattern, timeout = -1, searchwindowsize=None):
b342dc9b52eb add document
axmo
parents:
diff changeset
853 """This seeks through the stream until a pattern is matched.
b342dc9b52eb add document
axmo
parents:
diff changeset
854 The pattern is overloaded and may take several types including a list.
b342dc9b52eb add document
axmo
parents:
diff changeset
855 The pattern can be a StringType, EOF, a compiled re, or
b342dc9b52eb add document
axmo
parents:
diff changeset
856 a list of those types. Strings will be compiled to re types.
b342dc9b52eb add document
axmo
parents:
diff changeset
857 This returns the index into the pattern list. If the pattern was
b342dc9b52eb add document
axmo
parents:
diff changeset
858 not a list this returns index 0 on a successful match.
b342dc9b52eb add document
axmo
parents:
diff changeset
859 This may raise exceptions for EOF or TIMEOUT.
b342dc9b52eb add document
axmo
parents:
diff changeset
860 To avoid the EOF or TIMEOUT exceptions add EOF or TIMEOUT to
b342dc9b52eb add document
axmo
parents:
diff changeset
861 the pattern list.
b342dc9b52eb add document
axmo
parents:
diff changeset
862
b342dc9b52eb add document
axmo
parents:
diff changeset
863 After a match is found the instance attributes
b342dc9b52eb add document
axmo
parents:
diff changeset
864 'before', 'after' and 'match' will be set.
b342dc9b52eb add document
axmo
parents:
diff changeset
865 You can see all the data read before the match in 'before'.
b342dc9b52eb add document
axmo
parents:
diff changeset
866 You can see the data that was matched in 'after'.
b342dc9b52eb add document
axmo
parents:
diff changeset
867 The re.MatchObject used in the re match will be in 'match'.
b342dc9b52eb add document
axmo
parents:
diff changeset
868 If an error occured then 'before' will be set to all the
b342dc9b52eb add document
axmo
parents:
diff changeset
869 data read so far and 'after' and 'match' will be None.
b342dc9b52eb add document
axmo
parents:
diff changeset
870
b342dc9b52eb add document
axmo
parents:
diff changeset
871 If timeout is -1 then timeout will be set to the self.timeout value.
b342dc9b52eb add document
axmo
parents:
diff changeset
872
b342dc9b52eb add document
axmo
parents:
diff changeset
873 Note: A list entry may be EOF or TIMEOUT instead of a string.
b342dc9b52eb add document
axmo
parents:
diff changeset
874 This will catch these exceptions and return the index
b342dc9b52eb add document
axmo
parents:
diff changeset
875 of the list entry instead of raising the exception.
b342dc9b52eb add document
axmo
parents:
diff changeset
876 The attribute 'after' will be set to the exception type.
b342dc9b52eb add document
axmo
parents:
diff changeset
877 The attribute 'match' will be None.
b342dc9b52eb add document
axmo
parents:
diff changeset
878 This allows you to write code like this:
b342dc9b52eb add document
axmo
parents:
diff changeset
879 index = p.expect (['good', 'bad', pexpect.EOF, pexpect.TIMEOUT])
b342dc9b52eb add document
axmo
parents:
diff changeset
880 if index == 0:
b342dc9b52eb add document
axmo
parents:
diff changeset
881 do_something()
b342dc9b52eb add document
axmo
parents:
diff changeset
882 elif index == 1:
b342dc9b52eb add document
axmo
parents:
diff changeset
883 do_something_else()
b342dc9b52eb add document
axmo
parents:
diff changeset
884 elif index == 2:
b342dc9b52eb add document
axmo
parents:
diff changeset
885 do_some_other_thing()
b342dc9b52eb add document
axmo
parents:
diff changeset
886 elif index == 3:
b342dc9b52eb add document
axmo
parents:
diff changeset
887 do_something_completely_different()
b342dc9b52eb add document
axmo
parents:
diff changeset
888 instead of code like this:
b342dc9b52eb add document
axmo
parents:
diff changeset
889 try:
b342dc9b52eb add document
axmo
parents:
diff changeset
890 index = p.expect (['good', 'bad'])
b342dc9b52eb add document
axmo
parents:
diff changeset
891 if index == 0:
b342dc9b52eb add document
axmo
parents:
diff changeset
892 do_something()
b342dc9b52eb add document
axmo
parents:
diff changeset
893 elif index == 1:
b342dc9b52eb add document
axmo
parents:
diff changeset
894 do_something_else()
b342dc9b52eb add document
axmo
parents:
diff changeset
895 except EOF:
b342dc9b52eb add document
axmo
parents:
diff changeset
896 do_some_other_thing()
b342dc9b52eb add document
axmo
parents:
diff changeset
897 except TIMEOUT:
b342dc9b52eb add document
axmo
parents:
diff changeset
898 do_something_completely_different()
b342dc9b52eb add document
axmo
parents:
diff changeset
899 These two forms are equivalent. It all depends on what you want.
b342dc9b52eb add document
axmo
parents:
diff changeset
900 You can also just expect the EOF if you are waiting for all output
b342dc9b52eb add document
axmo
parents:
diff changeset
901 of a child to finish. For example:
b342dc9b52eb add document
axmo
parents:
diff changeset
902 p = pexpect.spawn('/bin/ls')
b342dc9b52eb add document
axmo
parents:
diff changeset
903 p.expect (pexpect.EOF)
b342dc9b52eb add document
axmo
parents:
diff changeset
904 print p.before
b342dc9b52eb add document
axmo
parents:
diff changeset
905
b342dc9b52eb add document
axmo
parents:
diff changeset
906 If you are trying to optimize for speed then see expect_list().
b342dc9b52eb add document
axmo
parents:
diff changeset
907 """
b342dc9b52eb add document
axmo
parents:
diff changeset
908 compiled_pattern_list = self.compile_pattern_list(pattern)
b342dc9b52eb add document
axmo
parents:
diff changeset
909 return self.expect_list(compiled_pattern_list, timeout, searchwindowsize)
b342dc9b52eb add document
axmo
parents:
diff changeset
910
b342dc9b52eb add document
axmo
parents:
diff changeset
911 def expect_list(self, pattern_list, timeout = -1, searchwindowsize = -1):
b342dc9b52eb add document
axmo
parents:
diff changeset
912 """This takes a list of compiled regular expressions and returns
b342dc9b52eb add document
axmo
parents:
diff changeset
913 the index into the pattern_list that matched the child's output.
b342dc9b52eb add document
axmo
parents:
diff changeset
914 The list may also contain EOF or TIMEOUT (which are not
b342dc9b52eb add document
axmo
parents:
diff changeset
915 compiled regular expressions). This method is similar to
b342dc9b52eb add document
axmo
parents:
diff changeset
916 the expect() method except that expect_list() does not
b342dc9b52eb add document
axmo
parents:
diff changeset
917 recompile the pattern list on every call.
b342dc9b52eb add document
axmo
parents:
diff changeset
918 This may help if you are trying to optimize for speed, otherwise
b342dc9b52eb add document
axmo
parents:
diff changeset
919 just use the expect() method. This is called by expect().
b342dc9b52eb add document
axmo
parents:
diff changeset
920 If timeout==-1 then the self.timeout value is used.
b342dc9b52eb add document
axmo
parents:
diff changeset
921 If searchwindowsize==-1 then the self.searchwindowsize value is used.
b342dc9b52eb add document
axmo
parents:
diff changeset
922 """
b342dc9b52eb add document
axmo
parents:
diff changeset
923 self.patterns = pattern_list
b342dc9b52eb add document
axmo
parents:
diff changeset
924
b342dc9b52eb add document
axmo
parents:
diff changeset
925 if timeout == -1:
b342dc9b52eb add document
axmo
parents:
diff changeset
926 timeout = self.timeout
b342dc9b52eb add document
axmo
parents:
diff changeset
927 if timeout != None:
b342dc9b52eb add document
axmo
parents:
diff changeset
928 end_time = time.time() + timeout
b342dc9b52eb add document
axmo
parents:
diff changeset
929 if searchwindowsize == -1:
b342dc9b52eb add document
axmo
parents:
diff changeset
930 searchwindowsize = self.searchwindowsize
b342dc9b52eb add document
axmo
parents:
diff changeset
931
b342dc9b52eb add document
axmo
parents:
diff changeset
932 try:
b342dc9b52eb add document
axmo
parents:
diff changeset
933 incoming = self.buffer
b342dc9b52eb add document
axmo
parents:
diff changeset
934 while 1: # Keep reading until exception or return.
b342dc9b52eb add document
axmo
parents:
diff changeset
935 # Sequence through the list of patterns looking for a match.
b342dc9b52eb add document
axmo
parents:
diff changeset
936 first_match = -1
b342dc9b52eb add document
axmo
parents:
diff changeset
937 for cre in pattern_list:
b342dc9b52eb add document
axmo
parents:
diff changeset
938 if cre is EOF or cre is TIMEOUT:
b342dc9b52eb add document
axmo
parents:
diff changeset
939 continue # The patterns for PexpectExceptions are handled differently.
b342dc9b52eb add document
axmo
parents:
diff changeset
940 if searchwindowsize is None: # search everything
b342dc9b52eb add document
axmo
parents:
diff changeset
941 match = cre.search(incoming)
b342dc9b52eb add document
axmo
parents:
diff changeset
942 else:
b342dc9b52eb add document
axmo
parents:
diff changeset
943 startpos = max(0, len(incoming) - searchwindowsize)
b342dc9b52eb add document
axmo
parents:
diff changeset
944 match = cre.search(incoming, startpos)
b342dc9b52eb add document
axmo
parents:
diff changeset
945 if match is None:
b342dc9b52eb add document
axmo
parents:
diff changeset
946 continue
b342dc9b52eb add document
axmo
parents:
diff changeset
947 if first_match > match.start() or first_match == -1:
b342dc9b52eb add document
axmo
parents:
diff changeset
948 first_match = match.start()
b342dc9b52eb add document
axmo
parents:
diff changeset
949 self.match = match
b342dc9b52eb add document
axmo
parents:
diff changeset
950 self.match_index = pattern_list.index(cre)
b342dc9b52eb add document
axmo
parents:
diff changeset
951 if first_match > -1:
b342dc9b52eb add document
axmo
parents:
diff changeset
952 self.buffer = incoming[self.match.end() : ]
b342dc9b52eb add document
axmo
parents:
diff changeset
953 self.before = incoming[ : self.match.start()]
b342dc9b52eb add document
axmo
parents:
diff changeset
954 self.after = incoming[self.match.start() : self.match.end()]
b342dc9b52eb add document
axmo
parents:
diff changeset
955 return self.match_index
b342dc9b52eb add document
axmo
parents:
diff changeset
956 # No match at this point
b342dc9b52eb add document
axmo
parents:
diff changeset
957 if timeout < 0 and timeout is not None:
b342dc9b52eb add document
axmo
parents:
diff changeset
958 raise TIMEOUT ('Timeout exceeded in expect_list().')
b342dc9b52eb add document
axmo
parents:
diff changeset
959 # Still have time left, so read more data
b342dc9b52eb add document
axmo
parents:
diff changeset
960 c = self.read_nonblocking (self.maxread, timeout)
b342dc9b52eb add document
axmo
parents:
diff changeset
961 incoming = incoming + c
b342dc9b52eb add document
axmo
parents:
diff changeset
962 if timeout is not None:
b342dc9b52eb add document
axmo
parents:
diff changeset
963 timeout = end_time - time.time()
b342dc9b52eb add document
axmo
parents:
diff changeset
964 except EOF, e:
b342dc9b52eb add document
axmo
parents:
diff changeset
965 self.buffer = ''
b342dc9b52eb add document
axmo
parents:
diff changeset
966 self.before = incoming
b342dc9b52eb add document
axmo
parents:
diff changeset
967 self.after = EOF
b342dc9b52eb add document
axmo
parents:
diff changeset
968 if EOF in pattern_list:
b342dc9b52eb add document
axmo
parents:
diff changeset
969 self.match = EOF
b342dc9b52eb add document
axmo
parents:
diff changeset
970 self.match_index = pattern_list.index(EOF)
b342dc9b52eb add document
axmo
parents:
diff changeset
971 return self.match_index
b342dc9b52eb add document
axmo
parents:
diff changeset
972 else:
b342dc9b52eb add document
axmo
parents:
diff changeset
973 self.match = None
b342dc9b52eb add document
axmo
parents:
diff changeset
974 self.match_index = None
b342dc9b52eb add document
axmo
parents:
diff changeset
975 raise EOF (str(e) + '\n' + str(self))
b342dc9b52eb add document
axmo
parents:
diff changeset
976 except TIMEOUT, e:
b342dc9b52eb add document
axmo
parents:
diff changeset
977 self.before = incoming
b342dc9b52eb add document
axmo
parents:
diff changeset
978 self.after = TIMEOUT
b342dc9b52eb add document
axmo
parents:
diff changeset
979 if TIMEOUT in pattern_list:
b342dc9b52eb add document
axmo
parents:
diff changeset
980 self.match = TIMEOUT
b342dc9b52eb add document
axmo
parents:
diff changeset
981 self.match_index = pattern_list.index(TIMEOUT)
b342dc9b52eb add document
axmo
parents:
diff changeset
982 return self.match_index
b342dc9b52eb add document
axmo
parents:
diff changeset
983 else:
b342dc9b52eb add document
axmo
parents:
diff changeset
984 self.match = None
b342dc9b52eb add document
axmo
parents:
diff changeset
985 self.match_index = None
b342dc9b52eb add document
axmo
parents:
diff changeset
986 raise TIMEOUT (str(e) + '\n' + str(self))
b342dc9b52eb add document
axmo
parents:
diff changeset
987 except Exception:
b342dc9b52eb add document
axmo
parents:
diff changeset
988 self.before = incoming
b342dc9b52eb add document
axmo
parents:
diff changeset
989 self.after = None
b342dc9b52eb add document
axmo
parents:
diff changeset
990 self.match = None
b342dc9b52eb add document
axmo
parents:
diff changeset
991 self.match_index = None
b342dc9b52eb add document
axmo
parents:
diff changeset
992 raise
b342dc9b52eb add document
axmo
parents:
diff changeset
993
b342dc9b52eb add document
axmo
parents:
diff changeset
994 def getwinsize(self):
b342dc9b52eb add document
axmo
parents:
diff changeset
995 """This returns the window size of the child tty.
b342dc9b52eb add document
axmo
parents:
diff changeset
996 The return value is a tuple of (rows, cols).
b342dc9b52eb add document
axmo
parents:
diff changeset
997 """
b342dc9b52eb add document
axmo
parents:
diff changeset
998 if 'TIOCGWINSZ' in dir(termios):
b342dc9b52eb add document
axmo
parents:
diff changeset
999 TIOCGWINSZ = termios.TIOCGWINSZ
b342dc9b52eb add document
axmo
parents:
diff changeset
1000 else:
b342dc9b52eb add document
axmo
parents:
diff changeset
1001 TIOCGWINSZ = 1074295912L # Assume
b342dc9b52eb add document
axmo
parents:
diff changeset
1002 s = struct.pack('HHHH', 0, 0, 0, 0)
b342dc9b52eb add document
axmo
parents:
diff changeset
1003 x = fcntl.ioctl(self.fileno(), TIOCGWINSZ, s)
b342dc9b52eb add document
axmo
parents:
diff changeset
1004 return struct.unpack('HHHH', x)[0:2]
b342dc9b52eb add document
axmo
parents:
diff changeset
1005
b342dc9b52eb add document
axmo
parents:
diff changeset
1006 def setwinsize(self, r, c):
b342dc9b52eb add document
axmo
parents:
diff changeset
1007 """This sets the window size of the child tty.
b342dc9b52eb add document
axmo
parents:
diff changeset
1008 This will cause a SIGWINCH signal to be sent to the child.
b342dc9b52eb add document
axmo
parents:
diff changeset
1009 This does not change the physical window size.
b342dc9b52eb add document
axmo
parents:
diff changeset
1010 It changes the size reported to TTY-aware applications like
b342dc9b52eb add document
axmo
parents:
diff changeset
1011 vi or curses -- applications that respond to the SIGWINCH signal.
b342dc9b52eb add document
axmo
parents:
diff changeset
1012 """
b342dc9b52eb add document
axmo
parents:
diff changeset
1013 # Check for buggy platforms. Some Python versions on some platforms
b342dc9b52eb add document
axmo
parents:
diff changeset
1014 # (notably OSF1 Alpha and RedHat 7.1) truncate the value for
b342dc9b52eb add document
axmo
parents:
diff changeset
1015 # termios.TIOCSWINSZ. It is not clear why this happens.
b342dc9b52eb add document
axmo
parents:
diff changeset
1016 # These platforms don't seem to handle the signed int very well;
b342dc9b52eb add document
axmo
parents:
diff changeset
1017 # yet other platforms like OpenBSD have a large negative value for
b342dc9b52eb add document
axmo
parents:
diff changeset
1018 # TIOCSWINSZ and they don't have a truncate problem.
b342dc9b52eb add document
axmo
parents:
diff changeset
1019 # Newer versions of Linux have totally different values for TIOCSWINSZ.
b342dc9b52eb add document
axmo
parents:
diff changeset
1020 # Note that this fix is a hack.
b342dc9b52eb add document
axmo
parents:
diff changeset
1021 if 'TIOCSWINSZ' in dir(termios):
b342dc9b52eb add document
axmo
parents:
diff changeset
1022 TIOCSWINSZ = termios.TIOCSWINSZ
b342dc9b52eb add document
axmo
parents:
diff changeset
1023 else:
b342dc9b52eb add document
axmo
parents:
diff changeset
1024 TIOCSWINSZ = -2146929561
b342dc9b52eb add document
axmo
parents:
diff changeset
1025 if TIOCSWINSZ == 2148037735L: # L is not required in Python >= 2.2.
b342dc9b52eb add document
axmo
parents:
diff changeset
1026 TIOCSWINSZ = -2146929561 # Same bits, but with sign.
b342dc9b52eb add document
axmo
parents:
diff changeset
1027 # Note, assume ws_xpixel and ws_ypixel are zero.
b342dc9b52eb add document
axmo
parents:
diff changeset
1028 s = struct.pack('HHHH', r, c, 0, 0)
b342dc9b52eb add document
axmo
parents:
diff changeset
1029 fcntl.ioctl(self.fileno(), TIOCSWINSZ, s)
b342dc9b52eb add document
axmo
parents:
diff changeset
1030
b342dc9b52eb add document
axmo
parents:
diff changeset
1031 def interact(self, escape_character = chr(29)):
b342dc9b52eb add document
axmo
parents:
diff changeset
1032 """This gives control of the child process to the interactive user
b342dc9b52eb add document
axmo
parents:
diff changeset
1033 (the human at the keyboard).
b342dc9b52eb add document
axmo
parents:
diff changeset
1034 Keystrokes are sent to the child process, and the stdout and stderr
b342dc9b52eb add document
axmo
parents:
diff changeset
1035 output of the child process is printed.
b342dc9b52eb add document
axmo
parents:
diff changeset
1036 When the user types the escape_character this method will stop.
b342dc9b52eb add document
axmo
parents:
diff changeset
1037 The default for escape_character is ^] (ASCII 29).
b342dc9b52eb add document
axmo
parents:
diff changeset
1038 This simply echos the child stdout and child stderr to the real
b342dc9b52eb add document
axmo
parents:
diff changeset
1039 stdout and it echos the real stdin to the child stdin.
b342dc9b52eb add document
axmo
parents:
diff changeset
1040
b342dc9b52eb add document
axmo
parents:
diff changeset
1041 Note that if you change the window size of the parent
b342dc9b52eb add document
axmo
parents:
diff changeset
1042 the SIGWINCH signal will not be passed through to the child.
b342dc9b52eb add document
axmo
parents:
diff changeset
1043 If you want the child window size to change when the parent's
b342dc9b52eb add document
axmo
parents:
diff changeset
1044 window size changes then do something like the following example:
b342dc9b52eb add document
axmo
parents:
diff changeset
1045 import pexpect, struct, fcntl, termios, signal, sys
b342dc9b52eb add document
axmo
parents:
diff changeset
1046 def sigwinch_passthrough (sig, data):
b342dc9b52eb add document
axmo
parents:
diff changeset
1047 s = struct.pack("HHHH", 0, 0, 0, 0)
b342dc9b52eb add document
axmo
parents:
diff changeset
1048 a = struct.unpack('hhhh', fcntl.ioctl(sys.stdout.fileno(), termios.TIOCGWINSZ , s))
b342dc9b52eb add document
axmo
parents:
diff changeset
1049 global p
b342dc9b52eb add document
axmo
parents:
diff changeset
1050 p.setwinsize(a[0],a[1])
b342dc9b52eb add document
axmo
parents:
diff changeset
1051 p = pexpect.spawn('/bin/bash') # Note this is global
b342dc9b52eb add document
axmo
parents:
diff changeset
1052 signal.signal(signal.SIGWINCH, sigwinch_passthrough)
b342dc9b52eb add document
axmo
parents:
diff changeset
1053 p.interact()
b342dc9b52eb add document
axmo
parents:
diff changeset
1054 """
b342dc9b52eb add document
axmo
parents:
diff changeset
1055 # Flush the buffer.
b342dc9b52eb add document
axmo
parents:
diff changeset
1056 self.stdout.write (self.buffer)
b342dc9b52eb add document
axmo
parents:
diff changeset
1057 self.stdout.flush()
b342dc9b52eb add document
axmo
parents:
diff changeset
1058 self.buffer = ''
b342dc9b52eb add document
axmo
parents:
diff changeset
1059 mode = tty.tcgetattr(self.STDIN_FILENO)
b342dc9b52eb add document
axmo
parents:
diff changeset
1060 tty.setraw(self.STDIN_FILENO)
b342dc9b52eb add document
axmo
parents:
diff changeset
1061 try:
b342dc9b52eb add document
axmo
parents:
diff changeset
1062 self.__interact_copy(escape_character)
b342dc9b52eb add document
axmo
parents:
diff changeset
1063 finally:
b342dc9b52eb add document
axmo
parents:
diff changeset
1064 tty.tcsetattr(self.STDIN_FILENO, tty.TCSAFLUSH, mode)
b342dc9b52eb add document
axmo
parents:
diff changeset
1065
b342dc9b52eb add document
axmo
parents:
diff changeset
1066 def __interact_writen(self, fd, data):
b342dc9b52eb add document
axmo
parents:
diff changeset
1067 """This is used by the interact() method.
b342dc9b52eb add document
axmo
parents:
diff changeset
1068 """
b342dc9b52eb add document
axmo
parents:
diff changeset
1069 while data != '' and self.isalive():
b342dc9b52eb add document
axmo
parents:
diff changeset
1070 n = os.write(fd, data)
b342dc9b52eb add document
axmo
parents:
diff changeset
1071 data = data[n:]
b342dc9b52eb add document
axmo
parents:
diff changeset
1072 def __interact_read(self, fd):
b342dc9b52eb add document
axmo
parents:
diff changeset
1073 """This is used by the interact() method.
b342dc9b52eb add document
axmo
parents:
diff changeset
1074 """
b342dc9b52eb add document
axmo
parents:
diff changeset
1075 return os.read(fd, 1000)
b342dc9b52eb add document
axmo
parents:
diff changeset
1076 def __interact_copy(self, escape_character = None):
b342dc9b52eb add document
axmo
parents:
diff changeset
1077 """This is used by the interact() method.
b342dc9b52eb add document
axmo
parents:
diff changeset
1078 """
b342dc9b52eb add document
axmo
parents:
diff changeset
1079 while self.isalive():
b342dc9b52eb add document
axmo
parents:
diff changeset
1080 try:
b342dc9b52eb add document
axmo
parents:
diff changeset
1081 r, w, e = select.select([self.child_fd, self.STDIN_FILENO], [], [])
b342dc9b52eb add document
axmo
parents:
diff changeset
1082 except select.errno, e:
b342dc9b52eb add document
axmo
parents:
diff changeset
1083 if e[0] != errno.EINTR:
b342dc9b52eb add document
axmo
parents:
diff changeset
1084 raise
b342dc9b52eb add document
axmo
parents:
diff changeset
1085 if self.child_fd in r:
b342dc9b52eb add document
axmo
parents:
diff changeset
1086 data = self.__interact_read(self.child_fd)
b342dc9b52eb add document
axmo
parents:
diff changeset
1087 if self.logfile != None:
b342dc9b52eb add document
axmo
parents:
diff changeset
1088 self.logfile.write (data)
b342dc9b52eb add document
axmo
parents:
diff changeset
1089 self.logfile.flush()
b342dc9b52eb add document
axmo
parents:
diff changeset
1090 os.write(self.STDOUT_FILENO, data)
b342dc9b52eb add document
axmo
parents:
diff changeset
1091 if self.STDIN_FILENO in r:
b342dc9b52eb add document
axmo
parents:
diff changeset
1092 data = self.__interact_read(self.STDIN_FILENO)
b342dc9b52eb add document
axmo
parents:
diff changeset
1093 self.__interact_writen(self.child_fd, data)
b342dc9b52eb add document
axmo
parents:
diff changeset
1094 if escape_character in data:
b342dc9b52eb add document
axmo
parents:
diff changeset
1095 break
b342dc9b52eb add document
axmo
parents:
diff changeset
1096 ##############################################################################
b342dc9b52eb add document
axmo
parents:
diff changeset
1097 # The following methods are no longer supported or allowed..
b342dc9b52eb add document
axmo
parents:
diff changeset
1098 def setmaxread (self, maxread):
b342dc9b52eb add document
axmo
parents:
diff changeset
1099 """This method is no longer supported or allowed.
b342dc9b52eb add document
axmo
parents:
diff changeset
1100 I don't like getters and setters without a good reason.
b342dc9b52eb add document
axmo
parents:
diff changeset
1101 """
b342dc9b52eb add document
axmo
parents:
diff changeset
1102 raise ExceptionPexpect ('This method is no longer supported or allowed. Just assign a value to the maxread member variable.')
b342dc9b52eb add document
axmo
parents:
diff changeset
1103 def expect_exact (self, pattern_list, timeout = -1):
b342dc9b52eb add document
axmo
parents:
diff changeset
1104 """This method is no longer supported or allowed.
b342dc9b52eb add document
axmo
parents:
diff changeset
1105 It was too hard to maintain and keep it up to date with expect_list.
b342dc9b52eb add document
axmo
parents:
diff changeset
1106 Few people used this method. Most people favored reliability over speed.
b342dc9b52eb add document
axmo
parents:
diff changeset
1107 The implementation is left in comments in case anyone needs to hack this
b342dc9b52eb add document
axmo
parents:
diff changeset
1108 feature back into their copy.
b342dc9b52eb add document
axmo
parents:
diff changeset
1109 If someone wants to diff this with expect_list and make them work
b342dc9b52eb add document
axmo
parents:
diff changeset
1110 nearly the same then I will consider adding this make in.
b342dc9b52eb add document
axmo
parents:
diff changeset
1111 """
b342dc9b52eb add document
axmo
parents:
diff changeset
1112 raise ExceptionPexpect ('This method is no longer supported or allowed.')
b342dc9b52eb add document
axmo
parents:
diff changeset
1113 def setlog (self, fileobject):
b342dc9b52eb add document
axmo
parents:
diff changeset
1114 """This method is no longer supported or allowed.
b342dc9b52eb add document
axmo
parents:
diff changeset
1115 """
b342dc9b52eb add document
axmo
parents:
diff changeset
1116 raise ExceptionPexpect ('This method is no longer supported or allowed. Just assign a value to the logfile member variable.')
b342dc9b52eb add document
axmo
parents:
diff changeset
1117
b342dc9b52eb add document
axmo
parents:
diff changeset
1118 ##############################################################################
b342dc9b52eb add document
axmo
parents:
diff changeset
1119 # End of spawn class
b342dc9b52eb add document
axmo
parents:
diff changeset
1120 ##############################################################################
b342dc9b52eb add document
axmo
parents:
diff changeset
1121
b342dc9b52eb add document
axmo
parents:
diff changeset
1122 def which (filename):
b342dc9b52eb add document
axmo
parents:
diff changeset
1123 """This takes a given filename; tries to find it in the environment path;
b342dc9b52eb add document
axmo
parents:
diff changeset
1124 then checks if it is executable.
b342dc9b52eb add document
axmo
parents:
diff changeset
1125 This returns the full path to the filename if found and executable.
b342dc9b52eb add document
axmo
parents:
diff changeset
1126 Otherwise this returns None.
b342dc9b52eb add document
axmo
parents:
diff changeset
1127 """
b342dc9b52eb add document
axmo
parents:
diff changeset
1128 # Special case where filename already contains a path.
b342dc9b52eb add document
axmo
parents:
diff changeset
1129 if os.path.dirname(filename) != '':
b342dc9b52eb add document
axmo
parents:
diff changeset
1130 if os.access (filename, os.X_OK):
b342dc9b52eb add document
axmo
parents:
diff changeset
1131 return filename
b342dc9b52eb add document
axmo
parents:
diff changeset
1132
b342dc9b52eb add document
axmo
parents:
diff changeset
1133 if not os.environ.has_key('PATH') or os.environ['PATH'] == '':
b342dc9b52eb add document
axmo
parents:
diff changeset
1134 p = os.defpath
b342dc9b52eb add document
axmo
parents:
diff changeset
1135 else:
b342dc9b52eb add document
axmo
parents:
diff changeset
1136 p = os.environ['PATH']
b342dc9b52eb add document
axmo
parents:
diff changeset
1137
b342dc9b52eb add document
axmo
parents:
diff changeset
1138 # Oddly enough this was the one line that made Pexpect
b342dc9b52eb add document
axmo
parents:
diff changeset
1139 # incompatible with Python 1.5.2.
b342dc9b52eb add document
axmo
parents:
diff changeset
1140 #pathlist = p.split (os.pathsep)
b342dc9b52eb add document
axmo
parents:
diff changeset
1141 pathlist = string.split (p, os.pathsep)
b342dc9b52eb add document
axmo
parents:
diff changeset
1142
b342dc9b52eb add document
axmo
parents:
diff changeset
1143 for path in pathlist:
b342dc9b52eb add document
axmo
parents:
diff changeset
1144 f = os.path.join(path, filename)
b342dc9b52eb add document
axmo
parents:
diff changeset
1145 if os.access(f, os.X_OK):
b342dc9b52eb add document
axmo
parents:
diff changeset
1146 return f
b342dc9b52eb add document
axmo
parents:
diff changeset
1147 return None
b342dc9b52eb add document
axmo
parents:
diff changeset
1148
b342dc9b52eb add document
axmo
parents:
diff changeset
1149 def split_command_line(command_line):
b342dc9b52eb add document
axmo
parents:
diff changeset
1150 """This splits a command line into a list of arguments.
b342dc9b52eb add document
axmo
parents:
diff changeset
1151 It splits arguments on spaces, but handles
b342dc9b52eb add document
axmo
parents:
diff changeset
1152 embedded quotes, doublequotes, and escaped characters.
b342dc9b52eb add document
axmo
parents:
diff changeset
1153 It's impossible to do this with a regular expression, so
b342dc9b52eb add document
axmo
parents:
diff changeset
1154 I wrote a little state machine to parse the command line.
b342dc9b52eb add document
axmo
parents:
diff changeset
1155 """
b342dc9b52eb add document
axmo
parents:
diff changeset
1156 arg_list = []
b342dc9b52eb add document
axmo
parents:
diff changeset
1157 arg = ''
b342dc9b52eb add document
axmo
parents:
diff changeset
1158
b342dc9b52eb add document
axmo
parents:
diff changeset
1159 # Constants to name the states we can be in.
b342dc9b52eb add document
axmo
parents:
diff changeset
1160 state_basic = 0
b342dc9b52eb add document
axmo
parents:
diff changeset
1161 state_esc = 1
b342dc9b52eb add document
axmo
parents:
diff changeset
1162 state_singlequote = 2
b342dc9b52eb add document
axmo
parents:
diff changeset
1163 state_doublequote = 3
b342dc9b52eb add document
axmo
parents:
diff changeset
1164 state_whitespace = 4 # The state of consuming whitespace between commands.
b342dc9b52eb add document
axmo
parents:
diff changeset
1165 state = state_basic
b342dc9b52eb add document
axmo
parents:
diff changeset
1166
b342dc9b52eb add document
axmo
parents:
diff changeset
1167 for c in command_line:
b342dc9b52eb add document
axmo
parents:
diff changeset
1168 if state == state_basic or state == state_whitespace:
b342dc9b52eb add document
axmo
parents:
diff changeset
1169 if c == '\\': # Escape the next character
b342dc9b52eb add document
axmo
parents:
diff changeset
1170 state = state_esc
b342dc9b52eb add document
axmo
parents:
diff changeset
1171 elif c == r"'": # Handle single quote
b342dc9b52eb add document
axmo
parents:
diff changeset
1172 state = state_singlequote
b342dc9b52eb add document
axmo
parents:
diff changeset
1173 elif c == r'"': # Handle double quote
b342dc9b52eb add document
axmo
parents:
diff changeset
1174 state = state_doublequote
b342dc9b52eb add document
axmo
parents:
diff changeset
1175 elif c.isspace():
b342dc9b52eb add document
axmo
parents:
diff changeset
1176 # Add arg to arg_list if we aren't in the middle of whitespace.
b342dc9b52eb add document
axmo
parents:
diff changeset
1177 if state == state_whitespace:
b342dc9b52eb add document
axmo
parents:
diff changeset
1178 None # Do nothing.
b342dc9b52eb add document
axmo
parents:
diff changeset
1179 else:
b342dc9b52eb add document
axmo
parents:
diff changeset
1180 arg_list.append(arg)
b342dc9b52eb add document
axmo
parents:
diff changeset
1181 arg = ''
b342dc9b52eb add document
axmo
parents:
diff changeset
1182 state = state_whitespace
b342dc9b52eb add document
axmo
parents:
diff changeset
1183 else:
b342dc9b52eb add document
axmo
parents:
diff changeset
1184 arg = arg + c
b342dc9b52eb add document
axmo
parents:
diff changeset
1185 state = state_basic
b342dc9b52eb add document
axmo
parents:
diff changeset
1186 elif state == state_esc:
b342dc9b52eb add document
axmo
parents:
diff changeset
1187 arg = arg + c
b342dc9b52eb add document
axmo
parents:
diff changeset
1188 state = state_basic
b342dc9b52eb add document
axmo
parents:
diff changeset
1189 elif state == state_singlequote:
b342dc9b52eb add document
axmo
parents:
diff changeset
1190 if c == r"'":
b342dc9b52eb add document
axmo
parents:
diff changeset
1191 state = state_basic
b342dc9b52eb add document
axmo
parents:
diff changeset
1192 else:
b342dc9b52eb add document
axmo
parents:
diff changeset
1193 arg = arg + c
b342dc9b52eb add document
axmo
parents:
diff changeset
1194 elif state == state_doublequote:
b342dc9b52eb add document
axmo
parents:
diff changeset
1195 if c == r'"':
b342dc9b52eb add document
axmo
parents:
diff changeset
1196 state = state_basic
b342dc9b52eb add document
axmo
parents:
diff changeset
1197 else:
b342dc9b52eb add document
axmo
parents:
diff changeset
1198 arg = arg + c
b342dc9b52eb add document
axmo
parents:
diff changeset
1199
b342dc9b52eb add document
axmo
parents:
diff changeset
1200 if arg != '':
b342dc9b52eb add document
axmo
parents:
diff changeset
1201 arg_list.append(arg)
b342dc9b52eb add document
axmo
parents:
diff changeset
1202 return arg_list
b342dc9b52eb add document
axmo
parents:
diff changeset
1203