[Python-modules-commits] [pexpect] 01/04: Imported Upstream version 4.2.0

Tobias Hansen thansen at moszumanska.debian.org
Thu Aug 11 08:16:00 UTC 2016


This is an automated email from the git hooks/post-receive script.

thansen pushed a commit to branch master
in repository pexpect.

commit 08b9657a4220334d03a0c3d57bd8556f4dff425c
Author: Tobias Hansen <thansen at debian.org>
Date:   Wed Aug 10 14:20:04 2016 +0100

    Imported Upstream version 4.2.0
---
 .coveragerc                                 |   3 +
 LICENSE                                     |   9 +-
 MANIFEST.in                                 |   6 +
 PKG-INFO                                    |   5 +-
 README.rst                                  |  55 ++++
 doc/commonissues.rst                        |   2 +-
 doc/conf.py                                 |   4 +-
 doc/history.rst                             |  14 +-
 examples/passmass.py                        |   2 +-
 examples/telnet.py                          |  25 ++
 PKG-INFO => pexpect.egg-info/PKG-INFO       |   5 +-
 pexpect.egg-info/SOURCES.txt                | 150 +++++++++++
 pexpect.egg-info/dependency_links.txt       |   1 +
 pexpect.egg-info/requires.txt               |   1 +
 pexpect.egg-info/top_level.txt              |   1 +
 pexpect/__init__.py                         |   2 +-
 pexpect/async.py                            |  10 +-
 pexpect/bashrc.sh                           |   5 +
 pexpect/expect.py                           |   7 +-
 pexpect/fdpexpect.py                        |  30 ++-
 pexpect/pty_spawn.py                        |  92 +++----
 pexpect/pxssh.py                            |   4 +-
 pexpect/spawnbase.py                        |   8 +-
 pexpect/utils.py                            |  47 +++-
 setup.cfg                                   |   9 +
 setup.py                                    |   8 +-
 tests/.coverage.docker-2.local.36578.771124 |   1 +
 tests/.coverage.docker-2.local.36579.455415 |   1 +
 tests/.coverage.docker-2.local.36580.123114 |   1 +
 tests/.coverage.docker-2.local.36581.321253 |   1 +
 tests/.coverage.docker-2.local.38943.357232 |   1 +
 tests/.coverage.docker-2.local.38944.471090 |   1 +
 tests/.coverage.docker-2.local.38945.54089  |   1 +
 tests/.coverage.docker-2.local.38946.82776  |   1 +
 tests/.coverage.docker-2.local.38984.172622 |   1 +
 tests/.coverage.docker-2.local.38985.978020 |   1 +
 tests/.coverage.docker-2.local.38986.928811 |   1 +
 tests/.coverage.docker-2.local.38987.237434 |   1 +
 tests/.coverage.docker-2.local.38991.12925  |   4 +
 tests/.coverage.docker-2.local.38993.581713 |   4 +
 tests/.coverage.docker-2.local.39001.377317 |   2 +
 tests/.coverage.docker-2.local.39003.638674 |   2 +
 tests/.coverage.docker-2.local.39005.280448 |   2 +
 tests/cc.c                                  |   7 +
 tests/log                                   | 380 ++++++++++++++++++++++++++++
 tests/test_async.py                         |   8 +-
 tests/test_delay.py                         |  45 ++++
 tests/test_env.py                           |  93 +++++++
 tests/test_expect.py                        |   2 +-
 tests/test_issue209.py                      |  23 ++
 tests/test_maxcanon.py                      | 176 -------------
 tests/test_misc.py                          |   7 -
 tests/test_repr.py                          |  11 +
 tests/test_socket.py                        | 255 +++++++++++++++++++
 tests/test_which.py                         |  17 ++
 55 files changed, 1285 insertions(+), 270 deletions(-)

diff --git a/.coveragerc b/.coveragerc
new file mode 100644
index 0000000..7e2d9e2
--- /dev/null
+++ b/.coveragerc
@@ -0,0 +1,3 @@
+[run]
+source = pexpect
+parallel = True
diff --git a/LICENSE b/LICENSE
index 9e10acb..754db5a 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,4 +1,4 @@
-PEXPECT LICENSE
+ISC LICENSE
 
     This license is approved by the OSI and FSF as GPL-compatible.
         http://opensource.org/licenses/isc-license.txt
@@ -6,9 +6,10 @@ PEXPECT LICENSE
     Copyright (c) 2013-2014, Pexpect development team
     Copyright (c) 2012, Noah Spurrier <noah at noah.org>
 
-    PERMISSION TO USE, COPY, MODIFY, AND/OR DISTRIBUTE THIS SOFTWARE FOR ANY
-    PURPOSE WITH OR WITHOUT FEE IS HEREBY GRANTED, PROVIDED THAT THE ABOVE
-    COPYRIGHT NOTICE AND THIS PERMISSION NOTICE APPEAR IN ALL COPIES.
+    Permission to use, copy, modify, and/or distribute this software for any
+    purpose with or without fee is hereby granted, provided that the above
+    copyright notice and this permission notice appear in all copies.
+    
     THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
     WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
