summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeff Quast <contact@jeffquast.com>2015-09-22 12:42:24 -0700
committerJeff Quast <contact@jeffquast.com>2015-09-22 12:42:24 -0700
commit3c1bc018218b86177e1cdf8e93ead035afacc421 (patch)
tree7c928ee4ad19c6c9610849f5f3b4bde7b5e8d4c4
parentae480683db601dc162ab2d02643ff84e1c3786be (diff)
parentea586fb9a545854f9b1212779653ec80f3428a2c (diff)
downloadpexpect-3c1bc018218b86177e1cdf8e93ead035afacc421.tar.gz
Merge remote-tracking branch 'origin/master' into default-handle-sighupdefault-handle-sighup-pull
-rw-r--r--doc/FAQ.rst26
-rw-r--r--doc/history.rst3
-rw-r--r--pexpect/pty_spawn.py20
-rw-r--r--pexpect/spawnbase.py10
-rwxr-xr-xtests/sigwinch_report.py1
-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
9 files changed, 91 insertions, 52 deletions
diff --git a/doc/FAQ.rst b/doc/FAQ.rst
index 0636772..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
@@ -117,14 +128,13 @@ 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**
diff --git a/doc/history.rst b/doc/history.rst
index 06e2ef8..b33e4d9 100644
--- a/doc/history.rst
+++ b/doc/history.rst
@@ -17,6 +17,9 @@ 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`).
+* 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`).
diff --git a/pexpect/pty_spawn.py b/pexpect/pty_spawn.py
index 1eeceec..7280a01 100644
--- a/pexpect/pty_spawn.py
+++ b/pexpect/pty_spawn.py
@@ -37,7 +37,7 @@ class spawn(SpawnBase):
def __init__(self, command, args=[], timeout=30, maxread=2000,
searchwindowsize=None, logfile=None, cwd=None, env=None,
ignore_sighup=False, echo=True, preexec_fn=None,
- encoding=None, codec_errors='strict'):
+ 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::
@@ -85,6 +85,13 @@ class spawn(SpawnBase):
: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
logging. This is the default. Set logfile to sys.stdout to echo
@@ -166,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)
@@ -182,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
@@ -218,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
@@ -273,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)
diff --git a/pexpect/spawnbase.py b/pexpect/spawnbase.py
index aa7ef86..0518d83 100644
--- a/pexpect/spawnbase.py
+++ b/pexpect/spawnbase.py
@@ -251,7 +251,10 @@ class SpawnBase(object):
*before* is all data received up to the exception, while *match* and
*after* attributes are value None.
- If timeout is -1 then timeout will be set to the self.timeout value.
+ 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.
@@ -319,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/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_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()