Skip to content

Commit ed41fca

Browse files
committed
Add Python 2/3 compat function to terminate a subprocess
1 parent 9b5a8e7 commit ed41fca

File tree

4 files changed

+33
-7
lines changed

4 files changed

+33
-7
lines changed

easybuild/tools/py2vs3/py2.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
import ConfigParser as configparser # noqa
3434
import json
3535
import subprocess
36+
import time
3637
import urllib2 as std_urllib # noqa
3738
from collections import Mapping, OrderedDict # noqa
3839
from HTMLParser import HTMLParser # noqa
@@ -59,6 +60,23 @@ def subprocess_popen_text(cmd, **kwargs):
5960
return subprocess.Popen(cmd, stdout=subprocess.PIPE, **kwargs)
6061

6162

63+
def subprocess_terminate(proc, timeout):
64+
"""Terminate the subprocess if it hasn't finished after the given timeout"""
65+
res = None
66+
for pipe in (proc.stdout, proc.stderr, proc.stdin):
67+
if pipe:
68+
pipe.close()
69+
while timeout > 0:
70+
res = proc.poll()
71+
if res is not None:
72+
break
73+
delay = min(timeout, 0.1)
74+
time.sleep(delay)
75+
timeout -= delay
76+
if res is None:
77+
proc.terminate()
78+
79+
6280
def raise_with_traceback(exception_class, message, traceback):
6381
"""Raise exception of specified class with given message and traceback."""
6482
raise exception_class, message, traceback # noqa: E999

easybuild/tools/py2vs3/py3.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,17 @@ def subprocess_popen_text(cmd, **kwargs):
7373
return subprocess.Popen(cmd, stdout=subprocess.PIPE, universal_newlines=True, **kwargs)
7474

7575

76+
def subprocess_terminate(proc, timeout):
77+
"""Terminate the subprocess if it hasn't finished after the given timeout"""
78+
try:
79+
proc.communicate(timeout=timeout)
80+
except subprocess.TimeoutExpired:
81+
for pipe in (proc.stdout, proc.stderr, proc.stdin):
82+
if pipe:
83+
pipe.close()
84+
proc.terminate()
85+
86+
7687
def raise_with_traceback(exception_class, message, traceback):
7788
"""Raise exception of specified class with given message and traceback."""
7889
raise exception_class(message).with_traceback(traceback)

test/framework/asyncprocess.py

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,14 @@
2828
@author: Toon Willems (Ghent University)
2929
"""
3030

31-
import subprocess
3231
import sys
3332
import time
3433
from test.framework.utilities import EnhancedTestCase
3534
from unittest import TextTestRunner, TestSuite
3635

3736
import easybuild.tools.asyncprocess as p
3837
from easybuild.tools.asyncprocess import Popen
38+
from easybuild.tools.py2vs3 import subprocess_terminate
3939

4040

4141
class AsyncProcessTest(EnhancedTestCase):
@@ -63,11 +63,7 @@ def runTest(self):
6363

6464
def tearDown(self):
6565
"""cleanup"""
66-
try:
67-
# Terminate subprocess
68-
self.shell.communicate(timeout=1)
69-
except subprocess.TimeoutExpired:
70-
pass
66+
subprocess_terminate(self.shell, timeout=1)
7167
super(AsyncProcessTest, self).tearDown()
7268

7369

test/framework/run.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
from easybuild.tools.run import check_async_cmd, check_log_for_errors, complete_cmd, get_output_from_process
5252
from easybuild.tools.run import parse_log_for_error, run_cmd, run_cmd_qa
5353
from easybuild.tools.config import ERROR, IGNORE, WARN
54+
from easybuild.tools.py2vs3 import subprocess_terminate
5455

5556

5657
class RunTest(EnhancedTestCase):
@@ -84,7 +85,7 @@ def get_proc(cmd, asynchronous=False):
8485
yield proc
8586
finally:
8687
# Make sure to close the process and its pipes
87-
proc.communicate(timeout=1)
88+
subprocess_terminate(proc, timeout=1)
8889

8990
# get all output at once
9091
with get_proc("echo hello") as proc:

0 commit comments

Comments
 (0)