diff --git a/MANIFEST.in b/MANIFEST.in
new file mode 100644
index 0000000..32c72ba
--- /dev/null
+++ b/MANIFEST.in
@@ -0,0 +1,6 @@
+recursive-include doc *
+prune doc/_build
+recursive-include examples *
+include .coveragerc README.rst LICENSE pexpect/bashrc.sh
+recursive-include tests *
+global-exclude __pycache__ *.pyc *~
diff --git a/PKG-INFO b/PKG-INFO
index 6647aad..aed0367 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,8 +1,8 @@
 Metadata-Version: 1.1
 Name: pexpect
-Version: 4.0.1
+Version: 4.2.0
 Summary: Pexpect allows easy control of interactive console applications.
-Home-page: http://pexpect.readthedocs.org/
+Home-page: https://pexpect.readthedocs.io/
 Author: Noah Spurrier; Thomas Kluyver; Jeff Quast
 Author-email: noah at noah.org; thomas at kluyver.me.uk; contact at jeffquast.com
 License: ISC license
@@ -32,7 +32,6 @@ Classifier: License :: OSI Approved :: ISC License (ISCL)
 Classifier: Operating System :: POSIX
 Classifier: Operating System :: MacOS :: MacOS X
 Classifier: Programming Language :: Python
-Classifier: Programming Language :: Python :: 2.6
 Classifier: Programming Language :: Python :: 2.7
 Classifier: Programming Language :: Python :: 3
 Classifier: Topic :: Software Development
diff --git a/README.rst b/README.rst
new file mode 100644
index 0000000..f03be78
--- /dev/null
+++ b/README.rst
@@ -0,0 +1,55 @@
+.. image:: https://travis-ci.org/pexpect/pexpect.png?branch=master
+   :target: https://travis-ci.org/pexpect/pexpect
+   :align: right
+   :alt: Build status
+
+Pexpect is a Pure Python Expect-like module
+
+Pexpect makes Python a better tool for controlling other applications.
+
+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.
+
+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.
+
+The main features of Pexpect require the pty module in the Python standard
+library, which is only available on Unix-like systems. Some features—waiting
+for patterns from file descriptors or subprocesses—are also available on
+Windows.
+
+If you want to work with the development version of the source code then please
+read the DEVELOPERS.rst document in the root of the source code tree.
+
+Free, open source, and all that good stuff.
+
+You can install Pexpect using pip::
+
+    pip install pexpect
+
+`Docs on ReadTheDocs <https://pexpect.readthedocs.io/>`_
+
+PEXPECT LICENSE::
+
+    http://opensource.org/licenses/isc-license.txt
+
+    Copyright (c) 2013-2014, Pexpect development team
+    Copyright (c) 2012, Noah Spurrier <noah at noah.org>
+
+    PERMISSION TO USE, COPY, MODIFY, AND/OR DISTRIBUTE THIS SOFTWARE FOR ANY
+    PURPOSE WITH OR WITHOUT FEE IS HEREBY GRANTED, PROVIDED THAT THE ABOVE
+    COPYRIGHT NOTICE AND THIS PERMISSION NOTICE APPEAR IN ALL COPIES.
+    THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+    WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+    MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+    ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+    WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+    ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+    OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+This license is approved by the OSI and FSF as GPL-compatible.
diff --git a/doc/commonissues.rst b/doc/commonissues.rst
index d3aa9d0..f60085e 100644
--- a/doc/commonissues.rst
+++ b/doc/commonissues.rst
@@ -47,7 +47,7 @@ not be an issue for most users. For some applications you might with to turn it
 off::
 
     child = pexpect.spawn ("ssh user at example.com")
-    child.delaybeforesend = 0
+    child.delaybeforesend = None
 
 Truncated output just before child exits
 ----------------------------------------
diff --git a/doc/conf.py b/doc/conf.py
index 8f9500f..f3de534 100644
--- a/doc/conf.py
+++ b/doc/conf.py
@@ -52,9 +52,9 @@ copyright = u'2013, Noah Spurrier and contributors'
 # built documents.
 #
 # The short X.Y version.
-version = '4.0.1'
+version = '4.2'
 # The full version, including alpha/beta/rc tags.
-release = '4.0.1'
+release = '4.2.0'
 
 # The language for content autogenerated by Sphinx. Refer to documentation
 # for a list of supported languages.
diff --git a/doc/history.rst b/doc/history.rst
index 1167865..f90d515 100644
--- a/doc/history.rst
+++ b/doc/history.rst
@@ -4,6 +4,18 @@ History
 Releases
 --------
 
