diff options
author | noah <noah@656d521f-e311-0410-88e0-e7920216d269> | 2005-11-17 16:03:47 +0000 |
---|---|---|
committer | noah <noah@656d521f-e311-0410-88e0-e7920216d269> | 2005-11-17 16:03:47 +0000 |
commit | f4f9260ee3214bcbfec0e1ece60d8f5aee9b3921 (patch) | |
tree | 7bd4c7985c4db60a97dfa2d048c6a26e47e867f4 | |
parent | 9c6e247b3d86813f3cd7e3f2fc3389fde8b65903 (diff) | |
download | pexpect-f4f9260ee3214bcbfec0e1ece60d8f5aee9b3921.tar.gz |
Cleaning up docs
git-svn-id: http://pexpect.svn.sourceforge.net/svnroot/pexpect/trunk@338 656d521f-e311-0410-88e0-e7920216d269
-rw-r--r-- | pexpect/Makefile | 6 | ||||
-rw-r--r-- | pexpect/doc/clean.css | 103 | ||||
-rw-r--r-- | pexpect/doc/email.png | bin | 0 -> 321 bytes | |||
-rw-r--r-- | pexpect/doc/index.html | 919 | ||||
-rwxr-xr-x | pexpect/tools/websync.py | 4 |
5 files changed, 1002 insertions, 30 deletions
diff --git a/pexpect/Makefile b/pexpect/Makefile index c737ed9..a73550d 100644 --- a/pexpect/Makefile +++ b/pexpect/Makefile @@ -45,9 +45,9 @@ pexpect-doc.tgz: doc/* -rm -f `ls doc/*.html | sed -e 's/doc\/index\.html//'` #$(DOCGENERATOR) `echo "$(MANIFEST_LINES)" | sed -e "s/\.py//g" -e "s/setup *//" -e "s/README *//"` #mv *.html doc/ - cd doc - $(DOCGENERATOR) ../pexpect.py ../pxssh.py ../FSM.py ../ANSI.py ../screen.py - cd .. + cd doc;\ + $(DOCGENERATOR) ../pexpect.py ../pxssh.py ../FSM.py ../ANSI.py ../screen.py;\ + cd ..;\ tar zcf pexpect-doc.tgz doc/ examples: pexpect-examples.tgz diff --git a/pexpect/doc/clean.css b/pexpect/doc/clean.css new file mode 100644 index 0000000..596112b --- /dev/null +++ b/pexpect/doc/clean.css @@ -0,0 +1,103 @@ + +body { + margin:0px; + padding:0px; + font-family:verdana, arial, helvetica, sans-serif; + color:#333; + background-color:white; + } +pre { + background: #eeeeee; + border: 1px solid #888888; + color: black; + padding: 1em; + white-space: pre; +} +h1 { + margin:5px 0px 5px 0px; + padding:0px; + font-size:20px; + line-height:28px; + font-weight:900; + color:#44f; + } +h2 { + margin:5px 0px 5px 0px; + padding:0px; + font-size:17px; + line-height:28px; + font-weight:900; + color:#226; + } +h3 { + margin:5px 0px 5px 0px; + padding:0px; + font-size:15px; + line-height:28px; + font-weight:900; + } +p +{ + font:11px/20px verdana, arial, helvetica, sans-serif; + margin:0px 0px 16px 0px; + padding:0px; +} +table +{ + font-size: 10pt; + color: #000000; +} +td{border:1px solid #999;} + +table.pymenu {color: #000000; background-color: #99ccff} +th.pymenu {color: #ffffff; background-color: #003366} + +.code +{ + font-family: "Lucida Console", monospace; font-weight: bold; + color: #007700; background-color: #dddddd +} + +#Content>p {margin:0px;} +#Content>p+p {text-indent:30px;} + +a { + text-decoration:none; + font-weight:600; + font-family:verdana, arial, helvetica, sans-serif; + color: #900; +} +//a:link {color:#09c;} +//a x:visited {color:#07a;} +a:hover {background-color:#ee0;} + +#Header { + margin:10px 0px 10px 0px; + padding:10px 0px 10px 20px; + /* For IE5/Win's benefit height = [correct height] + [top padding] + [top and bottom border widths] */ + height:33px; /* 14px + 17px + 2px = 33px */ + border-style:solid; + border-color:black; + border-width:1px 0px; /* top and bottom borders: 1px; left and right borders: 0px */ + line-height:33px; + background-color:#eee; + height:66px; /* the correct height */ + } + +#Content { + margin:0px 210px 50px 10px; + padding:10px; + } + +#Menu { + position:absolute; + top:100px; + right:20px; + width:172px; + padding:10px; + background-color:#eee; + border:1px solid #999; // dashed #999; + line-height:17px; + width:150px; + font-size:11px; + } diff --git a/pexpect/doc/email.png b/pexpect/doc/email.png Binary files differnew file mode 100644 index 0000000..cc60459 --- /dev/null +++ b/pexpect/doc/email.png diff --git a/pexpect/doc/index.html b/pexpect/doc/index.html index e93cec7..6f41308 100644 --- a/pexpect/doc/index.html +++ b/pexpect/doc/index.html @@ -1,31 +1,900 @@ -<!doctype html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> -<html><head><title>Pexpect Documentation</title> -<style type="text/css"><!-- -TT { font-family: lucidatypewriter, lucida console, courier } ---></style></head><body bgcolor="#f0f0f8"> - -<table width="100%" cellspacing=0 cellpadding=2 border=0 summary="heading"> -<tr bgcolor="#7799ee"> -<td valign=bottom> <br> -<font color="#ffffff" face="helvetica, arial"> <br><big><big><strong>pexpect</strong></big> -</big></font></td><td align=right valign=bottom> -</td></tr></table> - -<table width="100%" cellspacing=0 cellpadding=2 border=0 summary="section"> -<tr bgcolor="#aa55cc"> -<td colspan=3 valign=bottom> <br> -<font color="#fffff" face="helvetica, arial"><big><strong>Modules</strong></big></font></td></tr> - -<tr><td bgcolor="#aa55cc"><tt> </tt> -</td><td> </td> -<td width="100%"><table width="100%" summary="list"> +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> +<html> +<head> +<title>Pexpect - a Pure Python Expect-like module</title> +<link rel="stylesheet" href="clean.css" type="text/css"> +<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> +<meta name="Author" content="Noah Spurrier"> +<meta name="Keywords" + content="pexpect, Noah Spurrier, pypect, Python, Libes, TCL, Expect, pipe, popen, pyExpect, expectpy, expect-like, expect-alike, expect like"> +<meta name="Description" + content="Pexpect is a pure Python Expect-like module. Pexpect makes Python a better tool for controlling other applications."> +</head> +<body bgcolor="#ffffff" text="#000000"> +<div id="Header"> +<h1>Pexpect version 2.0<br> +a Pure Python Expect-like module +</h1> +</div> +<div id="Content"> +<p>Pexpect makes Python a better tool for controlling other +applications.</p> +<p>Pexpect is a pure Python module for spawning child applications; +controlling them; and responding to expected patterns in their output. +Pexpect works like Don Libes' Expect. Pexpect allows your script to +spawn a child application and control it as if a human were typing +commands.</p> +<p>Pexpect can be used for automating interactive applications such as +ssh, ftp, passwd, telnet, etc. It can be used to a automate setup +scripts for duplicating software package installations on different +servers. It can be used for automated software testing. Pexpect is in +the spirit of Don Libes' Expect, but Pexpect is pure Python. Unlike +other Expect-like modules for Python, Pexpect does not require TCL or +Expect nor does it require C extensions to be compiled. It should work +on any platform that supports the standard Python pty module. The +Pexpect interface was designed to be easy to use.</p> +<table border="0"> + <tbody> + <tr> + <td align="right" valign="top">Send questions to:</td> + <td align="left"><a href="http://www.noah.org/email/"><img + src="email.png" alt="Click to send email." border="0" height="16" + width="100"></a></td> + </tr> + </tbody> +</table> +<hr noshade="noshade" size="1"> +<h1><a name="license"></a>License</h1> +<p>Pexpect is Open Source, free, and all that stuff.<br> +It is licensed under the <a + href="http://www.opensource.org/licenses/PythonSoftFoundation.html">Python +Software Foundation License</a>.</p> +<hr noshade="noshade" size="1"> +<h1><a name="download"></a><a + href="http://sourceforge.net/project/showfiles.php?group_id=59762">Download</a></h1> +<p>Download the <a + href="http://sourceforge.net/project/showfiles.php?group_id=59762"> +current version here</a> from the SourceForge site. Grab the tarball <span + class="code">pexpect-current.tgz</span>. You should also grab the <span + class="code">pexpect-examples.tgz</span> tarball as this is the best +way to learn to use Pexpect.</p> +<h2>Installing Pexpect</h2> +<p>The <span class="code">pexpect-current.tgz</span> tarball is a +standard Python Distutil distribution.</p> +<ol> + <li>download <span class="code">pexpect-current.tgz</span></li> + <li><span class="code">tar zxf pexpect-current.tgz</span></li> + <li><span class="code">cd pexpect-current</span></li> + <li><span class="code">python setup.py install</span></li> +</ol> +<hr noshade="noshade" size="1"> +<h1><a name="doc"></a>Documentation</h1> <a href="pexpect.html">pexpect.spawn</a> This is the main class that you want.<br> <a href="pxssh.html">pxssh.ssh</a> Pexpect SSH is an extension of 'pexpect.spawn' that specializes in SSH.<br> -<hr noshade="1"> <a href="screen.html">SCREEN</a> This represents a virtual 'screen'.<br> <a href="ANSI.html">ANSI</a> This parses ANSI/VT-100 terminal escape codes.<br> <a href="FSM.html">FSM</a> This is a finite state machine used by ANSI.<br> -</td> -</tr></table></td></tr></table> +</p> +<h2>Examples</h2> +<p>The <span class="code">pexpect-examples.tgz</span> tarball contains +the following scripts that give examples of how Pexpect can be used.<br> +</p> +<blockquote> +<p><span class="code">script.py</span></p> +<p><blockquote> + This implements a command similar to the classic BSD +"script" command. + This will start a subshell and log all input and +output to a file. + This demonstrates the interact() method of Pexpect. +</p></blockquote> + +<p><span class="code">fix_cvs_files.py</span></p> +<p><blockquote> + This is for cleaning up binary files improperly +added to CVS. + This script scans the given path to find binary +files; + checks with CVS to see if the sticky options are set +to -kb; + finally if sticky options are not -kb then uses 'cvs +admin' to + set the -kb option. +</p></blockquote> + +<p><span class="code">ftp.py</span></p> +<p><blockquote> + This demonstrates an FTP "bookmark". + This connects to an ftp site; does a few ftp stuff; +and then gives the user + interactive control over the session. In this case +the "bookmark" is to a + directory on the OpenBSD ftp server. It puts you in +the i386 packages + directory. You can easily modify this for other +sites. + This demonstrates the interact() method of Pexpect. +</p></blockquote> + +<p><span class="code">monitor.py</span></p> +<p><blockquote> + This runs a sequence of commands on a remote host +using SSH. + It runs a simple system checks such as uptime and +free to monitor + the state of the remote host. +</p></blockquote> + +<p><span class="code">passmass.py</span></p> +<p><blockquote> + This will login to each given server and change the +password of the + given user. This demonstrates scripting logins and +</p></blockquote> + +<p><span class="code">python.py</span></p> +<p><blockquote> + This starts the python interpreter and prints the +greeting message backwards. + It then gives the user iteractive control of Python. +It's pretty useless! +</p></blockquote> + +<p><span class="code">rippy.py</span></p> +<p><blockquote> + This is a wizard for mencoder. It greatly simplifies +the process of + ripping a DVD to Divx (mpeg4) format. It can +transcode from any + video file to another. It has options for resampling +the audio stream; + removing interlace artifacts, fitting to a target +file size, etc. + There are lots of options, but the process is simple +and easy to use. +</p></blockquote> -</body></html> +<p><span class="code">sshls.py</span></p> +<p><blockquote> + This lists a directory on a remote machine. +</p></blockquote> +<p><span class="code">ssh_tunnel.py</span></p> +<p><blockquote> + This starts an SSH tunnel to a remote machine. It +monitors the connection + and restarts the tunnel if it goes down. +</p></blockquote> +<p><span class="code">uptime.py</span></p> +<p><blockquote> + This will run the uptime command and parse the +output into variables. + This demonstrates using a single regular expression +to match the output + of a command and capturing different variable in +match groups. + The regular expression takes into account a wide +variety of different + </blockquote> +</blockquote> +<p></p> +<hr noshade="noshade" size="1"> +<h1><a name="status"></a>Project Status</h1> +<p>This is mature, quality code. Automated pyunit tests reach over 80% +code coverage on pexpect.py. I regularly test on Linux and BSD +platforms. I occaisonally test on Solaris and Irix. Generally +everything works pretty well. The <a href="#download">examples</a> +tarball has several sample scripts.<br> +</p> +<p>I also built a protoype a screen scraper. I have a working ANSI +terminal emulator (VT100 compatible), it is not extensively tested with +real-world applications.</p> +<hr noshade="noshade" size="1"> +<h1><a name="requirements"></a>Requirements for use of Pexpect</h1> +<h2>Python</h2> +<blockquote> + <p>Pexpect was written and tested with Python 2.1. It should work on +earlier versions that have the <span class="code">pty</span> module. I +sometimes even manually test it with Python 1.5.2, but I can't easily +run the PyUnit test framework against Python 1.5.2, so I have less +confidence in Pexpect on Python 1.5.2.</p> +</blockquote> +<h2>pty module</h2> +<blockquote> + <p>Any POSIX system (UNIX) with a working <span class="code">pty</span> +module should be able to run Pexpect. The <span class="code">pty</span> +module is part of the Standard Python Library, so if you are running on +a POSIX system you should have it. The <span class="code">pty</span> +module does not run as well on all platforms. I have taken effort to +try to smooth the wrinkles out the different platforms. To learn more +about the wrinkles see <a href="#bugs">Bugs</a> and <a href="#testing">Testing</a>.</p> +</blockquote> +<p>Pexpect does not currently work on the standard Windows Python(see +the pty requirement); however, it seems to work fine using <a + href="http://www.cygwin.com/">Cygwin</a>. It is possible to build +something like a pty for Windows, but it would have to use a different +technique that I am still investigating. I know it's possible because +Libes' Expect was ported to Windows. <i>If you have any ideas or +skills to contribute in this area then I would really appreciate some +tips on how to approach this problem.</i> </p> +<hr noshade="noshade" size="1"> +<h1><a name="overview"></a>Overview</h1> +<p>Pexpect can be used for automating interactive applications such as +ssh, ftp, mencoder, passwd, etc. The Pexpect interface was designed to be +easy to use. Here is an example of Pexpect in action:</p> +<blockquote> + <pre class="code"># This connects to the openbsd ftp site and<br># downloads the recursive directory listing.<br>import pexpect<br>child = pexpect.spawn ('ftp ftp.openbsd.org')<br>child.expect ('Name .*: ')<br>child.sendline ('anonymous')<br>child.expect ('Password:')<br>child.sendline ('noah@example.com')<br>child.expect ('ftp> ')<br>child.sendline ('cd pub')<br>child.expect('ftp> ')<br>child.sendline ('get ls-lR.gz')<br>child.expect('ftp> ')<br>child.sendline ('bye')<br></pre> +</blockquote> +<p> Obviously you could write an ftp client using Python's own <span + class="code">ftplib</span> module, but this is just a demonstration. +You can use this technique with any application. This is especially +handy if you are writing automated test tools.</p> +<p>There are two common methods in Pexpect -- <span class="code"><b>expect()</b></span> +and <span class="code"><b>send()</b></span> (or <span class="code">sendline()</span> +which is like <span class="code">send()</span> with a linefeed). With +the <span class="code">expect()</span> command you cause your script +to wait for the child application to return a string. The string can be +regular expression. The <span class="code"><b>send()</b></span> method +writes a string to the child application. From the child's point of +view it looks just like someone typed the text from a terminal. After +each call to <span class="code"><b>expect()</b></span> the <span + class="code"><b>before</b></span> and <span class="code"><b>after</b></span> +properties will be set to the text printed by child application. The <span + class="code"><b>before</b></span> property will contain all text up to +the expected string. The <span class="code"><b>after</b></span> string +will contain the text that was matched (remember, the expected string +is a regular expression, so the matched string does not equal the +expected string necessarily). The <span class="code">match</span> +property is set to the <span class="code">re MatchObject</span> if +there is a successful match. If the child has died and you have read +all the child's output then expect will raise an <span class="code">EOF</span> +exception. You can read everything up to the EOF without generating an +exception by using the <span class="code"> expect(pexpect.EOF)</span>. +In this case everything the child has output will be available in the <span + class="code">before</span> property.</p> +<p>An example of Pexpect in action may be more clear. This example uses +<span class="code">ftp</span> to login to the OpenBSD site; list files +in a directory; and then pass interactive control of the ftp session to +the human user.</p> +<blockquote> + <pre class="code">import pexpect<br>child = pexpect.spawn ('ftp ftp.openbsd.org')<br>child.expect ('Name .*: ')<br>child.sendline ('anonymous')<br>child.expect ('Password:')<br>child.sendline ('noah@example.com')<br>child.expect ('ftp> ')<br>child.sendline ('ls /pub/OpenBSD/')<br>child.expect ('ftp> ')<br>print child.before # Print the result of the ls command.<br>child.interact() # Give control of the child to the user.<br></pre> +</blockquote> +<p>The pattern given to <span class="code">expect()</span> is a +regular expression. It can also be a list of regular expression. This +allows you to match multiple responses. The <span class="code">expect()</span> +method returns the index of the pattern that was matched. For example, +say you wanted to login to a server. After entering a password you +could get various responses from he server. Your password could be +rejected; or you could be allowed in and asked for your terminal type; +or you could be let right in and given a command prompt. The following +code fragment gives an example of this:</p> +<blockquote> + <pre class="code">child.expect('password:')<br>child.sendline (my_secret_password)<br># We expect any of these three patterns...<br>i = child.expect (['Permission denied', 'Terminal type', '[#\$] '])<br>if i==0:<br> print 'Permission denied on host. Can't login'<br> child.kill(0)<br>elif i==2:<br> print 'Login OK... need to send terminal type.'<br> child.sendline('vt100')<br> child.expect ('[#\$] ')<br>elif i==3:<br> print 'Login OK.'<br> print 'Shell command prompt', child.after</pre> +</blockquote> +<p>If nothing matches an expected pattern then expect will eventually +raise a TIMEOUT exception. The default time is 30 seconds, but you can +change this by passing a timeout argument to expect():</p> +<blockquote> + <pre class="code"># Wait no more than 2 minutes (120 seconds) for password prompt.<br>child.expect('password:', timeout=120)</pre> +</blockquote> +<h2>Find the end of line -- CR/LF conventions<br> +Matching at the end of a line can be tricky<br> +$ pattern is useless.<br> +</h2> +<p>Pexpect matches regular expressions a little differently than what +you might be used to. It reads one character from the stream at a time. +After each character it tests if all of the regular expressions for a +match. Note, pexpect does have an internal buffer, so reads are faster +than one character at a time, but from the user's perspective the regex +test happens one character at a time.<br> +</p> +<p><i><b>The $ pattern for end of line match is useless</b></i>. With +Pexpect I have not found any use for the $ pattern. The $ matches the +end of string which is immediately preceding each newline, but Pexpect +reads the stream one character at a time, so each character looks like +the end of a line. Pexpect can't do a look-ahead into the stream. In +general you would have this situation when using regular expressions +with any stream.</p> +<p>So the best way to match the end of a line is to look for the +newline. </p> +<p>Pexpect compiles all regular expressions with the DOTALL flag. With +the DOTALL flag a "." will match a newline. See the Python <a + href="http://www.python.org/doc/current/lib/node99.html#l2h-733">documentation</a></p> +<p><b>UNIX uses just linefeeds to end lines of text, but not when it +comes to TTY devices!</b> TTY devices are more like the Windows world. +Each line of text end with a CR/LF combination. When you intercept data +from a UNIX command from a TTY device you will find that the TTY device +outputs a CR/LF combination. A UNIX command may only write a linefeed +(\n), but the TTY device driver converts it to CR/LF. This means that +your terminal will see lines end with CR/LF (hex <span class="code">0D 0A</span>). +Since Pexpect emulates a terminal, to match ends of lines you have to +expect the CR/LF combination.</p> +<blockquote> + <p class="code">child.expect ('\r\n')</p> +</blockquote> +<p>If you just need to skip past a new line then <span class="code">expect +('\n')</span> by itself will work, but if you are expecting a specific +pattern before the end of line then you need to explicitly look for the +\r. For example the following expects a word at the end of a line:</p> +<blockquote> + <p class="code">child.expect ('\w+\r\n')</p> +</blockquote> +<p>But the following would both fail:</p> +<blockquote> + <p class="code">child.expect ('\w+\n')</p> +</blockquote> +<p>And as explained before, trying to use '$' to match the end of line +would not work either:</p> +<blockquote> + <p class="code">child.expect ('\w+$')</p> +</blockquote> +<p>So if you need to explicitly look for the END OF LINE, you want to +look for the CR/LF combination -- not just the LF and not the $ pattern.</p> +<p>This problem is not limited to Pexpect. This problem happens any +time you try to perform a regular expression match on a stream. Regular +expressions need to look ahead. With a stream it is hard to look ahead +because process generating the stream may not be finished. There is no +way to know if the process has paused momentarily or is finished and +waiting for you. <font color="#cc0000">Pexpect must implicitly always +do a NON greedy match (minimal) at the end of a input {### already said +this}.</font> </p> +<h2>Beware of + and * at the end of input.</h2> +<p>Remember that any time you try to match a pattern that needs +look-ahead that you will always get a minimal match (non greedy). For +example, the following will always return just one character:</p> +<blockquote> + <p class="code">child.expect ('.+')</p> +</blockquote> +<p>This example will match successfully, but will always return no +characters:</p> +<blockquote> + <p class="code">child.expect ('.*')</p> +</blockquote> +<p>Generally any star * expression will match as little as possible</p> +<p>One thing you can do is to try to force a non-ambiguous character at +the end of your <span class="code">\d+</span> pattern. Expect that +character to delimit the string. For example, you might try making thr +end of your pattrn be <span class="code">\D+</span> instead of <span + class="code">\D*</span>. That means number digits alone would not +satisfy the (<span class="code">\d+</span>) pattern. You would need +some number(s) and at least one <span class="code">\D</span> at the +end. </p> +<h2>Matching groups</h2> +<p>You can group regular expression using parenthesis. After a match, +the <span class="code">match</span> parameter of the spawn object will +contain the Python Match object. </p> +<h2>Examples</h2> +<p>Using "match" and groups...</p> +<h2>Debugging</h2> +<p>If you get the string value of a pexpect.spawn object you will get +lots of useful debugging information. For debugging it's very useful to +use the following pattern:</p> +<p>try:<br> + i = child.expect ([pattern1, pattern2, pattern3, +etc])<br> +except:<br> + print "Exception was thrown"<br> + print "debug information:"<br> + print str(child)<br> +</p> +<p>It is also useful to log the child's input and out to a file or the +screen. The following will turn on logging and send output to stdout +(the screen).<br> +</p> +<p> child = pexpect.spawn (foo)<br> + child.logfile = sys.stdout<br> +<br> +</p> +<hr noshade="noshade" size="1"> +<h1>Exceptions</h1> +<p><b>EOF</b></p> +<p>Note that two flavors of EOF Exception may be thrown. They are +virtually identical except for the message string. For practical +purposes you should have no need to distinguish between them, but they +do give a little extra information about what type of platform you are +running. The two messages are:</p> +<blockquote> + <p class="code">End Of File (EOF) in read(). Exception style platform.</p> + <p class="code">End Of File (EOF) in read(). Empty string style +platform.</p> +</blockquote> +<p>Some UNIX platforms will throw an exception when you try to read +from a file descriptor in the EOF state. Other UNIX platforms instead +quietly return an empty string to indicate that the EOF state has been +reached.</p> +<p><b>Expecting EOF</b></p> +<p>If you wish to read up to the end of the child's output without +generating an <span class="code">EOF</span> exception then use the <span + class="code">expect(pexpect.EOF)</span> method.</p> +<p><b>TIMEOUT</b></p> +<p>The <span class="code">expect()</span> and <span class="code">read()</span> +methods will also timeout if the child does not generate any output for +a given amount of time. If this happens they will raise a <span + class="code">TIMEOUT</span> exception. You can have these method +ignore a timeout and block indefinitely by passing None for the timeout +parameter.</p> +<blockquote> + <p class="code">child.expect(pexpect.EOF, timeout=None)</p> +</blockquote> +<hr noshade="noshade" size="1"> +<h1><a name="faq"></a>FAQ</h1> +<p>This is not a real FAQ, since no one really asked me most of these +questions. I just made them up. If anyone asks real questions then I +will put them here.</p> +<p><b>Q: Isn't there already a Python Expect?</b></p> +<p>A: Yes, there are several of them. They usually require you to +compile C. I wanted something that was pure Python and preferably a +single module that was simple to install. I also wanted something that +was easy to use. This pure Python expect only recently became possible +with the introduction of the pty module in the standard Python library. +Previously C extensions were required.</p> +<p><strong>Q: The before and after properties sound weird.</strong></p> +<p>Originally I was going to model Pexpect more after Expect, but then +I found that I could never remember how to get the context of the stuff +I was trying to parse. I hate having to read my own documentation. I +decided that it was easier for me to remember what before and after +was. It just so happens that this is how the -B and -A options in grep +works, so that made it even easier for me to remember. Whatever makes +my life easier is what's best.</p> +<p><b>Q: Why not just use Expect?</b></p> +<p>A: I love it. It's great. I has bailed me out of some real jams, but +I wanted something that would do 90% of what I need from Expect; be 10% +of the size; and allow me to write my code in Python instead of TCL. +Pexpect is not nearly as big as Expect, but Pexpect does everything I +have ever used Expect for. +<!--:-P If I liked TCL then you wouldn't be reading this. My appologies to Don Libes -- Expect is cool, TK is cool, but TCL is only slightly better than Perl in my book. Hopefully after Expyct is done I will not need to use Expect anymore -- except for that lovely autoexpect tool. Damn, I wish I had that! --> </p> +<p><b>Q: Why not just use a pipe (popen())?</b></p> +<p>A: A pipe works fine for getting the output to non-interactive +programs. If you just want to get the output from <span class="code">ls</span>, +<span class="code">uname</span>, or <span class="code">ping</span> +then this works. Pipes do not work very well for interactive programs +and pipes will almost certainly fail for most applications that ask for +passwords such as telnet, ftp, or ssh.</p> +<p>There are two reasons for this. </p> +<p>First an application may bypass stdout and print directly to its +controlling TTY. Something like SSH will do this when it asks you for a +password. This is why you cannot redirect the password prompt because +it does not go through stdout or stderr.</p> +<p>The second reason is because most applications are built using the C +Standard IO Library (anything that uses <span class="code">#include +<stdio.h></span>). One of the features of the stdio library is +that it buffers all input and output. Normally output is <b><i>line +buffered</i></b> when a program is printing to a TTY (your terminal +screen). Everytime the program prints a line-feed the currently +buffered data will get printed to your screen. The problem comes when +you connect a pipe. The stdio library is smart and can tell that it is +printing to a pipe instead of a TTY. In that case it switches from line +buffer mode to <i><b>block buffered</b></i>. In this mode the +currently buffered data is flushed when the buffer is full. This causes +most interactive programs to deadlock. Block buffering is more +efficient when writing to disks and pipes. Take the situation where a +program prints a message "Enter your user name:\n" and then waits for +you type type something. In block buffered mode, the stdio library will +not put the message into the pipe even though a linefeed is printed. +The result is that you never receive the message, yet the child +application will sit and wait for you to type a response. Don't confuse +the stdio lib's buffer with the pipe's buffer. The pipe buffer is +another area that can cause problems. You could flush the input side of +a pipe, whereas you have no control over the stdio library buffer. </p> +<p>More information: the Standard IO library has three states for a +FILE *. These are: _IOFBF for block buffered; _IOLBF for line buffered; +and _IONBF for unbuffered. The STDIO lib will use block buffering when +talking to a block file descriptor such as a pipe. This is usually not +helpful for interactive programs. Short of recompiling your program to +include fflush() everywhere or recompiling a custom stdio library there +is not much a controlling application can do about this if talking over +a pipe.</p> +<p> The program may have put data in its output that remains unflushed +because the output buffer is not full; then the program will go and +deadlock while waiting for input -- because you never send it any +because you are still waiting for its output (still stuck in the +STDIO's output buffer).</p> +<p>The answer is to use a pseudo-tty. A TTY device will force <i><b>line</b></i> +buffering (as opposed to block buffering). Line buffering means that +you will get each line when the child program sends a line feed. This +corresponds to the way most interactive programs operate -- send a line +of output then wait for a line of input.</p> +<p>I put "answer" in quotes because it's ugly solution and because +there is no POSIX standard for pseudo-TTY devices (even though they +have a TTY standard...). What would make more sense to me would be to +have some way to set a mode on a file descriptor so that it will tell +the STDIO to be line-buffered. I have investigated, and I don't think +there is a way to set the buffered state of a child process. The STDIO +Library does not maintain any external state in the kernel or whatnot, +so I don't think there is any way for you to alter it. I'm not quite +sure how this line-buffered/block-buffered state change happens +internally in the STDIO library. I think the STDIO lib looks at the +file descriptor and decides to change behavior based on whether it's a +TTY or a block file (see isatty()).</p> +<p>I hope that this qualifies as helpful.</p> +<h1>Don't use a pipe to control another application...</h1> +<p>Pexpect may seem similar to <span class="code">os.popen()</span> or +<span class="code">commands</span> module. The main difference is that +Pexpect (like Expect) uses a pseudo-TTY to talk to the child +application. Most applications do no work well through the system() +call or through pipes. And probably all applications that ask a user to +type in a password will fail. These applications bypass the stdin and +read directly from the TTY device. Many applications do not explicitly +flush their output buffers. This causes deadlocks if you try to control +an interactive application using a pipe. What happens is that most UNIX +applications use the stdio (#include <stdio.h>) for input and +output. The stdio library behaves differently depending on where the +output is going. There is no way to control this behavior from the +client end.<br> +</p> +<p><b>Q: Can I do screen scraping with this thing?</b></p> +<p>A: That depends. If your application just does line-oriented output +then this is easy. If it does screen-oriented output then it may work, +but it could be hard. For example, trying to scrape data from the 'top' +command would be hard. The top command repaints the text window. </p> +<p>I am working on an ANSI / VT100 terminal emulator that will have +methods to get characters from an arbitrary X,Y coordinate of the +virtual screen. It works and you can play with it, but I have no +working examples at this time.</p> +<hr noshade="noshade" size="1"> +<h1><a name="bugs"></a>Bugs</h1> +<h2>Threads</h2> +<p>On Linux (RH 8) you cannot spawn a child from a different thread and +pass the handle back to a worker thread. The child is successfully +spawned but you can't interact with it. The only way to make it work is +to spawn and interact with the child all in the same thread. [Adam +Kerrison] </p> +<h2><a name="echo_bug"></a>Timing issue with send() and sendline()</h2> +<p>This problem has been addressed and should not effect most users.</p> +<p>It is sometimes possible to read an echo of the string sent with <span + class="code">send()</span> and <span class="code">sendline()</span>. +If you call <span class="code">sendline()</span> and then immediately +call <span class="code">readline()</span> you may get part of your +output echoed back. You may read back what you just wrote even if the +child application does not explicitly echo it. Timing is critical. This +could be a security issue when talking to an application that asks for +a password; otherwise, this does not seem like a big deal. <i>But why +do TTYs do this</i>?</p> +<p>People usually report this when they are trying to control SSH or +some other login. For example, if your code looks something like this: </p> +<pre class="code">child.expect ('[pP]assword:')<br>child.sendline (my_password)</pre> +<p><br> +<blockquote> +1. SSH prints "password:" prompt to the user.<br> +2. SSH turns off echo on the TTY device.<br> +3. SSH waits for user to enter a password.<br> +</blockquote> +When scripting with Pexpect what can happen is that Pexpect will response to the "password:" prompt +before SSH has had time to turn off TTY echo. In other words, Pexpect sends the password between +steps 1. and 2., so the password gets echoed back to the TTY. I would call this an SSH bug. +</p> +<p> +Pexpect now automatically adds a short delay before sending data to a child process. +This more closely mimics what happens in the usual human-to-app interaction. +The delay can be tuned with the 'delaybeforesend' attribute of the spawn class. +In general, this fixes the problem for everyone and so this should not be an issue +for most users. For some applications you might with to turn it off. + child = pexpect.spawn ("ssh user@example.com") + child.delaybeforesend = 0 +</p> +<p><br> +</p> +<p>Try changing it to look like the following. I know that this fix +does not look correct, but it works. I have not figured out exactly +what is happening. You would think that the sleep should be after the +sendline(). The fact that the sleep helps when it's between the +expect() and the sendline() must be a clue.</p> +<pre class="code">child.expect ('[pP]assword:')<br>child.sendline (my_password)</pre> +<h2>Timing issue with isalive()</h2> +<p>Reading the state of isalive() immediately after a child exits may +sometimes return 1. This is a race condition. The child has closed its +file descriptor, but has not yet fully exited before Pexpect's +isalive() executes. Addings a slight delay before the isalive() will +help. In the following example <span class="code">isalive()</span> +sometimes returns 1:</p> +<blockquote> + <pre class="code">child = pexpect.spawn('ls')<br>child.expect(pexpect.EOF)<br>print child.isalive()</pre> +</blockquote> +<p>But if there is any delay before the call to <span class="code">isalive()</span> +then it will always return 0 as expected.</p> +<blockquote> + <pre class="code">child = pexpect.spawn('ls')<br>child.expect(pexpect.EOF)<br>time.sleep(0.1)<br>print child.isalive()</pre> +</blockquote> +<h2>Truncated output just before child exits</h2> +<p><i>So far I have seen this only on older versions of <b>Apple's MacOS X</b>.</i> +If the child application quits it may not flush its output buffer. This +means that your Pexpect application will receive an EOF even though it +should have received a little more data before the child died. This is +not generally a problem when talking to interactive child applications. +One example where it is a problem is when trying to read output from a +program like '<span class="code">ls</span>'. You may receive most of +the directory listing, but the last few lines will get lost before you +receive an EOF. The reason for this is that '<span class="code">ls</span>' +runs; completes its task; and then exits. The buffer is not flushed +before exit so the last few lines are lost. The following example +demonstrates the problem:</p> +<p> </p> +<blockquote> + <pre class="code">child = pexpect.spawn ('ls -l')<br>child.expect (pexpect.EOF)<br>print child.before <br> </pre> +</blockquote> +<p></p> +<h2>Controlling SSH on Solaris</h2> +<p>Pexpect does not yet work perfectly on Solaris. +One common problem is that SSH sometimes will not allow TTY password +authentication. For example, you may expect SSH to ask you for a +password using code like this: +</p> +<pre class="code">child = pexpect.spawn ('ssh user@example.com')<br>child.expect ('assword')<br>child.sendline ('mypassword')<br></pre> +You may see the following error come back from a spawned +child SSH: +<p></p> +<blockquote>Permission denied (publickey,keyboard-interactive). </blockquote> +<p> +This means that SSH thinks it can't access the TTY to ask you for your +password. +The only solution I have found is to use public key authentication with +SSH. +This bypasses the need for a password. I'm not happy with this +solution. +The problem is due to poor support for Solaris Pseudo TTYs in the +Python +Standard Library. </p> +<hr noshade="noshade" size="1"> +<h1><a name="changes"></a>CHANGES</h1> +<h2>Current Release</h2> +<p>Fixed OSError exception when a pexpect object is cleaned up. +Previously you might have seen this exception:</p> +<blockquote> + <pre class="code">Exception exceptions.OSError: (10, 'No child processes') <br>in <bound method spawn.__del__ of<br><pexpect.spawn instance at 0xd248c>> ignored</pre> +</blockquote> +<p>You should not see that anymore. Thanks to Michael Surette.</p> +<p>Added support for buffering reads. This greatly improves speed when +trying to match long output from a child process. When you create an +instance of the spawn object you can then set a buffer size. For now +you MUST do the following to turn on buffering -- it may be on by +default in future version.</p> +<blockquote> + <pre class="code">child = pexpect.spawn ('my_command')<br>child.maxread=1000 # Sets buffer to 1000 characters.</pre> +</blockquote> +<div> +<p>I made a subtle change to the way TIMEOUT and EOF exceptions behave. +Previously you could either expect these states in which case pexpect +will not raise an exception, or you could just let pexpect raise an +exception when these states were encountered. If you expected the +states then the 'before' property was set to everything before the +state was encountered, but if you let pexpect raise the exception then +'before' was not set. Now the 'before' property will get set either way +you choose to handle these states.</p> +<h2><i>Older changes...</i></h2> +<p>The spawn object now provides iterators for a <i>file-like interface</i>. +This makes Pexpect a more complete file-like object. You can now write +code like this:</p> +<blockquote> + <pre class="code">child = pexpect.spawn ('ls -l')<br>for line in child:<br> print line<br></pre> +</blockquote> +<p>I added the attribute <span class="code">exitstatus</span>. This +will give the exit code returned by the child process. This will be set +to <span class="code">None</span> while the child is still alive. When +<span class="code">isalive()</span> returns 0 then <span class="code">exitstatus</span> +will be set.</p> +<p>I made a few more tweaks to <span class="code">isalive()</span> so +that it will operate more consistently on different platforms. Solaris +is the most difficult to support.</p> +<p> </p> +<p>You can now put <span class="code">TIMEOUT</span> in a list of +expected patterns. This is just like putting <span class="code">EOF</span> +in the pattern list. Expecting for a <span class="code">TIMEOUT</span> +may not be used as often as <span class="code">EOF</span>, but this +makes Pexpect more consitent.</p> +<p>Thanks to a suggestion and sample code from Chad J. Schroeder I +added the ability for Pexpect to operate on a file descriptor that is +already open. This means that Pexpect can be used to control streams +such as those from serial port devices. Now you just pass the integer +file descriptor as the "command" when contsructing a spawn open. For +example on a Linux box with a modem on ttyS1:</p> +<blockquote> + <pre class="code">fd = os.open("/dev/ttyS1", os.O_RDWR|os.O_NONBLOCK|os.O_NOCTTY)<br>m = pexpect.spawn(fd) # Note integer fd is used instead of usual string.<br>m.send("+++") # Escape sequence<br>m.send("ATZ0\r") # Reset modem to profile 0<br>rval = m.expect(["OK", "ERROR"])</pre> +</blockquote> +<h3>Pexpect now tests itself on Compile Farm!</h3> +<p>I wrote a nice script that uses ssh to connect to each machine on +Source Forge's Compile Farm and then run the testall.py script for each +platform. The result of the test is then recorded for each platform. +Now it's easy to run regression tests across multiple platforms.</p> +<h3>Pexpect is a file-like object</h3> +<p>The spawn object now provides a <i>file-like interface</i>. It +supports most of the methods and attributes defined for Python File +Objects. </p> +<p>I changed write and writelines() so that they no longer return a +value. Use send() if you need that functionality. I did this to make +the Spawn object more closely match a file-like object.</p> +<p>read() was renamed to read_nonblocking(). I added a new read() +method that matches file-like object interface. In general, you should +not notice the difference except that read() no longer allows you to +directly set the timeout value. I hope this will not effect any +existing code. Switching to read_nonblocking() should fix existing code.</p> +<p>I changed the name of <span class="code">set_echo()</span> to <span + class="code">setecho()</span>.</p> +<p>I changed the name of <span class="code">send_eof()</span> to <span + class="code">sendeof()</span>.</p> +<p>I modified <span class="code">kill()</span> so that it checks to +make sure the pid isalive().</p> +<p>I modified <span class="code">spawn()</span> (really called from <span + class="code">__spawn()</span>)so that it does not raise an expection +if <span class="code">setwinsize()</span> fails. Some platforms such +as Cygwin do not like setwinsize. This was a constant problem and since +it is not a critical feature I decided to just silence the error. +Normally I don't like to do that, but in this case I'm making an +exception.</p> +<p>Added a method <span class="code">close()</span> that does what you +think. It closes the file descriptor of the child application. It makes +no attempt to actually kill the child or wait for its status. </p> +<p>Add variables <span class="code">__version__</span> and <span + class="code">__revision__</span> (from cvs) to the pexpect modules. +This is mainly helpful to me so that I can make sure that I'm testing +with the right version instead of one already installed.</p> +<h3>Logging changes</h3> +<blockquote> + <p><span class="code">log_open()</span> and <span class="code">log_close()</span> +have been removed. Now use <span class="code">setlog()</span>. The <span + class="code">setlog()</span> method takes a file object. This is far +more flexible than the previous log method. Each time data is written +to the file object it will be flushed. To turn logging off simply call <span + class="code">setlog()</span> with None.</p> +</blockquote> +<h2>isalive changes</h2> +<blockquote> + <p>I renamed the <span class="code">isAlive()</span> method to <span + class="code">isalive()</span> to match the more typical naming style +in Python. Also the technique used to detect child process status has +been drastically modified. Previously I did some funky stuff with +signals which caused indigestion in other Python modules on some +platforms. It's was a big headache. It still is, but I think it works +better now.</p> +</blockquote> +<h3>attribute name changes</h3> +<blockquote> + <p>The names of some attributes have been changed. This effects the +names of the attributes that are set after called the <span + class="code">expect()</span> method.</p> + <table class="pymenu" border="0" cellpadding="5"> + <tbody> + <tr> + <th class="pymenu">NEW NAME</th> + <th class="pymenu">OLD NAME</th> + </tr> + <tr> + <td><span class="code">before</span><br> + <i>Everything before the match.</i></td> + <td><span class="code">before</span></td> + </tr> + <tr> + <td><span class="code">after</span><br> + <i>Everything after and including the first character of the +match</i></td> + <td><span class="code">matched</span></td> + </tr> + <tr> + <td><span class="code">match</span><br> + <i>This is the re MatchObject from the match.<br> +You can get groups() from this.<br> +See '<span class="code">uptime.py</span>' in the examples tar ball.</i></td> + <td><i>New -- Did not exist</i></td> + </tr> + </tbody> + </table> +</blockquote> +<h3>EOF changes</h3> +<blockquote> + <p>The <span class="code">expect_eof()</span> method is gone. You +can now simply use the <span class="code">expect()</span> method to +look for EOF.</p> + <p>Was:</p> + <blockquote> + <p><span class="code">p.expect_eof ()</span></p> + </blockquote> + <p>Now:</p> + <blockquote> + <p><span class="code">p.expect (pexpect.EOF)</span></p> + </blockquote> +</blockquote> +<hr noshade="noshade" size="1"> +<h1><a name="testing"></a>TESTING</h1> +<p>The following platforms have been tested:</p> +<table class="pymenu" border="0" cellpadding="5"> + <tbody> + <tr> + <th class="pymenu">PLATFORM</th> + <th class="pymenu">RESULTS</th> + </tr> + <tr> + <td>Linux 2.4.9-ac10-rmk2-np1-cerf2<br> +armv4l</td> + <td><b><i>all tests passed</i></b></td> + </tr> + <tr> + <td>Linux 2.4.18 #2<br> +sparc64</td> + <td><b><i>all tests passed</i></b></td> + </tr> + <tr> + <td>MacOS X Darwin Kernel Version 5.5<br> +powerpc</td> + <td> + <p>failed more than one test.</p> + <p>Generally Pexpect works on OS X, but the nature of the quirks +cause a many of the tests to fail. See <a href="#bugs">bugs</a> +(Incomplete Child Output). The problem is more than minor, but Pexpect +is still more than useful for most tasks. The problem is an edge case.</p> + </td> + </tr> + <tr> + <td>Linux 2.2.20<br> +alpha<br> + </td> + <td><b><i>all tests passed</i></b></td> + </tr> + <tr> + <td>Linux 2.4.18-5smp<br> +i686</td> + <td><b><i>all tests passed</i></b></td> + </tr> + <tr> + <td>OpenBSD 2.9 GENERIC#653<br> +i386</td> + <td><b><i>all tests passed</i></b></td> + </tr> + <tr> + <td>Solaris</td> + <td> + <p>failed <span class="code">test_destructor</span></p> + <p>Otherwise, this is working pretty well. The destructor problem +is minor. For some reason, the <i>second</i> time a pty file +descriptor is created and deleted it never gets returned for use. It +does not effect the first time or the third time or any time after +that. It's only the second time. This is weird... This could be a file +descriptor leak, or it could be some peculiarity of how Solaris +recycles them. I thought it was a UNIX requirement for the OS to give +you the lowest available filedescriptor number. In any case, this +should not be a problem unless you create hundreds of pexpect +instances... It may also be a pty module bug. </p> + </td> + </tr> + <tr> + <td>Windows XP Cygwin</td> + <td>failed <span class="code">test_destructor</span>. That it +works at all is amazing to me. Cygwin rules!</td> + </tr> + </tbody> +</table> +<h1> </h1> +<h1><a name="todo">TO DO</a></h1> +<p>Add an option to add a delay after each expect() or before each +read()/readline() call to automatically avoid the <a href="#echo_bug">echo +bug</a>.</p> +<p> </p> +</div> +<hr noshade="noshade" size="1"> +<table border="0"> + <tbody> + <tr> + <td> <a href="http://www.noah.org/email/"><img src="email.png" + alt="Click to send email." border="0" height="16" width="100"></a> </td> + </tr> + </tbody> +</table> +</div> +<div id="Menu"><b>INDEX</b><br> +<hr noshade="noshade" size="1"> <a href="#license" + title="Python Software Foundation License">License</a><br> +<a href="#download" title="Download and setup instructions">Download</a><br> +<a href="#doc" title="Documentation and overview">Documentation</a><br> +<a href="#status" title="Project Status">Project Status</a><br> +<a href="#requirements" title="System requirements to use Pexpect">Requirements</a><br> +<a href="#overview" title="Overview of what Pexpect does">Overview</a><br> +<a href="#faq" title="FAQ">FAQ</a><br> +<a href="#bugs" title="Bugs and work-arounds">Known Bugs</a><br> +<a href="#changes" title="What's new with Pexpect">Recent Changes</a><br> +<a href="#testing" title="Test results on various platforms">Testing</a><br> +<a href="#todo" title="What to do next">To do</a><br> +<br> +<a href="http://sourceforge.net/projects/pexpect/" + title="The Pexpect project page on SourceForge.net"> <img + src="http://sourceforge.net/sflogo.php?group_id=59762&type=5" + alt="The Pexpect project page on SourceForge.net" border="0" + height="31" width="105"> </a> </div> +</body> +</html> diff --git a/pexpect/tools/websync.py b/pexpect/tools/websync.py index d1c7829..51e976c 100755 --- a/pexpect/tools/websync.py +++ b/pexpect/tools/websync.py @@ -12,14 +12,14 @@ import sys, os X = getpass.getpass('Password: ') -p = pexpect.spawn ('scp www/index.html noah@use-pr-shell1.sourceforge.net:htdocs/index.html') +p = pexpect.spawn ('scp doc/*.html noah@use-pr-shell1.sourceforge.net:htdocs/.') p.logfile = sys.stdout p.expect ('password:') p.sendline (X) p.expect (pexpect.EOF) print p.before -p = pexpect.spawn ('scp www/clean.css noah@use-pr-shell1.sourceforge.net:htdocs/clean.css') +p = pexpect.spawn ('scp doc/clean.css noah@use-pr-shell1.sourceforge.net:htdocs/clean.css') p.logfile = sys.stdout p.expect ('password:') p.sendline (X) |