cpython: a161081e8f7c (original) (raw)
--- a/Lib/subprocess.py +++ b/Lib/subprocess.py @@ -371,8 +371,9 @@ class TimeoutExpired(SubprocessError): """This exception is raised when the timeout expires while waiting for a child process. """
- def init(self, cmd, timeout, output=None): self.cmd = cmd
self.timeout = timeout[](#l1.10) self.output = output[](#l1.11)
def str(self): @@ -533,7 +534,7 @@ def check_output(*popenargs, timeout=Non except TimeoutExpired: process.kill() output, unused_err = process.communicate()
raise TimeoutExpired(process.args, output=output)[](#l1.18)
retcode = process.poll() if retcode: raise CalledProcessError(retcode, process.args, output=output)raise TimeoutExpired(process.args, timeout, output=output)[](#l1.19)
@@ -844,7 +845,7 @@ class Popen(object): return (stdout, stderr) try:
stdout, stderr = self._communicate(input, endtime)[](#l1.27)
stdout, stderr = self._communicate(input, endtime, timeout)[](#l1.28) finally:[](#l1.29) self._communication_started = True[](#l1.30)
@@ -865,12 +866,12 @@ class Popen(object): return endtime - time.time()
- def _check_timeout(self, endtime, orig_timeout): """Convenience for checking if a timeout has expired.""" if endtime is None: return if time.time() > endtime:
raise TimeoutExpired(self.args)[](#l1.42)
raise TimeoutExpired(self.args, orig_timeout)[](#l1.43)
if mswindows: @@ -1063,9 +1064,11 @@ class Popen(object): return self.returncode
def wait(self, timeout=None):[](#l1.51)
def wait(self, timeout=None, endtime=None):[](#l1.52) """Wait for child process to terminate. Returns returncode[](#l1.53) attribute."""[](#l1.54)
if endtime is not None:[](#l1.55)
timeout = self._remaining_time(endtime)[](#l1.56) if timeout is None:[](#l1.57) timeout = _subprocess.INFINITE[](#l1.58) else:[](#l1.59)
@@ -1073,7 +1076,7 @@ class Popen(object): if self.returncode is None: result = _subprocess.WaitForSingleObject(self._handle, timeout) if result == _subprocess.WAIT_TIMEOUT:
raise TimeoutExpired(self.args)[](#l1.64)
raise TimeoutExpired(self.args, timeout)[](#l1.65) self.returncode = _subprocess.GetExitCodeProcess(self._handle)[](#l1.66) return self.returncode[](#l1.67)
@@ -1083,7 +1086,7 @@ class Popen(object): fh.close()
def _communicate(self, input, endtime):[](#l1.73)
def _communicate(self, input, endtime, orig_timeout):[](#l1.74) # Start reader threads feeding into a list hanging off of this[](#l1.75) # object, unless they've already been started.[](#l1.76) if self.stdout and not hasattr(self, "_stdout_buff"):[](#l1.77)
@@ -1489,13 +1492,18 @@ class Popen(object): def wait(self, timeout=None, endtime=None): """Wait for child process to terminate. Returns returncode attribute."""
# If timeout was passed but not endtime, compute endtime in terms of[](#l1.82)
# timeout.[](#l1.83)
if endtime is None and timeout is not None:[](#l1.84)
endtime = time.time() + timeout[](#l1.85) if self.returncode is not None:[](#l1.86) return self.returncode[](#l1.87)
elif endtime is not None:[](#l1.88)
# endtime is preferred to timeout. timeout is only used for[](#l1.90)
# printing.[](#l1.91)
if endtime is not None or timeout is not None:[](#l1.92)
if endtime is None:[](#l1.93)
endtime = time.time() + timeout[](#l1.94)
elif timeout is None:[](#l1.95)
timeout = self._remaining_time(endtime)[](#l1.96)
if endtime is not None:[](#l1.98) # Enter a busy loop if we have a timeout. This busy loop was[](#l1.99) # cribbed from Lib/threading.py in Thread.wait() at r71065.[](#l1.100) delay = 0.0005 # 500 us -> initial delay of 1 ms[](#l1.101)
@@ -1507,7 +1515,7 @@ class Popen(object): break remaining = self._remaining_time(endtime) if remaining <= 0:
raise TimeoutExpired(self.args)[](#l1.106)
raise TimeoutExpired(self.args, timeout)[](#l1.107) delay = min(delay * 2, remaining, .05)[](#l1.108) time.sleep(delay)[](#l1.109) elif self.returncode is None:[](#l1.110)
@@ -1516,7 +1524,7 @@ class Popen(object): return self.returncode
def _communicate(self, input, endtime):[](#l1.115)
def _communicate(self, input, endtime, orig_timeout):[](#l1.116) if self.stdin and not self._communication_started:[](#l1.117) # Flush stdio buffer. This might block, if the user has[](#l1.118) # been writing to .stdin in an uncontrolled fashion.[](#l1.119)
@@ -1525,9 +1533,11 @@ class Popen(object): self.stdin.close() if _has_poll:
stdout, stderr = self._communicate_with_poll(input, endtime)[](#l1.124)
stdout, stderr = self._communicate_with_poll(input, endtime,[](#l1.125)
orig_timeout)[](#l1.126) else:[](#l1.127)
stdout, stderr = self._communicate_with_select(input, endtime)[](#l1.128)
stdout, stderr = self._communicate_with_select(input, endtime,[](#l1.129)
orig_timeout)[](#l1.130)
self.wait(timeout=self._remaining_time(endtime)) @@ -1550,7 +1560,7 @@ class Popen(object): return (stdout, stderr)
def _communicate_with_poll(self, input, endtime):[](#l1.138)
def _communicate_with_poll(self, input, endtime, orig_timeout):[](#l1.139) stdout = None # Return[](#l1.140) stderr = None # Return[](#l1.141)
@@ -1601,7 +1611,7 @@ class Popen(object): if e.args[0] == errno.EINTR: continue raise
self._check_timeout(endtime)[](#l1.147)
self._check_timeout(endtime, orig_timeout)[](#l1.148)
# XXX Rewrite these to use non-blocking I/O on the
# file objects; they are no longer using C stdio
@@ -1625,7 +1635,7 @@ class Popen(object):
return (stdout, stderr)
def _communicate_with_select(self, input, endtime):[](#l1.156)
def _communicate_with_select(self, input, endtime, orig_timeout):[](#l1.157) if not self._communication_started:[](#l1.158) self._read_set = [][](#l1.159) self._write_set = [][](#l1.160)
@@ -1667,9 +1677,9 @@ class Popen(object): # According to the docs, returning three empty lists indicates # that the timeout expired. if not (rlist or wlist or xlist):
raise TimeoutExpired(self.args)[](#l1.165)
raise TimeoutExpired(self.args, orig_timeout)[](#l1.166) # We also check what time it is ourselves for good measure.[](#l1.167)
self._check_timeout(endtime)[](#l1.168)
self._check_timeout(endtime, orig_timeout)[](#l1.169)
# XXX Rewrite these to use non-blocking I/O on the
# file objects; they are no longer using C stdio
--- a/Lib/test/test_subprocess.py +++ b/Lib/test/test_subprocess.py @@ -651,7 +651,9 @@ class ProcessTestCase(BaseTestCase): def test_wait_timeout(self): p = subprocess.Popen([sys.executable, "-c", "import time; time.sleep(0.1)"])
self.assertRaises(subprocess.TimeoutExpired, p.wait, timeout=0.01)[](#l2.7)
with self.assertRaises(subprocess.TimeoutExpired) as c:[](#l2.8)
p.wait(timeout=0.01)[](#l2.9)
self.assertIn("0.01", str(c.exception)) # For coverage of __str__.[](#l2.10) self.assertEqual(p.wait(timeout=2), 0)[](#l2.11)