+Version 4.2
+```````````
+
+* Change: When an ``env`` parameter is specified to the :class:`~.spawn` or
+  :class:`~.run` family of calls containing a value for ``PATH``, its value is
+  used to discover the target executable from a relative path, rather than the
+  current process's environment ``PATH``.  This mirrors the behavior of
+  :func:`subprocess.Popen` in the standard library (:ghissue:`348`).
+
+* Regression: Re-introduce capability for :meth:`read_nonblocking` in class
+  :class:`fdspawn` as previously supported in version 3.3 (:ghissue:`359`).
+
 Version 4.0
 ```````````
 
@@ -106,7 +118,7 @@ new maintenance after a long dormancy, so some caution is warranted.
 * Ignoring ``SIGHUP`` is now optional - thanks to Kimmo Parviainen-Jalanko for
   the patch.
 
-We also now have `docs on ReadTheDocs <http://pexpect.readthedocs.org/>`_,
+We also now have `docs on ReadTheDocs <https://pexpect.readthedocs.io/>`_,
 and `continuous integration on Travis CI <https://travis-ci.org/pexpect/pexpect>`_.
 
 Version 2.4
diff --git a/examples/passmass.py b/examples/passmass.py
index 8f5e21d..dc362f5 100755
--- a/examples/passmass.py
+++ b/examples/passmass.py
@@ -46,7 +46,7 @@ def login(host, user, password):
 
     child = pexpect.spawn('ssh -l %s %s'%(user, host))
     fout = file ("LOG.TXT","wb")
-    child.setlog (fout)
+    child.logfile = fout
 
     i = child.expect([pexpect.TIMEOUT, SSH_NEWKEY, '[Pp]assword: '])
     if i == 0: # Timeout
diff --git a/examples/telnet.py b/examples/telnet.py
new file mode 100644
index 0000000..a4fba6c
--- /dev/null
+++ b/examples/telnet.py
@@ -0,0 +1,25 @@
+#!/usr/bin/env python3
+
+import pexpect
+
+def main(airport_code):
+    output = ''
+    telnet = pexpect.spawn('telnet rainmaker.wunderground.com',
+                           encoding='latin1')
+    telnet.expect('Press Return to continue:')
+    telnet.sendline('')
+    telnet.expect('enter 3 letter forecast city code')
+    telnet.sendline(airport_code)
+    while telnet.expect(['X to exit:', 'Selection:']) == 0:
+        output += telnet.before
+        telnet.sendline('')
+    output += telnet.before
+    telnet.sendline('X')
+    telnet.expect(pexpect.EOF)
+    telnet.close()
+    print(output.strip())
+
+
+if __name__ == '__main__':
+    import sys
+    main(airport_code=sys.argv[1])
diff --git a/PKG-INFO b/pexpect.egg-info/PKG-INFO
similarity index 95%
copy from PKG-INFO
copy to pexpect.egg-info/PKG-INFO
index 6647aad..aed0367 100644
--- a/PKG-INFO
+++ b/pexpect.egg-info/PKG-INFO
@@ -1,8 +1,8 @@
 Metadata-Version: 1.1
 Name: pexpect
-Version: 4.0.1
+Version: 4.2.0
 Summary: Pexpect allows easy control of interactive console applications.
-Home-page: http://pexpect.readthedocs.org/
+Home-page: https://pexpect.readthedocs.io/
 Author: Noah Spurrier; Thomas Kluyver; Jeff Quast
 Author-email: noah at noah.org; thomas at kluyver.me.uk; contact at jeffquast.com
 License: ISC license
@@ -32,7 +32,6 @@ Classifier: License :: OSI Approved :: ISC License (ISCL)
 Classifier: Operating System :: POSIX
 Classifier: Operating System :: MacOS :: MacOS X
 Classifier: Programming Language :: Python
-Classifier: Programming Language :: Python :: 2.6
 Classifier: Programming Language :: Python :: 2.7
 Classifier: Programming Language :: Python :: 3
 Classifier: Topic :: Software Development
