1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306
|
Contents:
---------
* Contents:
* Expect Module for Python
* FTP:
* Example:
* Classes:
* How it works:
* Invocation:
* Methods:
* Backquote notation:
* Intricacies:
* Reading regular expressions:
Expect Module for Python
------------------------
This is Python module that does most of what you would normally
need from Tcl's expect, but it works like a standard popen(1)
call but with BOTH reading AND writing.
Example:
--------
#!/usr/bin/python
import sys
from expect import *
f = popen2 ("passwd " + sys.argv[1])
print f.read ("word: ")
f.write (sys.argv[2])
print f.read ("word: ")
f.write (sys.argv[2])
print f.read ()
or
#!/usr/bin/python
import sys, time
from expect import *
f = popen2 ("passwd " + sys.argv[1], "p")
print f.read (": ")
time.sleep (0.1)
f.write (sys.argv[2] + "\r\n")
print f.read (":")
time.sleep (0.1)
f.write (sys.argv[2] + "\r\n")
print f.read()
Classes:
--------
There are three classes defined by this module:
popen - this is like a standard UNIX popen command
the difference being that you can both read
and write to the result file object. The stderr
stream of the process is NOT redirected and
will hence appear on the terminal exactly like
with popen or back-quotes under sh.
popen2 - like popen, but both stderr AND stdout of the
process can be read through the same pipe. i.e.
f.read() calls return ALL output of the process.
popen3 - like popen2, but stderr and stdout are read
through two separate functions: f.read()
returns stdout of the process. f.read_error()
returns stderr.
How it works:
-------------
This is a completely standalone implementation of popen. It does
not rely on the existing popen in any way.
The problem with reading and writing to a process is that it is
easy to write code that blocks indefinitely waiting for IO.
This library works by queueing reads when doing either a read or
a write call. Read operations are buffered so that incoming data
(the stderr and stdout of the process) are queued in
anticipation of any future read(). write() operations are
unbuffered.
This allows you to arbitrarily read to and write from a process
without worrying about an indefinite block. It is hence very
similar to Tcl's expect program.
Invocation:
-----------
f = popen (command, options)
f = popen2 (command, options)
f = popen3 (command, options)
command is a string. command is a shell program passed as <arg> to
/bin/sh -c <arg>
options is a string. If options contains the character `b' then the
blocking is turned off. read() and write() will then not block waiting
for data. This is untested.
If options contains the character `p', then a pseudo tty is
opened for the process. The process will still inherit all
environment variables, hence for consistent behaviour, the
caller may want to explicitly set the TERM environment variable.
Note that many programs follow different behaviour depending on
whether they are attached to a tty or not.
In the passwd examples above, passwd is happy to read from a
pipe. If you use a terminal (`p') then you are required to send
a '\n' at the end of the line, and pause a small amount while
the getpass C library function switches into ICANON mode
(whatever that is) causing passwd to raw read separately from
the normal read queue.
All other letters passed to options are ignored.
Methods:
--------
f.read (integer)
* Can take a normal integer to read a finite amount of data in the
same way as usual file object's read does.
f.read ()
* If no arguments are passed, then this reads as much data as is
outputted by the process, blocking until it reads nothing
(i.e. the process has exited).
f.read (string)
* If a single string is passed, then read() reads up to and
including the matching string.
f.read ((string, string, ...))
* If a tuple of strings are passed, then read() reads up to and
including the first matching string.
f.read_error ()
* works just like read. Typically you would check for errors with
read_error() after calling read().
f.close ()
* closes all pipes and returns the exit code of the process. If
the process has been killed, then this raises an error giving
the terminating signal.
f.flush ()
* does nothing
f.isatty ()
* returns 0
f.readline ()
* reads up to an including a newline character. takes no arguments
f.readlines ()
* analogous to file objects readline(). takes no arguments
f.seek (offset, whence)
* reads and discards offset amount of data. whence must be 1.
returns nothing
f.tell ()
* returns the total amount of data read from stdout (or in the case
of popen2) from stdout and stderr.
f.writelines (list)
* analogous to file objects writelines (). returns nothing.
f.pid ()
* get the pid of the child process. Returns -1 if the child
has died.
f.fds ()
* get the stdin, stdout and stderr file descriptors as a tuple.
f.setblocking (block)
* takes an integer. 1 turns blocking on, 0 turns blocking off.
This overrides the options string. This is untested: rather
use settimeout(). setblocking(0) takes priority over
settimeout(anything).
f.settimeout (seconds)
* takes a float. sets the timeout to this many seconds or
fraction thereof. Tested only with reading but should work
fine with writing. If a read waits longer than this
for data, than it returns, raising an IO error. If timeout()
receives no arguments, it resets to no timeout - i.e.
indefinite blocking.
f.command
* a copy of the command.
Backquote notation:
-------------------
Backquotes work the same as in sh. It does this by binding the
the __repr__ method. Hence
a=`popen ("echo hello")`
Works just like
a=`echo hello`
under a sh or perl.
Intricacies:
------------
- To avoid invocation of /bin/sh, popen checks if the command
contains any shell special characters i.e. > ` ! < & $ \n ;
( ) { } and then, failing this, tries to interpret the
command-line by itself, following the exact conventions of
bash. If you are not convinced that this has the same behaviour,
add in a ; at the end of your command to force use of /bin/sh.
- If you try to close a process that has stopped or still executing,
close() will block waiting for the process to die.
- del f is just like f.close(), but sends the process the
SIGTERM signal before blocking waiting for the child to die.
Since a process can intercept the SIGTERM signal, its is
still possible for Python to block at an arbitrary location.
For instance:
def func ():
f = popen2 ("prog")
time.sleep (0.1)
func ()
If prog were to ignore SIGTERM, then func would block until
prog had exited because python dereferences f before
returning from func.
(The reason you need to sleep(0.1) is to give prog a chance
to set its signal handlers.)
You can REALLY kill a program by getting it is pid and
sending it the SIGKILL signal.
- f.p is the internal object that you would normally not be
interested in. However `f.p` prints useful output like:
f = popen2 ("echo 'Hi there!'")
print `f.p`
<ExpectObject running command "echo 'Hi there!'" as
pid 10373 at 80b30c0>
- You can carry on reading from a process even after it has
died and been close()'d. So long as there is still data
in the queue. If there is no data, read just returns an
empty string.
- Opening a pty currently works BSD style using /dev/pty??
To support other kinds, I'll probably copy some of the
rxvt code across. At the moment it works under Solaris
and Linux, (and I assume all BSD variants).
Reading regular expressions:
----------------------------
Reading of regular expressions is not implemented in C, but
can be easily implemented in Python. Simply write a function
which reads up until the last character of a regular expression
and then compares the found data against it.
Please feel free to send a method which implements this for
inclusion into the distribution.
For instance:
...
s = f.read ("(this|that|sh[aeiou]*p)")
...
------->
...
# this is off the top of my head: i.e. untested
s = ""
p = re.compile ("(this|that|sh[aeiou]*p)")
while 1:
s = s + f.read (("s", "t", "p"))
if p.match (s)
break
...
|