Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

returncode of Popen object is None after the process is terminated

I'm running a process with the use of Popen. I need to wait for the process to terminate. I'm checking that the process have terminated through the returncode. When returncode is different from None the process must have terminated. The problem is that when print_output is False the returncode is always None, even when the process have finished running (terminated). This is however not the case when print_output is True. I'm using the following code to run the process:

def run(command, print_output=True):
    # code mostly from: http://sharats.me/the-ever-useful-and-neat-subprocess-module.html
    from subprocess import Popen, PIPE
    from threading import Thread
    from queue import Queue, Empty
    from time import sleep

    io_q = Queue()

    def stream_watcher(identifier, stream):
        for line in stream:
            io_q.put((identifier, line))

        if not stream.closed:
            stream.close()

    with Popen(command, stdout=PIPE, stderr=PIPE, universal_newlines=True) as proc:
        if print_output:

            Thread(target=stream_watcher, name='stdout-watcher', args=('STDOUT', proc.stdout)).start()
            Thread(target=stream_watcher, name='stderr-watcher', args=('STDERR', proc.stderr)).start()

            def printer():
                while True:
                    try:
                        # Block for 1 second.
                        item = io_q.get(True, 1)
                    except Empty:
                        # No output in either streams for a second. Are we done?
                        if proc.poll() is not None:
                            break
                    else:
                        identifier, line = item
                        print(identifier + ':', line, end='')

            Thread(target=printer, name='printer').start()

        while proc.returncode is None:
            sleep(2)
            proc.poll()

        if not proc.returncode == 0:
            raise RuntimeError(
                'The process call "{}" returned with code {}. The return code is not 0, thus an error '
                'occurred.'.format(list(command), proc.returncode))

        return proc.stdout, proc.stderr

Any clues to what might cause this problem?

EDIT: Discovered something pretty weird. I'm running the following code:

run(my_command, True)
print('--------done--------')
run(my_command, False)
print('--------done--------')

'--------done--------' is never printed even though run(my_command, False) gets executed.

like image 245
user684322 Avatar asked Jun 21 '16 10:06

user684322


People also ask

How do I know if my subprocess Popen is running?

Popen has a built-in method to determine if the subprocess is still running, Popen. poll(). In your code process.

What is Returncode in Python?

The returncode() function provides a simple way to get the return code set by the command executed. The command is run in a sub-process and must require no input. For example, suppose you needed to get the return code set by the following python script: import sys sys. exit(4)

What is Popen in Python?

Python method popen() opens a pipe to or from command. The return value is an open file object connected to the pipe, which can be read or written depending on whether mode is 'r' (default) or 'w'. The bufsize argument has the same meaning as in open() function.

What does Python subprocess Popen return?

Popen Function The function should return a pointer to a stream that may be used to read from or write to the pipe while also creating a pipe between the calling application and the executed command. Immediately after starting, the Popen function returns data, and it does not wait for the subprocess to finish.


1 Answers

TL;DR

add popen.wait() after subprocess.Popen()

Explanation Part (sort of)

Python goes too fast and the child process is ended but returncode can't be read

(I don't really know why it does that. Explanations welcome)

Why did I use this:

Shell command execution and get both return code and output (stdout)

def exec_cmd(cmd):
    pop = subprocess.Popen(shlex.split(cmd), stderr=subprocess.STDOUT, stdout=subprocess.PIPE)
    pop.wait()
    return [pop.returncode, pop.communicate()[0]]

Also: please read the .wait warning on the popen page

like image 168
Boop Avatar answered Oct 06 '22 00:10

Boop