diff --git a/pexpect.egg-info/SOURCES.txt b/pexpect.egg-info/SOURCES.txt
new file mode 100644
index 0000000..cf6e4ca
--- /dev/null
+++ b/pexpect.egg-info/SOURCES.txt
@@ -0,0 +1,150 @@
+.coveragerc
+LICENSE
+MANIFEST.in
+README.rst
+setup.cfg
+setup.py
+doc/FAQ.rst
+doc/Makefile
+doc/clean.css
+doc/commonissues.rst
+doc/conf.py
+doc/examples.rst
+doc/history.rst
+doc/index.rst
+doc/install.rst
+doc/make.bat
+doc/overview.rst
+doc/requirements.txt
+doc/api/fdpexpect.rst
+doc/api/index.rst
+doc/api/pexpect.rst
+doc/api/popen_spawn.rst
+doc/api/pxssh.rst
+doc/api/replwrap.rst
+doc/sphinxext/github.py
+examples/README
+examples/astat.py
+examples/cgishell.cgi
+examples/chess.py
+examples/chess2.py
+examples/chess3.py
+examples/df.py
+examples/ftp.py
+examples/hive.py
+examples/monitor.py
+examples/passmass.py
+examples/python.py
+examples/script.py
+examples/ssh_tunnel.py
+examples/table_test.html
+examples/telnet.py
+examples/topip.py
+examples/uptime.py
+pexpect/ANSI.py
+pexpect/FSM.py
+pexpect/__init__.py
+pexpect/async.py
+pexpect/bashrc.sh
+pexpect/exceptions.py
+pexpect/expect.py
+pexpect/fdpexpect.py
+pexpect/popen_spawn.py
+pexpect/pty_spawn.py
+pexpect/pxssh.py
+pexpect/replwrap.py
+pexpect/run.py
+pexpect/screen.py
+pexpect/spawnbase.py
+pexpect/utils.py
+pexpect.egg-info/PKG-INFO
+pexpect.egg-info/SOURCES.txt
+pexpect.egg-info/dependency_links.txt
+pexpect.egg-info/requires.txt
+pexpect.egg-info/top_level.txt
+tests/.coverage.docker-2.local.36578.771124
+tests/.coverage.docker-2.local.36579.455415
+tests/.coverage.docker-2.local.36580.123114
+tests/.coverage.docker-2.local.36581.321253
+tests/.coverage.docker-2.local.38943.357232
+tests/.coverage.docker-2.local.38944.471090
+tests/.coverage.docker-2.local.38945.54089
+tests/.coverage.docker-2.local.38946.82776
+tests/.coverage.docker-2.local.38984.172622
+tests/.coverage.docker-2.local.38985.978020
+tests/.coverage.docker-2.local.38986.928811
+tests/.coverage.docker-2.local.38987.237434
+tests/.coverage.docker-2.local.38991.12925
+tests/.coverage.docker-2.local.38993.581713
+tests/.coverage.docker-2.local.39001.377317
+tests/.coverage.docker-2.local.39003.638674
+tests/.coverage.docker-2.local.39005.280448
+tests/PexpectTestCase.py
+tests/README
+tests/TESTDATA.txt
+tests/__init__.py
+tests/adhoc.py
+tests/alarm_die.py
+tests/bambi.vt
+tests/cc.c
+tests/depricated_test_filedescriptor.py
+tests/echo_w_prompt.py
+tests/echo_wait.py
+tests/exit1.py
+tests/exit667.c
+tests/getch.py
+tests/globe.vt
+tests/interact.py
+tests/list100.py
+tests/log
+tests/needs_kill.py
+tests/pexpectTest.py
+tests/qa.py
+tests/sigwinch_report.py
+tests/sleep_for.py
+tests/swapcase_echo.py
+tests/test_FSM.py
+tests/test_ansi.py
+tests/test_async.py
+tests/test_command_list_split.py
+tests/test_constructor.py
+tests/test_ctrl_chars.py
+tests/test_delay.py
+tests/test_destructor.py
+tests/test_dotall.py
+tests/test_env.py
+tests/test_expect.py
+tests/test_filedescriptor.py
+tests/test_interact.py
+tests/test_isalive.py
+tests/test_issue209.py
+tests/test_log.py
+tests/test_misc.py
+tests/test_missing_command.py
+tests/test_performance.py
+tests/test_pickling.py
+tests/test_popen_spawn.py
+tests/test_pxssh.py
+tests/test_replwrap.py
+tests/test_repr.py
+tests/test_run.py
+tests/test_run_out_of_pty.py
+tests/test_screen.py
+tests/test_socket.py
+tests/test_timeout_pattern.py
+tests/test_unicode.py
+tests/test_which.py
+tests/test_winsize.py
+tests/tetris.data
+tests/ticker.py
+tests/torturet.vt
+tests/utils.py
+tests/fakessh/ssh
+tests/platform_checks/README
+tests/platform_checks/check.py
+tests/platform_checks/check2.py
+tests/platform_checks/check_control_terminal.py
+tests/platform_checks/check_handler.py
+tests/platform_checks/check_read.py
+tests/platform_checks/check_signals.py
+tests/platform_checks/CSIGNALTEST/test.c
\ No newline at end of file
diff --git a/pexpect.egg-info/dependency_links.txt b/pexpect.egg-info/dependency_links.txt
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/pexpect.egg-info/dependency_links.txt
@@ -0,0 +1 @@
+
diff --git a/pexpect.egg-info/requires.txt b/pexpect.egg-info/requires.txt
new file mode 100644
index 0000000..13074f3
--- /dev/null
+++ b/pexpect.egg-info/requires.txt
@@ -0,0 +1 @@
+ptyprocess>=0.5
diff --git a/pexpect.egg-info/top_level.txt b/pexpect.egg-info/top_level.txt
new file mode 100644
index 0000000..808fb07
--- /dev/null
+++ b/pexpect.egg-info/top_level.txt
@@ -0,0 +1 @@
+pexpect
diff --git a/pexpect/__init__.py b/pexpect/__init__.py
index 3d1b42b..045fe36 100644
--- a/pexpect/__init__.py
+++ b/pexpect/__init__.py
@@ -75,7 +75,7 @@ if sys.platform != 'win32':
     from .pty_spawn import spawn, spawnu
     from .run import run, runu
 
