From 803cdc108e3942bc541ce5e0558604dbf8455142 Mon Sep 17 00:00:00 2001 From: Kristopher H Date: Wed, 19 Oct 2016 23:31:11 +0200 Subject: Raise ExceptionPexpect instead of PtyProcessError in spawn.close --- pexpect/pty_spawn.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pexpect/pty_spawn.py b/pexpect/pty_spawn.py index d1c6df7..11ad4f8 100644 --- a/pexpect/pty_spawn.py +++ b/pexpect/pty_spawn.py @@ -315,7 +315,10 @@ class spawn(SpawnBase): and SIGINT). ''' self.flush() - self.ptyproc.close(force=force) + with _wrap_ptyprocess_err(): + # PtyProcessError may be raised if it is not possible to terminate + # the child. + self.ptyproc.close(force=force) self.isalive() # Update exit status from ptyproc self.child_fd = -1 -- cgit v1.2.1 From 1eeddba2ef433cb23cefe8adc064f13a4b9265fa Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Wed, 19 Jul 2017 15:05:01 +0100 Subject: Rename async= parameter to async_= Closes gh-315 --- pexpect/spawnbase.py | 32 ++++++++++++++++++++++---------- tests/test_async.py | 30 +++++++++++++++--------------- 2 files changed, 37 insertions(+), 25 deletions(-) diff --git a/pexpect/spawnbase.py b/pexpect/spawnbase.py index cb64582..11e40f5 100644 --- a/pexpect/spawnbase.py +++ b/pexpect/spawnbase.py @@ -223,7 +223,7 @@ class SpawnBase(object): self._pattern_type_err(p) return compiled_pattern_list - def expect(self, pattern, timeout=-1, searchwindowsize=-1, async=False): + def expect(self, pattern, timeout=-1, searchwindowsize=-1, async_=False, **kw): '''This seeks through the stream until a pattern is matched. The pattern is overloaded and may take several types. The pattern can be a StringType, EOF, a compiled re, or a list of any of those types. @@ -307,7 +307,7 @@ class SpawnBase(object): If you are trying to optimize for speed then see expect_list(). On Python 3.4, or Python 3.3 with asyncio installed, passing - ``async=True`` will make this return an :mod:`asyncio` coroutine, + ``async_=True`` will make this return an :mod:`asyncio` coroutine, which you can yield from to get the same result that this method would normally give directly. So, inside a coroutine, you can replace this code:: @@ -315,15 +315,19 @@ class SpawnBase(object): With this non-blocking form:: - index = yield from p.expect(patterns, async=True) + index = yield from p.expect(patterns, async_=True) ''' + if 'async' in kw: + async_ = kw.pop('async') + if kw: + raise TypeError("Unknown keyword arguments: {}".format(kw)) compiled_pattern_list = self.compile_pattern_list(pattern) return self.expect_list(compiled_pattern_list, - timeout, searchwindowsize, async) + timeout, searchwindowsize, async_) def expect_list(self, pattern_list, timeout=-1, searchwindowsize=-1, - async=False): + async_=False, **kw): '''This takes a list of compiled regular expressions and returns the index into the pattern_list that matched the child output. The list may also contain EOF or TIMEOUT(which are not compiled regular @@ -333,21 +337,25 @@ class SpawnBase(object): the expect() method. This is called by expect(). - Like :meth:`expect`, passing ``async=True`` will make this return an + Like :meth:`expect`, passing ``async_=True`` will make this return an asyncio coroutine. ''' if timeout == -1: timeout = self.timeout + if 'async' in kw: + async_ = kw.pop('async') + if kw: + raise TypeError("Unknown keyword arguments: {}".format(kw)) exp = Expecter(self, searcher_re(pattern_list), searchwindowsize) - if async: + if async_: from .async import expect_async return expect_async(exp, timeout) else: return exp.expect_loop(timeout) def expect_exact(self, pattern_list, timeout=-1, searchwindowsize=-1, - async=False): + async_=False, **kw): '''This is similar to expect(), but uses plain string matching instead of compiled regular expressions in 'pattern_list'. The 'pattern_list' @@ -361,11 +369,15 @@ class SpawnBase(object): This method is also useful when you don't want to have to worry about escaping regular expression characters that you want to match. - Like :meth:`expect`, passing ``async=True`` will make this return an + Like :meth:`expect`, passing ``async_=True`` will make this return an asyncio coroutine. ''' if timeout == -1: timeout = self.timeout + if 'async' in kw: + async_ = kw.pop('async') + if kw: + raise TypeError("Unknown keyword arguments: {}".format(kw)) if (isinstance(pattern_list, self.allowed_string_types) or pattern_list in (TIMEOUT, EOF)): @@ -385,7 +397,7 @@ class SpawnBase(object): pattern_list = [prepare_pattern(p) for p in pattern_list] exp = Expecter(self, searcher_string(pattern_list), searchwindowsize) - if async: + if async_: from .async import expect_async return expect_async(exp, timeout) else: diff --git a/tests/test_async.py b/tests/test_async.py index 1a15524..1cc3236 100644 --- a/tests/test_async.py +++ b/tests/test_async.py @@ -18,53 +18,53 @@ class AsyncTests(PexpectTestCase): def test_simple_expect(self): p = pexpect.spawn('cat') p.sendline('Hello asyncio') - coro = p.expect(['Hello', pexpect.EOF] , async=True) + coro = p.expect(['Hello', pexpect.EOF] , async_=True) assert run(coro) == 0 print('Done') def test_timeout(self): p = pexpect.spawn('cat') - coro = p.expect('foo', timeout=1, async=True) + coro = p.expect('foo', timeout=1, async_=True) with self.assertRaises(pexpect.TIMEOUT): run(coro) p = pexpect.spawn('cat') - coro = p.expect(['foo', pexpect.TIMEOUT], timeout=1, async=True) + coro = p.expect(['foo', pexpect.TIMEOUT], timeout=1, async_=True) assert run(coro) == 1 def test_eof(self): p = pexpect.spawn('cat') p.sendline('Hi') - coro = p.expect(pexpect.EOF, async=True) + coro = p.expect(pexpect.EOF, async_=True) p.sendeof() assert run(coro) == 0 p = pexpect.spawn('cat') p.sendeof() - coro = p.expect('Blah', async=True) + coro = p.expect('Blah', async_=True) with self.assertRaises(pexpect.EOF): run(coro) def test_expect_exact(self): p = pexpect.spawn('%s list100.py' % sys.executable) - assert run(p.expect_exact(b'5', async=True)) == 0 - assert run(p.expect_exact(['wpeok', b'11'], async=True)) == 1 - assert run(p.expect_exact([b'foo', pexpect.EOF], async=True)) == 1 + assert run(p.expect_exact(b'5', async_=True)) == 0 + assert run(p.expect_exact(['wpeok', b'11'], async_=True)) == 1 + assert run(p.expect_exact([b'foo', pexpect.EOF], async_=True)) == 1 def test_async_utf8(self): p = pexpect.spawn('%s list100.py' % sys.executable, encoding='utf8') - assert run(p.expect_exact(u'5', async=True)) == 0 - assert run(p.expect_exact([u'wpeok', u'11'], async=True)) == 1 - assert run(p.expect_exact([u'foo', pexpect.EOF], async=True)) == 1 + assert run(p.expect_exact(u'5', async_=True)) == 0 + assert run(p.expect_exact([u'wpeok', u'11'], async_=True)) == 1 + assert run(p.expect_exact([u'foo', pexpect.EOF], async_=True)) == 1 def test_async_and_gc(self): p = pexpect.spawn('%s sleep_for.py 1' % sys.executable, encoding='utf8') - assert run(p.expect_exact(u'READY', async=True)) == 0 + assert run(p.expect_exact(u'READY', async_=True)) == 0 gc.collect() - assert run(p.expect_exact(u'END', async=True)) == 0 + assert run(p.expect_exact(u'END', async_=True)) == 0 def test_async_and_sync(self): p = pexpect.spawn('echo 1234', encoding='utf8', maxread=1) - assert run(p.expect_exact(u'1', async=True)) == 0 + assert run(p.expect_exact(u'1', async_=True)) == 0 assert p.expect_exact(u'2') == 0 - assert run(p.expect_exact(u'3', async=True)) == 0 + assert run(p.expect_exact(u'3', async_=True)) == 0 -- cgit v1.2.1 From 6d5811aef8ec50debe4bd7abf3964a14cf04688a Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Tue, 25 Jul 2017 10:24:25 +0100 Subject: Only pass strings to shlex Avoid passing None, which causes it to read from stdin. Closes gh-433 --- pexpect/popen_spawn.py | 3 ++- pexpect/utils.py | 5 +++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/pexpect/popen_spawn.py b/pexpect/popen_spawn.py index 600ac92..c9d4738 100644 --- a/pexpect/popen_spawn.py +++ b/pexpect/popen_spawn.py @@ -15,6 +15,7 @@ except ImportError: from .spawnbase import SpawnBase, PY3 from .exceptions import EOF +from .utils import string_types class PopenSpawn(SpawnBase): if PY3: @@ -39,7 +40,7 @@ class PopenSpawn(SpawnBase): kwargs['startupinfo'] = startupinfo kwargs['creationflags'] = subprocess.CREATE_NEW_PROCESS_GROUP - if not isinstance(cmd, (list, tuple)): + if isinstance(cmd, string_types): cmd = shlex.split(cmd) self.proc = subprocess.Popen(cmd, **kwargs) diff --git a/pexpect/utils.py b/pexpect/utils.py index ae0fe9d..bafc280 100644 --- a/pexpect/utils.py +++ b/pexpect/utils.py @@ -11,6 +11,11 @@ except NameError: # Alias Python2 exception to Python3 InterruptedError = select.error +if sys.version_info[0] >= 3: + string_types = (str,) +else: + string_types = (unicode, str) + def is_executable_file(path): """Checks that path is an executable regular file, or a symlink towards one. -- cgit v1.2.1