diff options
author | Bernát Gábor <bgabor8@bloomberg.net> | 2020-12-25 13:04:09 +0000 |
---|---|---|
committer | Bernát Gábor <bgabor8@bloomberg.net> | 2020-12-25 13:04:39 +0000 |
commit | 0bbdf445fc7d47d0dd31599872975534243ed555 (patch) | |
tree | 446c8de3a2155a3d4a14886376e36cb076a7d807 | |
parent | 631af1b0dd331c7a79c2d40ea4ef3bab1fd34632 (diff) | |
download | tox-git-0bbdf445fc7d47d0dd31599872975534243ed555.tar.gz |
Fix keyboard interrupt can fail
Signed-off-by: Bernát Gábor <bgabor8@bloomberg.net>
-rw-r--r-- | .pre-commit-config.yaml | 2 | ||||
-rw-r--r-- | src/tox/execute/local_sub_process/read_via_thread_unix.py | 22 | ||||
-rw-r--r-- | tests/execute/local_subprocess/local_subprocess_sigint.py | 2 | ||||
-rw-r--r-- | tests/execute/local_subprocess/test_local_subprocess.py | 10 |
4 files changed, 21 insertions, 15 deletions
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index a1387878..26a621fc 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -42,7 +42,7 @@ repos: - --min-py3-version - "3.6" - repo: https://github.com/asottile/blacken-docs - rev: v1.8.0 + rev: v1.9.1 hooks: - id: blacken-docs additional_dependencies: diff --git a/src/tox/execute/local_sub_process/read_via_thread_unix.py b/src/tox/execute/local_sub_process/read_via_thread_unix.py index 03b5c9cf..ba156e7f 100644 --- a/src/tox/execute/local_sub_process/read_via_thread_unix.py +++ b/src/tox/execute/local_sub_process/read_via_thread_unix.py @@ -1,6 +1,7 @@ """ On UNIX we use select.select to ensure we drain in a non-blocking fashion. """ +import errno # pragma: win32 no cover import os # pragma: win32 no cover import select # pragma: win32 no cover from typing import Callable # pragma: win32 no cover @@ -18,14 +19,19 @@ class ReadViaThreadUnix(ReadViaThread): # pragma: win32 no cover while not self.stop.is_set(): # we need to drain the stream, but periodically give chance for the thread to break if the stop event has # been set (this is so that an interrupt can be handled) - ready, __, ___ = select.select([self.file_no], [], [], STOP_EVENT_CHECK_PERIODICITY_IN_MS) - if ready: - data = os.read(self.file_no, 1) - if data: - try: - self.handler(data) - except Exception: # noqa - pass + try: + ready, __, ___ = select.select([self.file_no], [], [], STOP_EVENT_CHECK_PERIODICITY_IN_MS) + if ready: + data = os.read(self.file_no, 1) + if data: + try: + self.handler(data) + except Exception: # noqa + pass + except OSError as exception: + if exception.errno == errno.EBADF: + break + raise def _drain_stream(self) -> bytes: result = bytearray() # on closed file read returns empty diff --git a/tests/execute/local_subprocess/local_subprocess_sigint.py b/tests/execute/local_subprocess/local_subprocess_sigint.py index 16d0b4c9..928d41b8 100644 --- a/tests/execute/local_subprocess/local_subprocess_sigint.py +++ b/tests/execute/local_subprocess/local_subprocess_sigint.py @@ -10,7 +10,7 @@ from tox.execute.api import ToxKeyboardInterrupt from tox.execute.request import StdinSource from tox.report import NamedBytesIO -logging.basicConfig(level=logging.NOTSET) +logging.basicConfig(level=logging.DEBUG, format="%(relativeCreated)d\t%(levelname).1s\t%(message)s") bad_process = Path(__file__).parent / "bad_process.py" executor = local_sub_process.LocalSubProcessExecutor(colored=False) diff --git a/tests/execute/local_subprocess/test_local_subprocess.py b/tests/execute/local_subprocess/test_local_subprocess.py index ec8a299d..d8c51107 100644 --- a/tests/execute/local_subprocess/test_local_subprocess.py +++ b/tests/execute/local_subprocess/test_local_subprocess.py @@ -226,16 +226,16 @@ def test_command_keyboard_interrupt(tmp_path: Path) -> None: child = next(iter(psutil.Process(pid=root).children())).pid process.send_signal(SIGINT) try: - out, err = process.communicate(timeout=5) + out, err = process.communicate(timeout=None) except subprocess.TimeoutExpired: # pragma: no cover process.kill() out, err = process.communicate() assert False, f"{out}\n{err}" - assert "ERROR:root:got KeyboardInterrupt signal" in err, err - assert f"WARNING:root:KeyboardInterrupt from {root} SIGINT pid {child}" in err, err - assert f"WARNING:root:KeyboardInterrupt from {root} SIGTERM pid {child}" in err, err - assert f"INFO:root:KeyboardInterrupt from {root} SIGKILL pid {child}" in err, err + assert "E\tgot KeyboardInterrupt signal" in err, err + assert f"W\tKeyboardInterrupt from {root} SIGINT pid {child}" in err, err + assert f"W\tKeyboardInterrupt from {root} SIGTERM pid {child}" in err, err + assert f"I\tKeyboardInterrupt from {root} SIGKILL pid {child}" in err, err outs = out.split("\n") |