Skip to content

Commit

Permalink
added TimeoutException for commands that timeout. closes #172
Browse files Browse the repository at this point in the history
  • Loading branch information
Andrew Moffat committed Dec 29, 2014
1 parent f758927 commit 96452fb
Show file tree
Hide file tree
Showing 3 changed files with 19 additions and 3 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

## 1.10 -

* child processes that timeout via `_timeout` raise `sh.TimeoutException` instead of `sh.SignalExeception_9` [#172](https://github.com/amoffat/sh/issues/172)
* fixed `help(sh)` from the python shell and `pydoc sh` from the command line. [#173](https://github.com/amoffat/sh/issues/173)
* program names can no longer be shadowed by names that sh.py defines internally. removed the requirement of trailing underscores for programs that could have their names shadowed, like `id`.
* memory optimization when a child process's stdin is a newline-delimted string and our bufsize is newlines
Expand Down
15 changes: 14 additions & 1 deletion sh.py
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,7 @@ def __init__(self, full_cmd, stdout, stderr):


class SignalException(ErrorReturnCode): pass
class TimeoutException(Exception): pass

SIGNALS_THAT_SHOULD_THROW_EXCEPTION = (
signal.SIGABRT,
Expand Down Expand Up @@ -424,7 +425,12 @@ def __init__(self, cmd, call_args, stdin, stdout, stderr):
def wait(self):
if not self._process_completed:
self._process_completed = True
self.handle_command_exit_code(self.process.wait())

exit_code = self.process.wait()
if self.process.timed_out:
raise TimeoutException
else:
self.handle_command_exit_code(exit_code)

# https://github.com/amoffat/sh/issues/185
if self.call_args["done"]:
Expand Down Expand Up @@ -1203,6 +1209,11 @@ def __init__(self, parent_log, cmd, stdin, stdout, stderr, call_args, pipe):
OProc._registered_cleanup = True


# used to determine what exception to raise. if our process was
# killed via a timeout counter, we'll raise something different than
# a SIGKILL exception
self.timed_out = False

self.started = time.time()
self.cmd = cmd

Expand Down Expand Up @@ -1386,6 +1397,7 @@ def output_thread(self, stdout, stderr, timeout, started):
now = time.time()
if now - started > timeout:
self.log.debug("we've been running too long")
self.timed_out = True
self.kill()


Expand Down Expand Up @@ -2064,6 +2076,7 @@ class Environment(dict):
"ErrorReturnCode",
"NotYetReadyToRead",
"SignalException",
"TimeoutException",
"__project_url__",
"__version__",
"args",
Expand Down
6 changes: 4 additions & 2 deletions test.py
Original file line number Diff line number Diff line change
Expand Up @@ -1318,8 +1318,10 @@ def test_timeout(self):
sleep_for = 3
timeout = 1
started = time()
try: sh.sleep(sleep_for, _timeout=timeout).wait()
except sh.SignalException_9: pass
try:
sh.sleep(sleep_for, _timeout=timeout).wait()
except sh.TimeoutException:
pass
elapsed = time() - started
self.assertTrue(abs(elapsed - timeout) < 0.5)

Expand Down

0 comments on commit 96452fb

Please sign in to comment.