-__version__ = '4.0.1'
+__version__ = '4.2.0'
 __revision__ = ''
 __all__ = ['ExceptionPexpect', 'EOF', 'TIMEOUT', 'spawn', 'spawnu', 'run', 'runu',
            'which', 'split_command_line', '__version__', '__revision__']
diff --git a/pexpect/async.py b/pexpect/async.py
index ad75994..136fc0e 100644
--- a/pexpect/async.py
+++ b/pexpect/async.py
@@ -23,6 +23,7 @@ def expect_async(expecter, timeout=None):
         return expecter.timeout(e)
 
 class PatternWaiter(asyncio.Protocol):
+    transport = None
     def __init__(self, expecter):
         self.expecter = expecter
         self.fut = asyncio.Future()
@@ -30,10 +31,15 @@ class PatternWaiter(asyncio.Protocol):
     def found(self, result):
         if not self.fut.done():
             self.fut.set_result(result)
+            self.transport.pause_reading()
     
     def error(self, exc):
         if not self.fut.done():
             self.fut.set_exception(exc)
+            self.transport.pause_reading()
+
+    def connection_made(self, transport):
+        self.transport = transport
     
     def data_received(self, data):
         spawn = self.expecter.spawn
@@ -41,11 +47,11 @@ class PatternWaiter(asyncio.Protocol):
         spawn._log(s, 'read')
 
         if self.fut.done():
-            spawn.buffer += data
+            spawn.buffer += s
             return
 
         try:
-            index = self.expecter.new_data(data)
+            index = self.expecter.new_data(s)
             if index is not None:
                 # Found a match
                 self.found(index)
diff --git a/pexpect/bashrc.sh b/pexpect/bashrc.sh
new file mode 100644
index 0000000..99a3ac2
--- /dev/null
+++ b/pexpect/bashrc.sh
@@ -0,0 +1,5 @@
+source /etc/bash.bashrc
+source ~/.bashrc
+
+# Reset PS1 so pexpect can find it
+PS1="$"
diff --git a/pexpect/expect.py b/pexpect/expect.py
index 6fde9e8..660cfb5 100644
--- a/pexpect/expect.py
+++ b/pexpect/expect.py
@@ -44,6 +44,7 @@ class Expecter(object):
             spawn.match = None
             spawn.match_index = None
             msg = str(spawn)
+            msg += '\nsearcher: %s' % self.searcher
             if err is not None:
                 msg = str(err) + '\n' + msg
             raise EOF(msg)
@@ -63,6 +64,7 @@ class Expecter(object):
             spawn.match = None
             spawn.match_index = None
             msg = str(spawn)
+            msg += '\nsearcher: %s' % self.searcher
             if err is not None:
                 msg = str(err) + '\n' + msg
             raise TIMEOUT(msg)
@@ -95,7 +97,8 @@ class Expecter(object):
                     return self.timeout()
                 # Still have time left, so read more data
                 incoming = spawn.read_nonblocking(spawn.maxread, timeout)
-                time.sleep(0.0001)
+                if self.spawn.delayafterread is not None:
+                    time.sleep(self.spawn.delayafterread)
                 if timeout is not None:
                     timeout = end_time - time.time()
         except EOF as e:
@@ -294,4 +297,4 @@ class searcher_re(object):
         self.start = first_match
         self.match = the_match
         self.end = self.match.end()
