1
0
Fork 0
mirror of synced 2024-06-28 19:10:33 +12:00

patch subprocess.run to have better timeout handling

This commit is contained in:
Nick Sweeting 2019-01-20 14:07:28 -05:00
parent e620722bb9
commit ce07a6c738
2 changed files with 40 additions and 2 deletions

View file

@ -1,10 +1,10 @@
import os import os
import re
import sys import sys
from functools import wraps from functools import wraps
from collections import defaultdict from collections import defaultdict
from datetime import datetime from datetime import datetime
from subprocess import run, PIPE, DEVNULL
from peekable import Peekable from peekable import Peekable
@ -38,6 +38,7 @@ from util import (
progress, progress,
chmod_file, chmod_file,
pretty_path, pretty_path,
run, PIPE, DEVNULL
) )

View file

@ -3,12 +3,13 @@ import re
import sys import sys
import time import time
import json import json
import signal
import urllib.request import urllib.request
from decimal import Decimal from decimal import Decimal
from urllib.parse import quote from urllib.parse import quote
from datetime import datetime from datetime import datetime
from subprocess import run, PIPE, DEVNULL from subprocess import TimeoutExpired, Popen, PIPE, DEVNULL, CompletedProcess, CalledProcessError
from multiprocessing import Process from multiprocessing import Process
from config import ( from config import (
@ -533,3 +534,39 @@ def derived_link_info(link):
'title': '{title} ({type})'.format(**link), 'title': '{title} ({type})'.format(**link),
}) })
return link_info return link_info
def run(*popenargs, input=None, capture_output=False, timeout=None, check=False, **kwargs):
"""Patched of subprocess.run to fix blocking io making timeout=innefective"""
if input is not None:
if 'stdin' in kwargs:
raise ValueError('stdin and input arguments may not both be used.')
kwargs['stdin'] = PIPE
if capture_output:
if ('stdout' in kwargs) or ('stderr' in kwargs):
raise ValueError('stdout and stderr arguments may not be used '
'with capture_output.')
kwargs['stdout'] = PIPE
kwargs['stderr'] = PIPE
with Popen(*popenargs, **kwargs) as process:
try:
stdout, stderr = process.communicate(input, timeout=timeout)
except TimeoutExpired:
process.kill()
try:
stdout, stderr = process.communicate(input, timeout=2)
except:
pass
raise TimeoutExpired(popenargs[0][0], timeout)
except BaseException as err:
process.kill()
# We don't call process.wait() as .__exit__ does that for us.
raise
retcode = process.poll()
if check and retcode:
raise CalledProcessError(retcode, process.args,
output=stdout, stderr=stderr)
return CompletedProcess(process.args, retcode, stdout, stderr)