Skip to content

Commit

Permalink
Merge pull request #211 from pexpect/noexception-on-wait-after-terminate
Browse files Browse the repository at this point in the history
Do not raise Exception on wait() after terminate or previous wait()
  • Loading branch information
takluyver committed May 20, 2015
2 parents 82d4937 + e2e7952 commit 57a5519
Show file tree
Hide file tree
Showing 4 changed files with 31 additions and 10 deletions.
3 changes: 3 additions & 0 deletions doc/history.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ Version 4.0
waiting for output that matches a pattern.
* Enhancement: allow method as callbacks of argument ``events`` for
:func:`pexpect.run` (:ghissue:`176`).
* 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
```````````
Expand Down
9 changes: 8 additions & 1 deletion pexpect/pty_spawn.py
Original file line number Diff line number Diff line change
Expand Up @@ -614,10 +614,17 @@ def wait(self):
not read any data from the child, so this will block forever if the
child has unread output and has terminated. In other words, the child
may have printed output then called exit(), but, the child is
technically still alive until its output is read by the parent. '''
technically still alive until its output is read by the parent.
This method is non-blocking if :meth:`wait` has already been called
previously or :meth:`isalive` method returns False. It simply returns
the previously determined exit status.
'''

ptyproc = self.ptyproc
with _wrap_ptyprocess_err():
# exception may occur if "Is some other process attempting
# "job control with our child pid?"
exitstatus = ptyproc.wait()
self.status = ptyproc.status
self.exitstatus = ptyproc.exitstatus
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,5 +61,5 @@
'Topic :: System :: Software Distribution',
'Topic :: Terminals',
],
install_requires=['ptyprocess'],
install_requires=['ptyprocess>=0.5'],
)
27 changes: 19 additions & 8 deletions tests/test_isalive.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,22 +25,33 @@
import time
from . import PexpectTestCase


class IsAliveTestCase(PexpectTestCase.PexpectTestCase):
"""Various tests for the running status of processes."""

def test_expect_wait (self):
'''This tests that calling wait on a finished process works as expected.
'''
p = pexpect.spawn('sleep 3')
def test_expect_wait(self):
"""Ensure consistency in wait() and isalive()."""
p = pexpect.spawn('sleep 1')
assert p.isalive()
p.wait()
assert p.wait() == 0
assert not p.isalive()
# In previous versions of ptyprocess/pexpect, calling wait() a second
# time would raise an exception, but not since v4.0
assert p.wait() == 0

def test_expect_wait_after_termination(self):
"""Ensure wait on a process terminated by kill -9."""
p = pexpect.spawn('sleep 3')
assert p.isalive()
p.kill(9)
time.sleep(1)
with self.assertRaises(pexpect.ExceptionPexpect):
p.wait()

# when terminated, the exitstatus is None, but p.signalstatus
# and p.terminated reflects that the kill -9 nature.
assert p.wait() is None
assert p.signalstatus == 9
assert p.terminated == True
assert not p.isalive()

def test_signal_wait(self):
'''Test calling wait with a process terminated by a signal.'''
Expand Down Expand Up @@ -102,7 +113,7 @@ def test_expect_isalive_consistent_multiple_calls (self):
p = pexpect.spawn('cat')
assert p.isalive()
assert p.isalive()
p.kill(9)
p.sendeof()
p.expect(pexpect.EOF)
assert not p.isalive()
assert not p.isalive()
Expand Down

0 comments on commit 57a5519

Please sign in to comment.