Antoine Gallix
Antoine Gallix

Reputation: 816

Call command-line oriented script from another python script

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])

Upvotes: 0

Views: 199

Answers (2)

ElmoVanKielmo
ElmoVanKielmo

Reputation: 11290

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!

Upvotes: 1

jcfollower
jcfollower

Reputation: 3158

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.

Upvotes: 1

Related Questions