Index: third_party/pexpect/doc/overview.rst |
diff --git a/third_party/pexpect/doc/overview.rst b/third_party/pexpect/doc/overview.rst |
new file mode 100644 |
index 0000000000000000000000000000000000000000..d394ef16f8179872f2cfa996e4dd0a18e4fc48d7 |
--- /dev/null |
+++ b/third_party/pexpect/doc/overview.rst |
@@ -0,0 +1,257 @@ |
+API Overview |
+============ |
+ |
+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:: |
+ |
+ # This connects to the openbsd ftp site and |
+ # downloads the recursive directory listing. |
+ import pexpect |
+ child = pexpect.spawn('ftp ftp.openbsd.org') |
+ child.expect('Name .*: ') |
+ child.sendline('anonymous') |
+ child.expect('Password:') |
+ child.sendline('noah@example.com') |
+ child.expect('ftp> ') |
+ child.sendline('lcd /tmp') |
+ child.expect('ftp> ') |
+ child.sendline('cd pub/OpenBSD') |
+ child.expect('ftp> ') |
+ child.sendline('get README') |
+ child.expect('ftp> ') |
+ child.sendline('bye') |
+ |
+Obviously you could write an ftp client using Python's own :mod:`ftplib` 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. |
+ |
+There are two important methods in Pexpect -- :meth:`~pexpect.spawn.expect` and |
+:meth:`~pexpect.spawn.send` (or :meth:`~pexpect.spawn.sendline` which is |
+like :meth:`~pexpect.spawn.send` with a linefeed). The :meth:`~pexpect.spawn.expect` |
+method waits for the child application to return a given string. The string you |
+specify is a regular expression, so you can match complicated patterns. The |
+:meth:`~pexpect.spawn.send` 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 :meth:`~pexpect.spawn.expect` the ``before`` and ``after`` |
+properties will be set to the text printed by child application. The ``before`` |
+property will contain all text up to the expected string pattern. The ``after`` |
+string will contain the text that was matched by the expected pattern. |
+The match property is set to the `re match object <http://docs.python.org/3/library/re#match-objects>`_. |
+ |
+An example of Pexpect in action may make things more clear. This example uses |
+ftp to login to the OpenBSD site; list files in a directory; and then pass |
+interactive control of the ftp session to the human user:: |
+ |
+ import pexpect |
+ child = pexpect.spawn ('ftp ftp.openbsd.org') |
+ child.expect ('Name .*: ') |
+ child.sendline ('anonymous') |
+ child.expect ('Password:') |
+ child.sendline ('noah@example.com') |
+ child.expect ('ftp> ') |
+ child.sendline ('ls /pub/OpenBSD/') |
+ child.expect ('ftp> ') |
+ print child.before # Print the result of the ls command. |
+ child.interact() # Give control of the child to the user. |
+ |
+Special EOF and TIMEOUT patterns |
+-------------------------------- |
+ |
+There are two special patterns to match the End Of File (:class:`~pexpect.EOF`) |
+or a Timeout condition (:class:`~pexpect.TIMEOUT`). You can pass these |
+patterns to :meth:`~pexpect.spawn.expect`. These patterns are not regular |
+expressions. Use them like predefined constants. |
+ |
+If the child has died and you have read all the child's output then ordinarily |
+:meth:`~pexpect.spawn.expect` will raise an :class:`~pexpect.EOF` exception. |
+You can read everything up to the EOF without generating an exception by using |
+the EOF pattern expect. In this case everything the child has output will be |
+available in the ``before`` property. |
+ |
+The pattern given to :meth:`~pexpect.spawn.expect` may be a regular expression |
+or it may also be a list of regular expressions. This allows you to match |
+multiple optional responses. The :meth:`~pexpect.spawn.expect` 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 the |
+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:: |
+ |
+ child.expect('password:') |
+ child.sendline(my_secret_password) |
+ # We expect any of these three patterns... |
+ i = child.expect (['Permission denied', 'Terminal type', '[#\$] ']) |
+ if i==0: |
+ print('Permission denied on host. Can\'t login') |
+ child.kill(0) |
+ elif i==1: |
+ print('Login OK... need to send terminal type.') |
+ child.sendline('vt100') |
+ child.expect('[#\$] ') |
+ elif i==2: |
+ print('Login OK.') |
+ print('Shell command prompt', child.after) |
+ |
+If nothing matches an expected pattern then :meth:`~pexpect.spawn.expect` will |
+eventually raise a :class:`~pexpect.TIMEOUT` exception. The default time is 30 |
+seconds, but you can change this by passing a timeout argument to |
+:meth:`~pexpect.spawn.expect`:: |
+ |
+ # Wait no more than 2 minutes (120 seconds) for password prompt. |
+ child.expect('password:', timeout=120) |
+ |
+Find the end of line -- CR/LF conventions |
+----------------------------------------- |
+ |
+Pexpect matches regular expressions a little differently than what you might be |
+used to. |
+ |
+The :regexp:`$` pattern for end of line match is useless. The :regexp:`$` |
+matches the end of string, but Pexpect reads from the child one character at a |
+time, so each character looks like the end of a line. Pexpect can't do a |
+look-ahead into the child's output stream. In general you would have this |
+situation when using regular expressions with any stream. |
+ |
+.. 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 patterns test happens |
+ one character at a time. |
+ |
+The best way to match the end of a line is to look for the newline: ``"\r\n"`` |
+(CR/LF). Yes, that does appear to be DOS-style. It may surprise some UNIX people |
+to learn that terminal TTY device drivers (dumb, vt100, ANSI, xterm, etc.) all |
+use the CR/LF combination to signify the end of line. Pexpect uses a Pseudo-TTY |
+device to talk to the child application, so when the child app prints ``"\n"`` |
+you actually see ``"\r\n"``. |
+ |
+UNIX uses just linefeeds to end lines of text, but not when it comes to TTY |
+devices! TTY devices are more like the Windows world. Each line of text ends |
+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 ``0D 0A``). Since Pexpect emulates a terminal, to match ends of |
+lines you have to expect the CR/LF combination:: |
+ |
+ child.expect('\r\n') |
+ |
+If you just need to skip past a new line then ``expect('\n')`` 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:: |
+ |
+ child.expect('\w+\r\n') |
+ |
+But the following would both fail:: |
+ |
+ child.expect('\w+\n') |
+ |
+And as explained before, trying to use :regexp:`$` to match the end of line |
+would not work either:: |
+ |
+ child.expect ('\w+$') |
+ |
+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. |
+ |
+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 the 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. Pexpect must |
+implicitly always do a NON greedy match (minimal) at the end of a input. |
+ |
+Pexpect compiles all regular expressions with the :data:`re.DOTALL` flag. |
+With the :data:`~re.DOTALL` flag, a ``"."`` will match a newline. |
+ |
+Beware of + and * at the end of patterns |
+---------------------------------------- |
+ |
+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:: |
+ |
+ child.expect ('.+') |
+ |
+This example will match successfully, but will always return no characters:: |
+ |
+ child.expect ('.*') |
+ |
+Generally any star * expression will match as little as possible. |
+ |
+One thing you can do is to try to force a non-ambiguous character at the end of |
+your :regexp:`\\d+` pattern. Expect that character to delimit the string. For |
+example, you might try making the end of your pattern be :regexp:`\\D+` instead |
+of :regexp:`\\D*`. Number digits alone would not satisfy the :regexp:`(\\d+)\\D+` |
+pattern. You would need some numbers and at least one non-number at the end. |
+ |
+ |
+Debugging |
+--------- |
+ |
+If you get the string value of a :class:`pexpect.spawn` object you will get lots |
+of useful debugging information. For debugging it's very useful to use the |
+following pattern:: |
+ |
+ try: |
+ i = child.expect ([pattern1, pattern2, pattern3, etc]) |
+ except: |
+ print("Exception was thrown") |
+ print("debug information:") |
+ print(str(child)) |
+ |
+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):: |
+ |
+ child = pexpect.spawn(foo) |
+ child.logfile = sys.stdout |
+ |
+Exceptions |
+---------- |
+ |
+:class:`~pexpect.EOF` |
+ |
+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: |
+ |
+- "End Of File (EOF) in read(). Exception style platform." |
+- "End Of File (EOF) in read(). Empty string style platform." |
+ |
+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. |
+ |
+If you wish to read up to the end of the child's output without generating an |
+:class:`~pexpect.EOF` exception then use the ``expect(pexpect.EOF)`` method. |
+ |
+:class:`~pexpect.TIMEOUT` |
+ |
+The :meth:`~pexpect.spawn.expect` and :meth:`~pexpect.spawn.read` 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 :class:`~pexpect.TIMEOUT` exception. |
+You can have these methods ignore timeout and block indefinitely by passing |
+``None`` for the timeout parameter:: |
+ |
+ child.expect(pexpect.EOF, timeout=None) |
+ |
+.. _windows: |
+ |
+Pexpect on Windows |
+------------------ |
+ |
+.. versionadded:: 4.0 |
+ Windows support |
+ |
+Pexpect can be used on Windows to wait for a pattern to be produced by a child |
+process, using :class:`pexpect.popen_spawn.PopenSpawn`, or a file descriptor, |
+using :class:`pexpect.fdpexpect.fdspawn`. This should be considered experimental |
+for now. |
+ |
+:class:`pexpect.spawn` and :func:`pexpect.run` are *not* available on Windows, |
+as they rely on Unix pseudoterminals (ptys). Cross platform code must not use |
+these. |