-        return best_index
\ No newline at end of file
+        return best_index
diff --git a/pexpect/fdpexpect.py b/pexpect/fdpexpect.py
index dd1b492..ac7443e 100644
--- a/pexpect/fdpexpect.py
+++ b/pexpect/fdpexpect.py
@@ -22,7 +22,8 @@ PEXPECT LICENSE
 '''
 
 from .spawnbase import SpawnBase
-from .exceptions import ExceptionPexpect
+from .exceptions import ExceptionPexpect, TIMEOUT
+from .utils import select_ignore_interrupts
 import os
 
 __all__ = ['fdspawn']
@@ -112,3 +113,30 @@ class fdspawn(SpawnBase):
         "Call self.write() for each item in sequence"
         for s in sequence:
             self.write(s)
+
+    def read_nonblocking(self, size=1, timeout=-1):
+        """
+        Read from the file descriptor and return the result as a string.
+
+        The read_nonblocking method of :class:`SpawnBase` assumes that a call
+        to os.read will not block (timeout parameter is ignored). This is not
+        the case for POSIX file-like objects such as sockets and serial ports.
+
+        Use :func:`select.select`, timeout is implemented conditionally for
+        POSIX systems.
+
+        :param int size: Read at most *size* bytes.
+        :param int timeout: Wait timeout seconds for file descriptor to be
+            ready to read. When -1 (default), use self.timeout. When 0, poll.
+        :return: String containing the bytes read
+        """
+        if os.name == 'posix':
+            if timeout == -1:
+                timeout = self.timeout
+            rlist = [self.child_fd]
+            wlist = []
+            xlist = []
+            rlist, wlist, xlist = select_ignore_interrupts(rlist, wlist, xlist, timeout)
+            if self.child_fd not in rlist:
+                raise TIMEOUT('Timeout exceeded.')
+        return super(fdspawn, self).read_nonblocking(size)
diff --git a/pexpect/pty_spawn.py b/pexpect/pty_spawn.py
index 1d9554b..d1c6df7 100644
--- a/pexpect/pty_spawn.py
+++ b/pexpect/pty_spawn.py
@@ -1,7 +1,6 @@
 import os
 import sys
 import time
-import select
 import pty
 import tty
 import errno
@@ -13,7 +12,7 @@ from ptyprocess.ptyprocess import use_native_pty_fork
 
 from .exceptions import ExceptionPexpect, EOF, TIMEOUT
 from .spawnbase import SpawnBase
-from .utils import which, split_command_line
+from .utils import which, split_command_line, select_ignore_interrupts
 
 @contextmanager
 def _wrap_ptyprocess_err():
@@ -144,8 +143,7 @@ class spawn(SpawnBase):
         many users that I decided that the default pexpect behavior should be
         to sleep just before writing to the child application. 1/20th of a
         second (50 ms) seems to be enough to clear up the problem. You can set
-        delaybeforesend to 0 to return to the old behavior. Most Linux machines
-        don't like this to be below 0.03. I don't know why.
+        delaybeforesend to None to return to the old behavior.
 
         Note that spawn is clever about finding commands on your path.
         It uses the same logic that "which" uses to find executables.
@@ -155,7 +153,12 @@ class spawn(SpawnBase):
         in self.exitstatus or self.signalstatus. If the child exited normally
         then exitstatus will store the exit return code and signalstatus will
         be None. If the child was terminated abnormally with a signal then
-        signalstatus will store the signal value and exitstatus will be None.
+        signalstatus will store the signal value and exitstatus will be None::
+
+            child = pexpect.spawn('some_command')
+            child.close()
+            print(child.exitstatus, child.signalstatus)
+
         If you need more detail you can also read the self.status member which
         stores the status returned by os.waitpid. You can interpret this using
         os.WIFEXITED/os.WEXITSTATUS or os.WIFSIGNALED/os.TERMSIG.
@@ -201,7 +204,6 @@ class spawn(SpawnBase):
         s.append(repr(self))
         s.append('command: ' + str(self.command))
         s.append('args: %r' % (self.args,))
-        s.append('searcher: %r' % (self.searcher,))
         s.append('buffer (last 100 chars): %r' % (
                 self.buffer[-100:] if self.buffer else self.buffer,))
         s.append('before (last 100 chars): %r' % (
@@ -210,7 +212,8 @@ class spawn(SpawnBase):
         s.append('match: %r' % (self.match,))
         s.append('match_index: ' + str(self.match_index))
         s.append('exitstatus: ' + str(self.exitstatus))
-        s.append('flag_eof: ' + str(self.flag_eof))
+        if hasattr(self, 'ptyproc'):
+            s.append('flag_eof: ' + str(self.flag_eof))
         s.append('pid: ' + str(self.pid))
         s.append('child_fd: ' + str(self.child_fd))
         s.append('closed: ' + str(self.closed))
@@ -261,7 +264,7 @@ class spawn(SpawnBase):
             self.args.insert(0, command)
             self.command = command
 
-        command_with_path = which(self.command)
+        command_with_path = which(self.command, env=self.env)
         if command_with_path is None:
             raise ExceptionPexpect('The command was not found or was not ' +
                     'executable: %s.' % self.command)
@@ -285,8 +288,13 @@ class spawn(SpawnBase):
         if dimensions is not None:
             kwargs['dimensions'] = dimensions
 
-        self.ptyproc = ptyprocess.PtyProcess.spawn(self.args, env=self.env,
-                                                   cwd=self.cwd, **kwargs)
+        if self.encoding is not None:
+            # Encode command line using the specified encoding
+            self.args = [a if isinstance(a, bytes) else a.encode(self.encoding)
+                         for a in self.args]
+
+        self.ptyproc = self._spawnpty(self.args, env=self.env,
+                                     cwd=self.cwd, **kwargs)
 
         self.pid = self.ptyproc.pid
         self.child_fd = self.ptyproc.fd
@@ -295,6 +303,10 @@ class spawn(SpawnBase):
         self.terminated = False
         self.closed = False
 
+    def _spawnpty(self, args, **kwargs):
+        '''Spawn a pty and return an instance of PtyProcess.'''
+        return ptyprocess.PtyProcess.spawn(args, **kwargs)
+
     def close(self, force=True):
         '''This closes the connection with the child application. Note that
         calling close() more than once is valid. This emulates standard Python
