3

I am developing a small tool in Python 2.7 and using subprocess module. I am using this module to run commands on remote devices using its check_output function. There might be a situation in which the remote device is not functioning and therefore I am getting the following response: Timeout: No Response from 10.xxx.xxx.xxx Following is my code:

try:
    x=subprocess.check_output(command, shell=True)
except Exception:
    print ("Some issues in fetching details")
    exit()
else:
    print (x)

I want to put timeout into this function so that if after a certain amount of time, no response is recieved, my code goes in the Exception part and prints the given message. I tried using timeout argument in the check_output command but after running my script with timeout argument, it is immediately printing the message given in the Exception part. What I tried:

try:
    x=subprocess.check_output(command, shell=True, timeout=5)
except Exception:
    print ("Some issues in fetching details")
    exit()
else:
    print (x)
Vipul
  • 125
  • 2
  • 11

2 Answers2

4

My guess is that you are running your code in Python 2.

If that is the case, subprocess.check_output() does not accept a timeout parameter, and the function will fail immediately with:

TypeError: __init__() got an unexpected keyword argument 'timeout'

But, because you are catching all exceptions and printing a generic message, you don't see the actual exception, and you assume that the command is timing out immediately.

One way to fix this problem is to run your code in Python 3.

Whether you are running Python 2 or 3, I recommend that you do not catch all exceptions, or that you at least print the value of the exception so that you can see the actual cause, e.g.

try:
    x=subprocess.check_output(command, shell=True, timeout=5)
except subprocess.TimeoutExpired as exc:
    print("Command timed out: {}".format(exc))
    exit()
else:
    print (x)

which explicitly checks for a timeout exception. All other exceptions are propagated as usual and so are not masked by your "catch all" code. Or,

try:
    x=subprocess.check_output(command, shell=True, timeout=5)
except Exception as exc:
    print("Command failed: {}".format(exc))
    exit()
else:
    print (x)

but the former is preferred.

Edit

OP can't use Python 3. If you are using Linux then you could use the timeout command, e.g.

x = subprocess.check_output('timeout 5 {}'.format(command), shell=True)

On timeout this will raise an exception with a particular exit status value of 124:

subprocess.CalledProcessError: Command 'timeout 5 sleep 10' returned non-zero exit status 124

BTW you shouldn't use the shell=True option as there are security implications as mentioned in the documentation. Instead you should pass a list of strings to check_output() like this:

from shlex import shlex

command = shlex('timeout 5 {}'.format(command))
try:
    x = subprocess.check_output(command)
except subprocess.CalledProcessError as exc:
    if exc.returncode == 124:
        print "Command timed out"
    else:
        raise

If you are using another OS (or you don't want to use timeout) then you can run your subprocess in a separate thread and have your main thread time it out if required. See this other question, Using module 'subprocess' with timeout, for details about how to do that.

Community
  • 1
  • 1
mhawke
  • 84,695
  • 9
  • 117
  • 138
  • thank you for your reply, but I can't use Python 3. And moreover in my question I have mentioned that on adding `timeout` the code is immediately going to the except part. It seems it has nothing to do with how generic Exception I have chosen. Can you please help me with any other solution? – Vipul Apr 16 '15 at 05:42
  • @Vipul: yes, the reason that your code goes immediately to the exception handler is explained in the answer, i.e. Python 2 does not support the timeout option for `check_output()`. The fact that you didn't know that is because your exception handler does not print the actual exception and so you were clueless as to why your code is failing. OK you can't use Python 3. What OS are you using? – mhawke Apr 16 '15 at 06:45
  • @Vipul: some alternatives added to answer. – mhawke Apr 16 '15 at 06:56
  • Linux dcnm-v1 2.6.18-128.el5 – Vipul Apr 16 '15 at 07:06
  • on doing what you stated, the code is immediately printing 'Command timed out'. Shouldn't it keep trying for 5 secs and then give timed out error message? – Vipul Apr 16 '15 at 07:20
  • Yes, it should wait 5 seconds, and it does for me. Is this the _exact_ command that you are running? `x = subprocess.check_output(['timeout', '5', 'sleep', '10'])` . What happens if you run it (just type it into a Python 2 interpreter)? – mhawke Apr 16 '15 at 11:16
  • Where do I put the command(the variable) then? I gave it like this `x = subprocess.check_output(['timeout', '5', 'sleep', '10'])` and its directly going to the except part. I also gave this `x = subprocess.check_output(command, ['timeout', '5', 'sleep', '10'])` of which I am not sure but in this case too it directly went to the except part. – Vipul Apr 17 '15 at 05:03
  • Let's just get it working first. Type `subprocess.check_output(['timeout', '5', 'sleep', '10'])` directly into a Python 2 interpreter and see what happens. It should time out after 5 seconds and an exception will be raised. If that works then construct the command using string formatting (as shown in answer) and try that. – mhawke Apr 17 '15 at 05:53
  • I am trying a lot, but everytime it says that there is a syntax error – Vipul Apr 17 '15 at 06:12
  • What is the exact error message, and in what circumstances do you see it? Does `subprocess.check_output(['timeout', '5', 'sleep', '10'])` work? Hopefully you don't see a syntax error for that. – mhawke Apr 17 '15 at 08:55
  • `import subprocess try: subprocess.check_output(['timeout', '5', 'sleep', '10']) except Exception as e: print "exception" ` This is what I tried and while running I get this error: `./test.py: line 5: syntax error near unexpected token \`['timeout',' ./test.py: line 5: \` subprocess.check_output(['timeout', '5', 'sleep', '10'])' ` – Vipul Apr 17 '15 at 09:19
  • Well you have a syntax error. Correct that and try again. I see that there might be some stray backquotes (`'`'`), but I don't know whether they are in the traceback or if you added them there for formatting. Otherwise the code looks OK. – mhawke Apr 17 '15 at 09:35
  • exactly..there is nothing extra...i have tried many times..i dont understand why its showing like that – Vipul Apr 17 '15 at 09:37
  • I also don't understand. You are using Python 2? It is very simple to enter a few lines of code and run them. Sorry, but I can not think of anything else that will assist you. – mhawke Apr 17 '15 at 09:40
2

Python 2.7 does not support timeout parameter. You can instead use EasyProcess. This is a layer on top of subprocess module and pretty easy to use.

user3379410
  • 176
  • 1
  • 11