summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/FAQ.rst43
-rw-r--r--doc/api/ANSI.rst14
-rw-r--r--doc/api/index.rst9
-rw-r--r--doc/api/screen.rst10
-rw-r--r--doc/commonissues.rst14
-rw-r--r--doc/conf.py4
-rw-r--r--doc/history.rst18
-rw-r--r--doc/overview.rst2
-rw-r--r--pexpect/fdpexpect.py9
-rw-r--r--pexpect/pty_spawn.py75
-rw-r--r--pexpect/pxssh.py11
-rw-r--r--pexpect/screen.py7
-rw-r--r--pexpect/spawnbase.py29
-rwxr-xr-xtests/getch.py6
-rwxr-xr-xtests/interact.py16
-rw-r--r--tests/interact_unicode.py24
-rwxr-xr-xtests/sigwinch_report.py1
-rwxr-xr-xtests/test_interact.py67
-rwxr-xr-xtests/test_misc.py6
-rw-r--r--tests/test_unicode.py9
-rw-r--r--tests/test_which.py9
-rwxr-xr-xtests/test_winsize.py59
22 files changed, 233 insertions, 209 deletions
diff --git a/doc/FAQ.rst b/doc/FAQ.rst
index bec1c35..1964b12 100644
--- a/doc/FAQ.rst
+++ b/doc/FAQ.rst
@@ -1,6 +1,17 @@
FAQ
===
+**Q: Where can I get help with pexpect? Is there a mailing list?**
+
+A: You can use the `pexpect tag on Stackoverflow <http://stackoverflow.com/questions/tagged/pexpect>`__
+to ask questions specifically related to Pexpect. For more general Python
+support, there's the python-list_ mailing list, and the `#python`_
+IRC channel. Please refrain from using github for general
+python or systems scripting support.
+
+.. _python-list: https://mail.python.org/mailman/listinfo/python-list
+.. _#python: https://www.python.org/community/irc/
+
**Q: Why don't shell pipe and redirect (| and >) work when I spawn a command?**
A: Remember that Pexpect does NOT interpret shell meta characters such as
@@ -21,15 +32,6 @@ previous example::
child = pexpect.spawn('/bin/bash', ['-c', shell_cmd])
child.expect(pexpect.EOF)
-**Q: Isn't there already a Python Expect?**
-
-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 became possible with the introduction of
-the pty module in the standard Python library. Previously, C extensions
-were required.
-
**Q: The `before` and `after` properties sound weird.**
A: This is how the -B and -A options in grep works, so that made it
@@ -126,11 +128,18 @@ another application.
**Q: Can I do screen scraping with this thing?**
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.
-
-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 (see :mod:`pexpect.ANSI`), but I have
-no working examples at this time.
+this is easy. If a program emits many terminal sequences, from video
+attributes to screen addressing, such as programs using curses, then
+it may become very difficult to ascertain what text is displayed on a screen.
+
+We suggest using the `pyte <https://github.com/selectel/pyte>`_ library to
+screen-scrape. The module :mod:`pexpect.ANSI` released with previous versions
+of pexpect is now marked deprecated and may be removed in the future.
+
+**Q: I get strange behavior with pexect and gevent**
+
+A: Pexpect uses fork(2), exec(2), select(2), waitpid(2), and implements its
+own selector in expect family of calls. pexpect has been known to misbehave
+when paired with gevent. A solution might be to isolate your pexpect
+dependent code from any frameworks that manipulate event selection behavior
+by running it in an another process entirely.
diff --git a/doc/api/ANSI.rst b/doc/api/ANSI.rst
deleted file mode 100644
index 064563d..0000000
--- a/doc/api/ANSI.rst
+++ /dev/null
@@ -1,14 +0,0 @@
-ANSI - ANSI (VT100) terminal emulator
-=====================================
-
-.. automodule:: pexpect.ANSI
-
-.. autoclass:: term
- :show-inheritance:
-
-.. autoclass:: ANSI
- :show-inheritance:
-
- .. automethod:: write_ch
- .. automethod:: write
- .. automethod:: process \ No newline at end of file
diff --git a/doc/api/index.rst b/doc/api/index.rst
index 1a6a6ae..fd017a5 100644
--- a/doc/api/index.rst
+++ b/doc/api/index.rst
@@ -8,5 +8,10 @@ API documentation
fdpexpect
replwrap
pxssh
- screen
- ANSI
+
+The modules ``pexpect.screen`` and ``pexpect.ANSI`` have been deprecated in
+Pexpect version 4. They were separate from the main use cases for Pexpect, and
+there are better maintained Python terminal emulator packages, such as
+`pyte <https://pypi.python.org/pypi/pyte>`__.
+These modules are still present for now, but we don't advise using them in new
+code.
diff --git a/doc/api/screen.rst b/doc/api/screen.rst
deleted file mode 100644
index 8268fb9..0000000
--- a/doc/api/screen.rst
+++ /dev/null
@@ -1,10 +0,0 @@
-screen - manage a virtual 'screen'
-==================================
-
-.. automodule:: pexpect.screen
-
-.. autoclass:: screen
- :members:
-
- .. automethod:: __init__
- .. automethod:: __str__ \ No newline at end of file
diff --git a/doc/commonissues.rst b/doc/commonissues.rst
index 26d0e2b..d3aa9d0 100644
--- a/doc/commonissues.rst
+++ b/doc/commonissues.rst
@@ -49,20 +49,6 @@ off::
child = pexpect.spawn ("ssh user@example.com")
child.delaybeforesend = 0
-Timing issue with isalive()
----------------------------
-
-Reading the state of :meth:`~pexpect.spawn.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
-:meth:`~pexpect.spawn.isalive` executes. Addings a slight delay before the
-:meth:`~pexpect.spawn.isalive` call will help. For example::
-
- child = pexpect.spawn('ls')
- child.expect(pexpect.EOF)
- time.sleep(0.1)
- print child.isalive()
-
Truncated output just before child exits
----------------------------------------
diff --git a/doc/conf.py b/doc/conf.py
index 3dd5d3e..305ad6a 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 = '3.3'
+version = '4.0'
# The full version, including alpha/beta/rc tags.
-release = '3.3'
+release = '4.0.dev'
# 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 7844270..b33e4d9 100644
--- a/doc/history.rst
+++ b/doc/history.rst
@@ -17,15 +17,27 @@ Version 4.0
* It is now possible to call :meth:`~.wait` multiple times, or after a process
is already determined to be terminated without raising an exception
(:ghpull:`211`).
-
-Version 3.4
-```````````
+* New :class:`pexpect.spawn` keyword argument, ``dimensions=(rows, columns)``
+ allows setting terminal screen dimensions before launching a program
+ (:ghissue:`122`).
* Fix regression that prevented executable, but unreadable files from
being found when not specified by absolute path -- such as
/usr/bin/sudo (:ghissue:`104`).
* Fixed regression when executing pexpect with some prior releases of
the multiprocessing module where stdin has been closed (:ghissue:`86`).
+Backwards incompatible changes
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+* Deprecated ``pexpect.screen`` and ``pexpect.ANSI``. Please use other packages
+ such as `pyte <https://pypi.python.org/pypi/pyte>`__ to emulate a terminal.
+* Removed the independent top-level modules (``pxssh fdpexpect FSM screen ANSI``)
+ which were installed alongside Pexpect. These were moved into the Pexpect
+ package in 3.0, but the old names were left as aliases.
+* Child processes created by Pexpect no longer ignore SIGHUP by default: the
+ ``ignore_sighup`` parameter of :class:`pexpect.spawn` defaults to False. To
+ get the old behaviour, pass ``ignore_sighup=True``.
+
Version 3.3
```````````
diff --git a/doc/overview.rst b/doc/overview.rst
index 139ba36..c5bcb05 100644
--- a/doc/overview.rst
+++ b/doc/overview.rst
@@ -234,7 +234,7 @@ If you wish to read up to the end of the child's output without generating an
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 method ignore a timeout and block indefinitely by passing
+You can have these methods ignore timeout and block indefinitely by passing
``None`` for the timeout parameter::
child.expect(pexpect.EOF, timeout=None)
diff --git a/pexpect/fdpexpect.py b/pexpect/fdpexpect.py
index 2b51e24..ca8cf07 100644
--- a/pexpect/fdpexpect.py
+++ b/pexpect/fdpexpect.py
@@ -32,7 +32,8 @@ class fdspawn(SpawnBase):
descriptor. For example, you could use it to read through a file looking
for patterns, or to control a modem or serial device. '''
- def __init__ (self, fd, args=None, timeout=30, maxread=2000, searchwindowsize=None, logfile=None):
+ def __init__ (self, fd, args=None, timeout=30, maxread=2000, searchwindowsize=None,
+ logfile=None, encoding=None, codec_errors='strict'):
'''This takes a file descriptor (an int) or an object that support the
fileno() method (returning an int). All Python file-like objects
support fileno(). '''
@@ -50,7 +51,8 @@ class fdspawn(SpawnBase):
self.args = None
self.command = None
- SpawnBase.__init__(self, timeout, maxread, searchwindowsize, logfile)
+ SpawnBase.__init__(self, timeout, maxread, searchwindowsize, logfile,
+ encoding=encoding, codec_errors=codec_errors)
self.child_fd = fd
self.own_fd = False
self.closed = False
@@ -93,7 +95,8 @@ class fdspawn(SpawnBase):
s = self._coerce_send_string(s)
self._log(s, 'send')
- return os.write(self.child_fd, s)
+ b = self._encoder.encode(s, final=False)
+ return os.write(self.child_fd, b)
def sendline(self, s):
"Write to fd with trailing newline, return number of bytes written"
diff --git a/pexpect/pty_spawn.py b/pexpect/pty_spawn.py
index 380fb15..09c008b 100644
--- a/pexpect/pty_spawn.py
+++ b/pexpect/pty_spawn.py
@@ -36,8 +36,8 @@ class spawn(SpawnBase):
def __init__(self, command, args=[], timeout=30, maxread=2000,
searchwindowsize=None, logfile=None, cwd=None, env=None,
- ignore_sighup=True, echo=True, preexec_fn=None,
- encoding=None, codec_errors='strict'):
+ ignore_sighup=False, echo=True, preexec_fn=None,
+ encoding=None, codec_errors='strict', dimensions=None):
'''This is the constructor. The command parameter may be a string that
includes a command and any arguments to the command. For example::
@@ -78,15 +78,19 @@ class spawn(SpawnBase):
output are read back from the child. This feature is useful in
conjunction with searchwindowsize.
- The searchwindowsize attribute sets the how far back in the incoming
- seach buffer Pexpect will search for pattern matches. Every time
- Pexpect reads some data from the child it will append the data to the
- incoming buffer. The default is to search from the beginning of the
- incoming buffer each time new data is read from the child. But this is
- very inefficient if you are running a command that generates a large
- amount of data where you want to match. The searchwindowsize does not
- affect the size of the incoming data buffer. You will still have
- access to the full buffer after expect() returns.
+ When the keyword argument *searchwindowsize* is None (default), the
+ full buffer is searched at each iteration of receiving incoming data.
+ The default number of bytes scanned at each iteration is very large
+ and may be reduced to collaterally reduce search cost. After
+ :meth:`~.expect` returns, the full buffer attribute remains up to
+ size *maxread* irrespective of *searchwindowsize* value.
+
+ When the keyword argument ``timeout`` is specified as a number,
+ (default: *30*), then :class:`TIMEOUT` will be raised after the value
+ specified has elapsed, in seconds, for any of the :meth:`~.expect`
+ family of method calls. When None, TIMEOUT will not be raised, and
+ :meth:`~.expect` may block indefinitely until match.
+
The logfile member turns on or off logging. All input and output will
be copied to the given file object. Set logfile to None to stop
@@ -117,7 +121,7 @@ class spawn(SpawnBase):
child = pexpect.spawn('some_command')
child.logfile_read = sys.stdout
- Remember to use spawnu instead of spawn for the above code if you are
+ You will need to pass an encoding to spawn in the above code if you are
using Python 3.
To separately log output sent to the child use logfile_send::
@@ -125,9 +129,8 @@ class spawn(SpawnBase):
child.logfile_send = fout
If ``ignore_sighup`` is True, the child process will ignore SIGHUP
- signals. For now, the default is True, to preserve the behaviour of
- earlier versions of Pexpect, but you should pass this explicitly if you
- want to rely on it.
+ signals. The default is False from Pexpect 4.0, meaning that SIGHUP
+ will be handled normally by the child.
The delaybeforesend helps overcome a weird behavior that many users
were experiencing. The typical problem was that a user would expect() a
@@ -170,6 +173,10 @@ class spawn(SpawnBase):
If preexec_fn is given, it will be called in the child process before
launching the given command. This is useful to e.g. reset inherited
signal handlers.
+
+ The dimensions attribute specifies the size of the pseudo-terminal as
+ seen by the subprocess, and is specified as a two-entry tuple (rows,
+ columns). If this is unspecified, the defaults in ptyprocess will apply.
'''
super(spawn, self).__init__(timeout=timeout, maxread=maxread, searchwindowsize=searchwindowsize,
logfile=logfile, encoding=encoding, codec_errors=codec_errors)
@@ -186,7 +193,7 @@ class spawn(SpawnBase):
self.args = None
self.name = '<pexpect factory incomplete>'
else:
- self._spawn(command, args, preexec_fn)
+ self._spawn(command, args, preexec_fn, dimensions)
def __str__(self):
'''This returns a human-readable string that represents the state of
@@ -222,7 +229,7 @@ class spawn(SpawnBase):
s.append('delayafterterminate: ' + str(self.delayafterterminate))
return '\n'.join(s)
- def _spawn(self, command, args=[], preexec_fn=None):
+ def _spawn(self, command, args=[], preexec_fn=None, dimensions=None):
'''This starts the given command in a child process. This does all the
fork/exec type of stuff for a pty. This is called by __init__. If args
is empty then command will be parsed (split on spaces) and args will be
@@ -277,6 +284,9 @@ class spawn(SpawnBase):
preexec_fn()
kwargs['preexec_fn'] = preexec_wrapper
+ if dimensions is not None:
+ kwargs['dimensions'] = dimensions
+
self.ptyproc = ptyprocess.PtyProcess.spawn(self.args, env=self.env,
cwd=self.cwd, **kwargs)
@@ -295,7 +305,7 @@ class spawn(SpawnBase):
and SIGINT). '''
self.flush()
- self.ptyproc.close()
+ self.ptyproc.close(force=force)
self.isalive() # Update exit status from ptyproc
self.child_fd = -1
@@ -388,8 +398,8 @@ class spawn(SpawnBase):
'''This reads at most size characters from the child application. It
includes a timeout. If the read does not complete within the timeout
period then a TIMEOUT exception is raised. If the end of file is read
- then an EOF exception will be raised. If a log file was set using
- setlog() then all data will also be written to the log file.
+ then an EOF exception will be raised. If a logfile is specified, a
+ copy is written to that log.
If timeout is None then the read may block indefinitely.
If timeout is -1 then the self.timeout value is used. If timeout is 0
@@ -684,11 +694,13 @@ class spawn(SpawnBase):
the stdout and stderr output of the child process is printed. This
simply echos the child stdout and child stderr to the real stdout and
it echos the real stdin to the child stdin. When the user types the
- escape_character this method will stop. The default for
- escape_character is ^]. This should not be confused with ASCII 27 --
- the ESC character. ASCII 29 was chosen for historical merit because
- this is the character used by 'telnet' as the escape character. The
- escape_character will not be sent to the child process.
+ escape_character this method will return None. The escape_character
+ will not be transmitted. The default for escape_character is
+ entered as ``Ctrl - ]``, the very same as BSD telnet. To prevent
+ escaping, escape_character may be set to None.
+
+ If a logfile is specified, then the data sent and received from the
+ child process in interact mode is duplicated to the given log.
You may pass in optional input and output filter functions. These
functions should take a string and return a string. The output_filter
@@ -720,7 +732,7 @@ class spawn(SpawnBase):
self.buffer = self.string_type()
mode = tty.tcgetattr(self.STDIN_FILENO)
tty.setraw(self.STDIN_FILENO)
- if PY3:
+ if escape_character is not None and PY3:
escape_character = escape_character.encode('latin-1')
try:
self.__interact_copy(escape_character, input_filter, output_filter)
@@ -762,19 +774,22 @@ class spawn(SpawnBase):
break
if output_filter:
data = output_filter(data)
- if self.logfile is not None:
- self.logfile.write(data)
- self.logfile.flush()
+ self._log(data, 'read')
os.write(self.STDOUT_FILENO, data)
if self.STDIN_FILENO in r:
data = self.__interact_read(self.STDIN_FILENO)
if input_filter:
data = input_filter(data)
- i = data.rfind(escape_character)
+ i = -1
+ if escape_character is not None:
+ i = data.rfind(escape_character)
if i != -1:
data = data[:i]
+ if data:
+ self._log(data, 'send')
self.__interact_writen(self.child_fd, data)
break
+ self._log(data, 'send')
self.__interact_writen(self.child_fd, data)
def __select(self, iwtd, owtd, ewtd, timeout=None):
diff --git a/pexpect/pxssh.py b/pexpect/pxssh.py
index 71f56a0..4638164 100644
--- a/pexpect/pxssh.py
+++ b/pexpect/pxssh.py
@@ -95,9 +95,12 @@ class pxssh (spawn):
def __init__ (self, timeout=30, maxread=2000, searchwindowsize=None,
logfile=None, cwd=None, env=None, ignore_sighup=True, echo=True,
- options={}):
+ options={}, encoding=None, codec_errors='strict'):
- spawn.__init__(self, None, timeout=timeout, maxread=maxread, searchwindowsize=searchwindowsize, logfile=logfile, cwd=cwd, env=env, ignore_sighup=ignore_sighup, echo=echo)
+ spawn.__init__(self, None, timeout=timeout, maxread=maxread,
+ searchwindowsize=searchwindowsize, logfile=logfile,
+ cwd=cwd, env=env, ignore_sighup=ignore_sighup, echo=echo,
+ encoding=encoding, codec_errors=codec_errors)
self.name = '<pxssh>'
@@ -169,7 +172,7 @@ class pxssh (spawn):
# maximum time for reading the entire prompt
total_timeout = timeout_multiplier * 3.0
- prompt = b''
+ prompt = self.string_type()
begin = time.time()
expired = 0.0
timeout = first_char_timeout
@@ -334,7 +337,7 @@ class pxssh (spawn):
if not self.set_unique_prompt():
self.close()
raise ExceptionPxssh('could not set shell prompt '
- '(recieved: %r, expected: %r).' % (
+ '(received: %r, expected: %r).' % (
self.before, self.PROMPT,))
return True
diff --git a/pexpect/screen.py b/pexpect/screen.py
index efe9ee5..0bced89 100644
--- a/pexpect/screen.py
+++ b/pexpect/screen.py
@@ -27,6 +27,13 @@ import codecs
import copy
import sys
+import warnings
+
+warnings.warn(("pexpect.screen and pexpect.ANSI are deprecated. "
+ "We recommend using pyte to emulate a terminal screen: "
+ "https://pypi.python.org/pypi/pyte"),
+ stacklevel=2)
+
NUL = 0 # Fill character; ignored on input.
ENQ = 5 # Transmit answerback message.
BEL = 7 # Ring the bell.
diff --git a/pexpect/spawnbase.py b/pexpect/spawnbase.py
index 9fd2e18..0518d83 100644
--- a/pexpect/spawnbase.py
+++ b/pexpect/spawnbase.py
@@ -242,14 +242,22 @@ class SpawnBase(object):
# returns 0('foobar') if all input is available at once,
# but returs 1('foo') if parts of the final 'bar' arrive late
- After a match is found the instance attributes 'before', 'after' and
- 'match' will be set. You can see all the data read before the match in
- 'before'. You can see the data that was matched in 'after'. The
- re.MatchObject used in the re match will be in 'match'. If an error
- occurred then 'before' will be set to all the data read so far and
- 'after' and 'match' will be None.
-
- If timeout is -1 then timeout will be set to the self.timeout value.
+ When a match is found for the given pattern, the class instance
+ attribute *match* becomes an re.MatchObject result. Should an EOF
+ or TIMEOUT pattern match, then the match attribute will be an instance
+ of that exception class. The pairing before and after class
+ instance attributes are views of the data preceding and following
+ the matching pattern. On general exception, class attribute
+ *before* is all data received up to the exception, while *match* and
+ *after* attributes are value None.
+
+ When the keyword argument timeout is -1 (default), then TIMEOUT will
+ raise after the default value specified by the class timeout
+ attribute. When None, TIMEOUT will not be raised and may block
+ indefinitely until match.
+
+ When the keyword argument searchwindowsize is -1 (default), then the
+ value specified by the class maxread attribute is used.
A list entry may be EOF or TIMEOUT instead of a string. This will
catch these exceptions and return the index of the list entry instead
@@ -314,9 +322,8 @@ class SpawnBase(object):
expressions). This method is similar to the expect() method except that
expect_list() does not recompile the pattern list on every call. This
may help if you are trying to optimize for speed, otherwise just use
- the expect() method. This is called by expect(). If timeout==-1 then
- the self.timeout value is used. If searchwindowsize==-1 then the
- self.searchwindowsize value is used.
+ the expect() method. This is called by expect().
+
Like :meth:`expect`, passing ``async=True`` will make this return an
asyncio coroutine.
diff --git a/tests/getch.py b/tests/getch.py
index 41e3224..a362e52 100755
--- a/tests/getch.py
+++ b/tests/getch.py
@@ -18,6 +18,7 @@ PEXPECT LICENSE
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
'''
+from __future__ import print_function
import sys, tty, termios
if hasattr(sys.stdin, 'buffer'):
@@ -27,13 +28,13 @@ else:
stdin = sys.stdin
def main():
- print('READY')
+ print('READY', end='\r\n')
while True:
try:
val = ord(stdin.read(1))
except KeyboardInterrupt:
val = 3
- sys.stdout.write('%d<STOP>\r\n' % (val,))
+ print('%d<STOP>' % (val,), end='\r\n')
if val == 0:
# StopIteration equivalent is ctrl+' ' (\x00, NUL)
break
@@ -46,3 +47,4 @@ if __name__ == '__main__':
main()
finally:
termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
+ sys.stdout.flush()
diff --git a/tests/interact.py b/tests/interact.py
index 9f8e672..a839e95 100755
--- a/tests/interact.py
+++ b/tests/interact.py
@@ -31,9 +31,21 @@ import sys
def main():
- p = pexpect.spawn(sys.executable + ' echo_w_prompt.py',
+ p = pexpect.spawn('{sys.executable} getch.py'.format(sys=sys),
env=no_coverage_env())
- p.interact()
+
+ # defaults matches api
+ escape_character = chr(29)
+ encoding = None
+
+ if len(sys.argv) > 1 and '--no-escape' in sys.argv:
+ escape_character = None
+
+ if len(sys.argv) > 1 and '--utf8' in sys.argv:
+ encoding = 'utf8'
+
+ p.interact(escape_character=escape_character)
+
print("Escaped interact")
if __name__ == '__main__':
diff --git a/tests/interact_unicode.py b/tests/interact_unicode.py
deleted file mode 100644
index f4c1f55..0000000
--- a/tests/interact_unicode.py
+++ /dev/null
@@ -1,24 +0,0 @@
-#!/usr/bin/env python
-'''
-Just like interact.py, but using spawnu instead of spawn
-'''
-try:
- # This allows coverage to measure code run in this process
- import coverage
- coverage.process_startup()
-except ImportError:
- pass
-
-from utils import no_coverage_env
-import pexpect
-import sys
-
-
-def main():
- p = pexpect.spawnu(sys.executable + ' echo_w_prompt.py',
- env=no_coverage_env())
- p.interact()
- print("Escaped interact")
-
-if __name__ == '__main__':
- main()
diff --git a/tests/sigwinch_report.py b/tests/sigwinch_report.py
index 626d424..f10956a 100755
--- a/tests/sigwinch_report.py
+++ b/tests/sigwinch_report.py
@@ -39,6 +39,7 @@ def handler(signum, frame):
print('SIGWINCH:', getwinsize ())
sys.stdout.flush()
+print("Initial Size:", getwinsize())
print("setting handler for SIGWINCH")
signal.signal(signal.SIGWINCH, handler)
print("READY")
diff --git a/tests/test_interact.py b/tests/test_interact.py
index e635cb0..865353b 100755
--- a/tests/test_interact.py
+++ b/tests/test_interact.py
@@ -41,15 +41,12 @@ class InteractTestCase (PexpectTestCase.PexpectTestCase):
else:
env['PYTHONPATH'] = self.project_dir
- self.interact_py = ' '.join((sys.executable,
- 'interact.py',))
- self.interact_ucs_py = ' '.join((sys.executable,
- 'interact_unicode.py',))
+ self.interact_py = ('{sys.executable} interact.py'.format(sys=sys))
def test_interact_escape(self):
" Ensure `escape_character' value exits interactive mode. "
p = pexpect.spawn(self.interact_py, timeout=5, env=self.env)
- p.expect('<in >')
+ p.expect('READY')
p.sendcontrol(']') # chr(29), the default `escape_character'
# value of pexpect.interact().
p.expect_exact('Escaped interact')
@@ -57,39 +54,43 @@ class InteractTestCase (PexpectTestCase.PexpectTestCase):
assert not p.isalive()
assert p.exitstatus == 0
- def test_interact_spawn_eof(self):
- " Ensure subprocess receives EOF and exit. "
- p = pexpect.spawn(self.interact_py, timeout=5, env=self.env)
- p.expect('<in >')
- p.sendline(b'alpha')
- p.sendline(b'beta')
- p.expect(b'<out>alpha')
- p.expect(b'<out>beta')
- p.sendeof()
- # strangely, on travis-ci, sendeof() terminates the subprocess,
- # it doesn't receive ^D, just immediately throws EOF.
- idx = p.expect_exact(['<eof>', pexpect.EOF])
- if idx == 0:
+ def test_interact_escape_None(self):
+ " Return only after Termination when `escape_character=None'. "
+ p = pexpect.spawn('{self.interact_py} --no-escape'.format(self=self),
+ timeout=5, env=self.env)
+ p.expect('READY')
+ p.sendcontrol(']')
+ p.expect('29<STOP>')
+ p.send('\x00')
+ if not os.environ.get('TRAVIS', None):
+ # on Travis-CI, we sometimes miss trailing stdout from the
+ # chain of child processes, not entirely sure why. So this
+ # is skipped on such systems.
+ p.expect('0<STOP>')
p.expect_exact('Escaped interact')
- p.expect(pexpect.EOF)
+ p.expect(pexpect.EOF)
assert not p.isalive()
assert p.exitstatus == 0
- def test_interact_spawnu_eof(self):
- " Ensure subprocess receives unicode, EOF, and exit. "
- p = pexpect.spawnu(self.interact_ucs_py, timeout=5, env=self.env)
- p.expect('<in >')
- p.sendline('ɑlpha')
- p.sendline('Βeta')
- p.expect('<out>ɑlpha')
- p.expect('<out>Βeta')
- p.sendeof()
- # strangely, on travis-ci, sendeof() terminates the subprocess,
- # it doesn't receive ^D, just immediately throws EOF.
- idx = p.expect_exact(['<eof>', pexpect.EOF])
- if idx == 0:
+ def test_interact_exit_unicode(self):
+ " Ensure subprocess receives utf8. "
+ p = pexpect.spawnu('{self.interact_py} --utf8'.format(self=self),
+ timeout=5, env=self.env)
+ p.expect('READY')
+ p.send('ɑ') # >>> map(ord, u'ɑ'.encode('utf8'))
+ p.expect('201<STOP>') # [201, 145]
+ p.expect('145<STOP>')
+ p.send('Β') # >>> map(ord, u'Β'.encode('utf8'))
+ p.expect('206<STOP>') # [206, 146]
+ p.expect('146<STOP>')
+ p.send('\x00')
+ if not os.environ.get('TRAVIS', None):
+ # on Travis-CI, we sometimes miss trailing stdout from the
+ # chain of child processes, not entirely sure why. So this
+ # is skipped on such systems.
+ p.expect('0<STOP>')
p.expect_exact('Escaped interact')
- p.expect(pexpect.EOF)
+ p.expect(pexpect.EOF)
assert not p.isalive()
assert p.exitstatus == 0
diff --git a/tests/test_misc.py b/tests/test_misc.py
index d5a707c..16bdfc2 100755
--- a/tests/test_misc.py
+++ b/tests/test_misc.py
@@ -317,9 +317,11 @@ class TestCaseMisc(PexpectTestCase.PexpectTestCase):
" test forced self.__fork_pty() and __pty_make_controlling_tty "
# given,
class spawn_ourptyfork(pexpect.spawn):
- def _spawn(self, command, args=[], preexec_fn=None):
+ def _spawn(self, command, args=[], preexec_fn=None,
+ dimensions=None):
self.use_native_pty_fork = False
- pexpect.spawn._spawn(self, command, args, preexec_fn)
+ pexpect.spawn._spawn(self, command, args, preexec_fn,
+ dimensions)
# exercise,
p = spawn_ourptyfork('cat', echo=False)
diff --git a/tests/test_unicode.py b/tests/test_unicode.py
index f342bf9..55632c3 100644
--- a/tests/test_unicode.py
+++ b/tests/test_unicode.py
@@ -173,6 +173,15 @@ class UnicodeTests(PexpectTestCase.PexpectTestCase):
# exercise,
assert child.readline() == 'input' + child.crlf
+ def test_unicode_argv(self):
+ """ Ensure a program can be executed with unicode arguments. """
+ p = pexpect.spawn(u'echo ǝpoɔıun'.format(self=self),
+ timeout=5, encoding='utf8')
+ p.expect(u'ǝpoɔıun')
+ p.expect(pexpect.EOF)
+ assert not p.isalive()
+ assert p.exitstatus == 0
+
if __name__ == '__main__':
unittest.main()
diff --git a/tests/test_which.py b/tests/test_which.py
index bda3333..f909214 100644
--- a/tests/test_which.py
+++ b/tests/test_which.py
@@ -1,3 +1,4 @@
+# -*- coding: utf-8 -*-
import subprocess
import tempfile
import shutil
@@ -21,9 +22,13 @@ class TestCaseWhich(PexpectTestCase.PexpectTestCase):
def test_os_defpath_which(self):
" which() finds an executable in $PATH and returns its abspath. "
- fname = 'cc'
+
bin_dir = tempfile.mkdtemp()
- bin_path = os.path.join(bin_dir, fname)
+ temp_obj = tempfile.NamedTemporaryFile(
+ suffix=u'.sh', prefix=u'ǝpoɔıun-',
+ dir=bin_dir, delete=False)
+ bin_path = temp_obj.name
+ fname = os.path.basename(temp_obj.name)
save_path = os.environ['PATH']
save_defpath = os.defpath
diff --git a/tests/test_winsize.py b/tests/test_winsize.py
index 75f8c0e..be16773 100755
--- a/tests/test_winsize.py
+++ b/tests/test_winsize.py
@@ -25,39 +25,32 @@ import time
class TestCaseWinsize(PexpectTestCase.PexpectTestCase):
- def test_winsize (self):
- '''
- This tests that the child process can set and get the windows size.
- This makes use of an external script sigwinch_report.py.
- '''
- p1 = pexpect.spawn('%s sigwinch_report.py' % self.PYTHONBIN)
- p1.expect('READY', timeout=10)
-
- p1.setwinsize (11,22)
- index = p1.expect ([pexpect.TIMEOUT, b'SIGWINCH: \(([0-9]*), ([0-9]*)\)'],
- timeout=30)
- if index == 0:
- self.fail("TIMEOUT -- this platform may not support sigwinch properly.\n" + str(p1))
- self.assertEqual(p1.match.group(1, 2), (b"11" ,b"22"))
- self.assertEqual(p1.getwinsize(), (11, 22))
-
- time.sleep(1)
- p1.setwinsize (24,80)
- index = p1.expect ([pexpect.TIMEOUT, b'SIGWINCH: \(([0-9]*), ([0-9]*)\)'],
- timeout=10)
- if index == 0:
- self.fail ("TIMEOUT -- this platform may not support sigwinch properly.\n" + str(p1))
- self.assertEqual(p1.match.group(1, 2), (b"24" ,b"80"))
- self.assertEqual(p1.getwinsize(), (24, 80))
-
- p1.close()
-
-# def test_parent_resize (self):
-# pid = os.getpid()
-# p1 = pexpect.spawn('%s sigwinch_report.py' % self.PYTHONBIN)
-# time.sleep(10)
-# p1.setwinsize (11,22)
-# os.kill (pid, signal.SIGWINCH)
+ def test_initial_winsize(self):
+ """ Assert initial window dimension size (24, 80). """
+ p = pexpect.spawn('{self.PYTHONBIN} sigwinch_report.py'
+ .format(self=self), timeout=3)
+ # default size by PtyProcess class is 24 rows by 80 columns.
+ p.expect_exact('Initial Size: (24, 80)')
+ p.close()
+
+ def test_initial_winsize_by_dimension(self):
+ """ Assert user-parameter window dimension size is initial. """
+ p = pexpect.spawn('{self.PYTHONBIN} sigwinch_report.py'
+ .format(self=self), timeout=3,
+ dimensions=(40, 100))
+ p.expect_exact('Initial Size: (40, 100)')
+ p.close()
+
+ def test_setwinsize(self):
+ """ Ensure method .setwinsize() sends signal caught by child. """
+ p = pexpect.spawn('{self.PYTHONBIN} sigwinch_report.py'
+ .format(self=self), timeout=3)
+ # Note that we must await the installation of the child process'
+ # signal handler,
+ p.expect_exact('READY')
+ p.setwinsize(19, 84)
+ p.expect_exact('SIGWINCH: (19, 84)')
+ p.close()
if __name__ == '__main__':
unittest.main()