Sign up ×
Stack Overflow is a community of 4.7 million programmers, just like you, helping each other. Join them; it only takes a minute:

I am using a script written in Python that uses the argparse module to get it's arguments from command line. I try to modify this file as less as possible as various people work on it.

Ex: script is called CLscript.py and I call it with

python CLscript.py -option1 arg1 -flag1 -option2 arg2

But I'm facing the case where I would like to automate things one level higher and automatically launch this script with wide range of script-generated arguments.

I would like to keep using all the existing organisation of options and flags available in this script.

For example, when I run CLscript.py from topLevelScript.py through :

subprocess.call("python CLscript.py -option1 arg1 -flag1 -option2 arg2")

,and I see from the output that something is going wrong, I stop the execution topLevelScript.py, but CLscript.py continue to run independently in another python process that I Have to kill manually. I cannot neither launch topLevelScript.py in debug mode to stop at a breakpoint in CLscript.py.

I would like to do this all from inside python, without building a command line string and launching CLscript.py with a subprocess. Every call would remains attached to the same original launch, just like a function call, and not creating multiple python threads like it would do with a subprocess.call() .

Something like passing a list of string with options, flags and arguments somehow to the script maybe?

Is there something like

import CLscript.py
CLsimulator(CLscript,["-option1",arg1,"-flag1","-option2",arg2])
share|improve this question
    
"creating multiple python threads like it would do with a subprocess.call()" - subprocess module is not related to threads. – ElmoVanKielmo Mar 24 '14 at 11:42
    
Actually I am not quite clear what you want to do, would you please specify it more detailed or give an example? – lowitty Mar 24 '14 at 11:46
1  
"Something like passing a list of string with options, flags and arguments" - first argument for subprocess.call() is a list of strings. – ElmoVanKielmo Mar 24 '14 at 11:48
    
I edited my question to make it clearer – antoine Mar 24 '14 at 14:23
    
@ElmoVanKielmo see my edits for why I try not to use subprocess.call() – antoine Mar 24 '14 at 14:25

2 Answers 2

up vote 1 down vote accepted

First of all, use http://docs.python.org/2/library/subprocess.html#subprocess.Popen and not subprocess.call():

import subprocess

child = subprocess.Popen(
    ['python', 'CLscript.py', '-option1', 'arg1', '-flag1', '-option2', 'arg2'],
    stdin=subprocess.PIPE,
    stdout=subprocess.PIPE,
    stderr=subprocess.PIPE
)

Please notice that as the first argument you pass an array of strings just like you want.
Secondly redirection of standard file descriptors will be important. See http://docs.python.org/2/library/subprocess.html#subprocess.PIPE.
Now you have child variable which holds instance of Popen class.
What you can do with this instance?

# Check if child is terminated and possibly get the returncode
child.poll()
# Write to child's standard input by a file-like object accessible with
child.stdin
# Read child's standard output and standard error by file-like objects accesible with
child.stdout
child.stderr

You said you wanted to detect if something goes wrong in the child process from it's output.
Don't you find stdout and stderr quite useful for this case?
Now you wanted to terminate the child if you detected that something went wrong.

child.kill()
child.terminate()
child.send_signal(signal)

If in the end you are sure that everything went well but you want to let child finalize normally, you should use

child.wait()

or even better

child.communicate()

because communicate will handle lots of output properly.

Good luck!

share|improve this answer
    
Ok, I thougt before of Popen as some low-level thing I shouldn't touch and use call instead, but like this it doesn't seems so complicated. Thank you! – antoine Mar 25 '14 at 9:58
1  
@antoine subprocess.call(...) is actually a shorthand for child = subprocess.Popen(...) without pipes to stdin, stdout, stderr followed by child.wait(). – ElmoVanKielmo Mar 25 '14 at 10:05

Would something like this work? Extract most of your code into a new function that expects arguments similar to the ones you send in via the command line. Then write a new function that gathers the command line arguments and sends them to the first function ...

def main(foo, bar):
    a = foo + bar
    print a

def from_command_line():
    foo, bar = get_command_line_args()
    main(foo, bar)

if __name__ == "__main__":
    from_command_line()

Then your other scripts can just call the main function.

share|improve this answer
    
That would be a neat way to handle the problem, I like the idea, thank you. Nevertheless in my particular case, as it's a cooperative project, I cannot modify this file and Elmo's answer allows me to do it. – antoine Mar 25 '14 at 9:57

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.