@@ -390,8 +402,6 @@ class spawn(SpawnBase):
         '''
         return self.ptyproc.setecho(state)
 
-        self.echo = state
-
     def read_nonblocking(self, size=1, timeout=-1):
         '''This reads at most size characters from the child application. It
         includes a timeout. If the read does not complete within the timeout
@@ -426,7 +436,7 @@ class spawn(SpawnBase):
         # If isalive() is false, then I pretend that this is the same as EOF.
         if not self.isalive():
             # timeout of 0 means "poll"
-            r, w, e = self.__select([self.child_fd], [], [], 0)
+            r, w, e = select_ignore_interrupts([self.child_fd], [], [], 0)
             if not r:
                 self.flag_eof = True
                 raise EOF('End Of File (EOF). Braindead platform.')
@@ -434,12 +444,12 @@ class spawn(SpawnBase):
             # Irix takes a long time before it realizes a child was terminated.
             # FIXME So does this mean Irix systems are forced to always have
             # FIXME a 2 second delay when calling read_nonblocking? That sucks.
-            r, w, e = self.__select([self.child_fd], [], [], 2)
+            r, w, e = select_ignore_interrupts([self.child_fd], [], [], 2)
             if not r and not self.isalive():
                 self.flag_eof = True
                 raise EOF('End Of File (EOF). Slow platform.')
 
-        r, w, e = self.__select([self.child_fd], [], [], timeout)
+        r, w, e = select_ignore_interrupts([self.child_fd], [], [], timeout)
 
         if not r:
             if not self.isalive():
@@ -487,9 +497,9 @@ class spawn(SpawnBase):
 
         This value may be discovered using fpathconf(3)::
 
-        >>> from os import fpathconf
-        >>> print(fpathconf(0, 'PC_MAX_CANON'))
-        256
+            >>> from os import fpathconf
+            >>> print(fpathconf(0, 'PC_MAX_CANON'))
+            256
 
         On such a system, only 256 bytes may be received per line. Any
         subsequent bytes received will be discarded. BEL (``'\a'``) is then
@@ -500,13 +510,14 @@ class spawn(SpawnBase):
         Canonical input processing may be disabled altogether by executing
         a shell, then stty(1), before executing the final program::
 
-        >>> bash = pexpect.spawn('/bin/bash', echo=False)
-        >>> bash.sendline('stty -icanon')
-        >>> bash.sendline('base64')
-        >>> bash.sendline('x' * 5000)
+            >>> bash = pexpect.spawn('/bin/bash', echo=False)
+            >>> bash.sendline('stty -icanon')
+            >>> bash.sendline('base64')
+            >>> bash.sendline('x' * 5000)
         '''
 
-        time.sleep(self.delaybeforesend)
+        if self.delaybeforesend is not None:
+            time.sleep(self.delaybeforesend)
 
         s = self._coerce_send_string(s)
         self._log(s, 'send')
@@ -520,10 +531,8 @@ class spawn(SpawnBase):
         written.  Only a limited number of bytes may be sent for each
         line in the default terminal mode, see docstring of :meth:`send`.
         '''
-
-        n = self.send(s)
-        n = n + self.send(self.linesep)
-        return n
+        s = self._coerce_send_string(s)
+        return self.send(s + self.linesep)
 
     def _log_control(self, s):
         """Write control characters to the appropriate log files"""
