Return value of variable from subprocess in python

I have a code workflow where, from a main script (level 0), I call another script through subprocess

. This one subprocess script

(level 1) in turn calls another script like subprocess

. Now from this level 2 sub-process script I want to return the value of a variable before the main script (level 0). I have tried Popen.communicate()

but I cannot return the value. My current code:

main_script.py

def func():

    para = ['a','b']
    result = subprocess.Popen([sys.executable,"first_subprocess.py"]+para,stdout=subprocess.PIPE)
    result.wait()

    return_code = result.returncode
    out, err = sub_result.communicate()


    if return_code == 1:
        return return_code

    else:
        if out is not None:
            print 'return value: ', out


if __name__ == '__main__':

    func()

      

Above, a script is called first_subprocess.py

which has:

def some_func():

    # some other code and multiple print statements

    para = ['a','b']
    result = subprocess.Popen([sys.executable,"second_subprocess.py"]+para,stdout=subprocess.PIPE)

    result.wait()
    out, err = result.communicate()
    return_code = sub_result.returncode
    if return_code == 0:
        return out


if __name__ == '__main__':

    some_func()

      

second_subprocess.py

returns a value similar to:

def test():
    # some other code and multiple print statements
    val = 'time'
    print 'returning value'
    return val   

if __name__ == '__main__':    

    test()

      

When I try to execute the code above, I get all the statements print

in the codes as output, but not the return value. Even if you try to print

change the value of a variable in a subprocess instead of executing, it will not serve the purpose because there are multiple print statements. In the meantime, there is no need to know about it. ”

How can I return the value of a variable in this case?

UPDATED VERSION:

Following @Anthons suggestion, I changed my first_subprocess.py

script and main_script.py

as follows:

first_subprocess.py:

def some_func():

   try:
    key = None
    if not (key is None):

       para = ['a','b']
       result = subprocess.Popen([sys.executable,"second_subprocess.py"]+para,stdout=subprocess.PIPE)

       sub_result.wait()
       out, err = sub_result.communicate()
       return_code = sub_result.returncode
       if return_code == 0:
       for line in out.splitlines():
           if not line.startswith('>>>'):
              continue
           print line
   else:
     sys.exit(0)
 except:
   return 1

      

Main_script.py:

if out is not None:
   for line in out.splitlines():
       if not line.startswith('>>>'):
          continue
      value = line.split(':',1)[1].lstrip()

print 'return value:',value`

      

When I execute the above, I get UnboundLocalError: local variable 'value' referenced before assignment

in command print value

. It seems that if I do not execute the code in level 1 script and execute sys.exit () then out

in the main script it is neither empty nor single, except it is undefined and therefore value

does not get initialized and throws an error

+3


source to share


1 answer


If you just want to return an integer value, you can use the exit value. This is not the same return from some_func()

you will need to do sys.exit(integer_val)

.

If you want to return a string of type time

, you have to print it (or write to sys.stdout

) and then in the calling process (level 1) parse the output from the subprocess and print it to your own stdout for level 0 to see it.

In your case, the second level should do something like:

def test():
    # some other code and multiple print statements
    val = 'time'
    print 'returning value:', val

if __name__ == '__main__':    
    test()

      

And at level 1, you would do:

def some_func():

    # some other code and multiple print statements

    para = ['a','b']
    result = subprocess.Popen([sys.executable,"second_subprocess.py"]+para,stdout=subprocess.PIPE)

    result.wait()
    out, err = result.communicate()
    return_code = sub_result.returncode
    if return_code == 0:
        print out

if __name__ == '__main__':
    some_func()

      

With this main_script.py, there is a lot to read from calling your level 1 script.

I usually use subprocess.check_output()

for this kind of information transfer. This will throw an exception if the called process has a non-zero exit status (i.e. On error). I can also recommend that if a subprocess writes more information than just a variable, you can easily handle the output lines by returning something unique at the beginning of the line (so you can still use print statements to debug individual scripts and get the correct value from the output ):

Level 2:

def test():
    # some other code and multiple print statements
    print 'debug: Still going strong'
    val = 'time'
    print '>>>> returning value:', val

if __name__ == '__main__':    
    test()

      

Level 1:

...
out, err = result.communicate()
for line in out.splitlines():
    if not line.startswith('>>>>'):
        continue
    print line
...

      

Level 0:



...
out, err = result.communicate()
for line in out.splitlines():
    if not line.startswith('>>>>'):
        continue
    try:
        value = line.split(':', 1)[1]
    except IndexError:
        print 'wrong input line', repr(line)
    print 'return value: ', value
...

      


The following files work together. Save them under the specified names

lvl2.py

# lvl2
import sys

def test():
    # some other code and multiple print statements
    print >> sys.stderr, 'argv', sys.argv[1:]
    print 'debug: Still going strong'
    val = 'time'
    print '>>>> returning value:', val
    return 0

if __name__ == '__main__':
    sys.exit(test())

      

lvl1.py

# lvl1.py
import sys
import subprocess

def some_func():
    para = ['a','b']
    sub_result = subprocess.Popen(
        [sys.executable, "lvl2.py" ] + para,
        stdout=subprocess.PIPE)
    sub_result.wait()
    out, err = sub_result.communicate()
    return_code = sub_result.returncode
    if return_code == 0:
        for line in out.splitlines():
            if not line.startswith('>>>'):
                continue
            print line
    else:
        print >> sys.stderr, 'level 2 exited with' + return_code
    sys.exit(0)

if __name__ == '__main__':
    sys.exit(some_func())

      

lvl0.py

# lvl0
import subprocess
import sys

def func():
    para = ['a','b']
    result = subprocess.Popen(
        [sys.executable, "lvl1.py"] + para,
        stdout=subprocess.PIPE)
    result.wait()
    return_code = result.returncode
    out, err = result.communicate()

    value = None
    if return_code == 0:
        for line in out.splitlines():
            if not line.startswith('>>>'):
                continue
            value = line.split(':',1)[1].lstrip()
            print
    else:
        print 'non-zero exit', return_code
    print 'return value:', value

if __name__ == '__main__':
    func()

      

Then run python lvl0.py

to check the output

argv ['a', 'b']

return value: time

      

Now bring them under your version control system and start modifying a few lines at a time, each time you start python lvl0.py

, to check what you might have broken. Commit each revision so you can revert to the last "known good" state and slowly re-enter the rest of your code.

+1


source







All Articles