@@ -758,7 +767,7 @@ class spawn(SpawnBase):
         '''
 
         while self.isalive():
-            r, w, e = self.__select([self.child_fd, self.STDIN_FILENO], [], [])
+            r, w, e = select_ignore_interrupts([self.child_fd, self.STDIN_FILENO], [], [])
             if self.child_fd in r:
                 try:
                     data = self.__interact_read(self.child_fd)
@@ -790,33 +799,6 @@ class spawn(SpawnBase):
                 self._log(data, 'send')
                 self.__interact_writen(self.child_fd, data)
 
-    def __select(self, iwtd, owtd, ewtd, timeout=None):
-
-        '''This is a wrapper around select.select() that ignores signals. If
-        select.select raises a select.error exception and errno is an EINTR
-        error then it is ignored. Mainly this is used to ignore sigwinch
-        (terminal resize). '''
-
-        # if select() is interrupted by a signal (errno==EINTR) then
-        # we loop back and enter the select() again.
-        if timeout is not None:
-            end_time = time.time() + timeout
-        while True:
-            try:
-                return select.select(iwtd, owtd, ewtd, timeout)
-            except select.error:
-                err = sys.exc_info()[1]
-                if err.args[0] == errno.EINTR:
-                    # if we loop back we have to subtract the
-                    # amount of time we already waited.
-                    if timeout is not None:
-                        timeout = end_time - time.time()
-                        if timeout < 0:
-                            return([], [], [])
-                else:
-                    # something else caused the select.error, so
-                    # this actually is an exception.
-                    raise
 
 def spawnu(*args, **kwargs):
     """Deprecated: pass encoding to spawn() instead."""
diff --git a/pexpect/pxssh.py b/pexpect/pxssh.py
index 4638164..d5aec8a 100644
--- a/pexpect/pxssh.py
+++ b/pexpect/pxssh.py
@@ -46,7 +46,7 @@ class pxssh (spawn):
 
     Example that runs a few commands on a remote server and prints the result::
 
-        import pxssh
+        from pexpect import pxssh
         import getpass
         try:
             s = pxssh.pxssh()
@@ -70,7 +70,7 @@ class pxssh (spawn):
 
     Example showing how to specify SSH options::
 
-        import pxssh
+        from pexpect import pxssh
         s = pxssh.pxssh(options={
                             "StrictHostKeyChecking": "no",
                             "UserKnownHostsFile": "/dev/null"})
diff --git a/pexpect/spawnbase.py b/pexpect/spawnbase.py
index 0518d83..5dd24b5 100644
--- a/pexpect/spawnbase.py
+++ b/pexpect/spawnbase.py
@@ -62,7 +62,7 @@ class SpawnBase(object):
         # Data before searchwindowsize point is preserved, but not searched.
         self.searchwindowsize = searchwindowsize
         # Delay used before sending data to child. Time in seconds.
-        # Most Linux machines don't like this to be below 0.03 (30 ms).
+        # Set this to None to skip the time.sleep() call completely.
         self.delaybeforesend = 0.05
         # Used by close() to give kernel time to update process status.
         # Time in seconds.
@@ -70,6 +70,12 @@ class SpawnBase(object):
         # Used by terminate() to give kernel time to update process status.
         # Time in seconds.
         self.delayafterterminate = 0.1
+        # Delay in seconds to sleep after each call to read_nonblocking().
+        # Set this to None to skip the time.sleep() call completely: that
+        # would restore the behavior from pexpect-2.0 (for performance
+        # reasons or because you don't want to release Python's global
+        # interpreter lock).
+        self.delayafterread = 0.0001
         self.softspace = False
         self.name = '<' + repr(self) + '>'
         self.closed = True
diff --git a/pexpect/utils.py b/pexpect/utils.py
index 737f0ed..ae0fe9d 100644
--- a/pexpect/utils.py
+++ b/pexpect/utils.py
@@ -1,6 +1,15 @@
 import os
 import sys
 import stat
+import select
+import time
+import errno
+
+try:
+    InterruptedError
+except NameError:
+    # Alias Python2 exception to Python3
+    InterruptedError = select.error
 
 
 def is_executable_file(path):
@@ -31,7 +40,7 @@ def is_executable_file(path):
     return os.access(fpath, os.X_OK)
 
 
-def which(filename):
+def which(filename, env=None):
     '''This takes a given filename; tries to find it in the environment path;
     then checks if it is executable. This returns the full path to the filename
     if found and executable. Otherwise this returns None.'''
@@ -39,10 +48,11 @@ def which(filename):
     # Special case where filename contains an explicit path.
     if os.path.dirname(filename) != '' and is_executable_file(filename):
         return filename
-    if 'PATH' not in os.environ or os.environ['PATH'] == '':
+    if env is None:
+        env = os.environ
+    p = env.get('PATH')
+    if not p:
         p = os.defpath
-    else:
-        p = os.environ['PATH']
     pathlist = p.split(os.pathsep)
     for path in pathlist:
         ff = os.path.join(path, filename)
@@ -110,3 +120,32 @@ def split_command_line(command_line):
     if arg != '':
         arg_list.append(arg)
     return arg_list
+
+
+def select_ignore_interrupts(iwtd, owtd, ewtd, timeout=None):
+
+    '''This is a wrapper around select.select() that ignores signals. If
+    select.select raises a select.error exception and errno is an EINTR
+    error then it is ignored. Mainly this is used to ignore sigwinch
+    (terminal resize). '''
+
+    # if select() is interrupted by a signal (errno==EINTR) then
+    # we loop back and enter the select() again.
+    if timeout is not None:
+        end_time = time.time() + timeout
+    while True:
+        try:
+            return select.select(iwtd, owtd, ewtd, timeout)
+        except InterruptedError:
+            err = sys.exc_info()[1]
+            if err.args[0] == errno.EINTR:
+                # if we loop back we have to subtract the
+                # amount of time we already waited.
+                if timeout is not None:
+                    timeout = end_time - time.time()
+                    if timeout < 0:
+                        return([], [], [])
+            else:
+                # something else caused the select.error, so
+                # this actually is an exception.
+                raise
diff --git a/setup.cfg b/setup.cfg
index ae62686..23bfafb 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -1,2 +1,11 @@
... 1322 lines suppressed ...

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/python-modules/packages/pexpect.git



More information about the Python-modules-commits mailing list