cannot pass arguments to python script when invoke from subprocess - python

I have searched SO but couldn't find an asnwer.
I want to invoke a python script(child script) from another python script(main script). I cannot pass arguments from parent to child?
I am expecting "subprocess launched: id1-id2" from the console.
But what I am getting is "subprocess launched:test-default". The subprocess is using the default parameters instead of receiving parameters from the parent script.
# parent
import subprocess
subprocess.call(['python', 'child.py', 'id1', 'id2'])
# script name: child.py
def child(id, id2):
print ('subprocess launched: {}-{}'.format(str(id), id2))
if __name__ == '__main__':
main(id='test', id2='default')

The parameters that you pass to a Python process are stored in sys.argv [Python-doc]. This is a list of parameters, that works a bit similar to $# in bash [bash-man] for example.
Note that argv[0] is not the first parameter, but the name of the Python script you run, as is specified by the documentation:
argv[0] is the script name (it is operating system dependent whether this is a full pathname or not).
The remaining parameters are the parameters passed to the script.
You can thus rewrite your child.py to:
# script name: child.py
from sys import argv
def child(id, id2):
print ('subprocess launched: {}-{}'.format(str(id), id2))
if __name__ == '__main__':
child(id=argv[1], id2=argv[2])

Related

Running a python script which takes an argument using Robot Framework

Let's say I have a python script located at C:\script.py. This is the contents of the script:
def func1(arg1):
print (arg1)
if __name__ == "__main__":
func1(arg1)
Now, I want to run this script using Robot Framework. I'm thinking about doing something like this:
*** Test Cases ***
Test1
Run Process python C:\script.py ${arg1}
But it doesn't work. How can I run this script, and pass an argument to it?
It would be nicer if you have posted a real example that we could experiment, to understand:
But it doesn't work.
As you can see in the documentation of Run Process, you have to redirect the output of your process, so you can see it (if that was your problem).
Here is a working example based on yours:
import sys
arg1 = sys.argv[1] or None
def func1(argument):
print(argument)
if __name__ == "__main__":
func1(arg1)
*** Settings ***
Library Process
*** Test Cases ***
Test1
Run Process python C:/script.py This is my argument to script. stdout=C:/script_output.log
But maybe the best solution is to make your script as a Keyword.
First, you will have to modify your script to use command line arguments which you can find in sys.argv.
For example:
import sys
def func1(arg1):
print (arg1)
if __name__ == "__main__":
func1(sys.argv[1])
Next, you must make sure to have two or more spaces between script.py and the argument:
Run Process python C:\\script.py ${arg1}
And, of course, you need to define what ${arg1} is, which you didn't do in your example.
I agree with #Helio, making python program as a keyword will be faster and easy solution to implement.
Import py script in settings section under Library.
${result}= func1 arg1
Here func1 act as a keyword to do whatever it is suppose to do as a function. Then result variable will capture the output which then can be logged or printed to console.

Accessing variable in __main__

I am trying to access a variable from a python module which is being run as a script. The variable is defined in the if __name__ == "__main__":
The code I am working with looks something like this:
MyCode.py
cmd = 'python OtherCode.py'
os.system(cmd) # Run the other module as a python script
OtherCode.py
if __name__ == "__main__":
var = 'This is the variable I want to access'
I was wondering if there was a way to access this variable while still running the OtherCode.py as a script.
You can use the runpy module to import the module as __main__ then extract the variable from the returned dictionary:
import runpy
vars = runpy.run_module("OtherCode", run_name="__main__")
desired_var = vars["var"] # where "var" is the variable name you want
When you use os.system, it runs the specified command as a completely separate process. You would need to pass the variable through some sort of OS-level communication mechanism: stdout, a socket, shared memory, etc.
But since both scripts are Python, it would be much easier to just import OtherCode. (Though note that you will need to set up OtherCode.py inside of a package so that Python knows it can be imported.)
While this fix might not be ideal (or what people are looking for if they google it)
I ended up printing out the variable and then used subprocess to get the stdout as a variable:
MyCode.py
cmd = 'python OtherCode.py'
cmdOutput = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE).stdout
OtherCode.py
if __name__ == "__main__":
var = 'This is the variable I want to access'
print(var)
In this case the cmdOutput == var

How to make a function accept runtime arguments

I want to define a function such that I want it to accept command line arguments
below is my code
def tc1(resloc):
from uiautomator import Device;
'Do some activity'
with open(resloc, 'a') as text_file:
text_file.write('TC1 PASSED \n')
text_file.close()
else:
with open(resloc, 'a') as text_file:
text_file.write('TC1 FAILED \n')
text_file.close()
if __name__ == '__main__':
tc1("C:\\<pathtoautomation>\\Results\results.txt")
Now when I execute the same using command line from python it continues to refer to the path mentioned here tc1("C:\\<pathtoautomation>\\Results\results.txt") and doesn't consider what I pass in the runtime from the command line
\Scripts>python.exe trail.py C:\\<pathtoautomationresults>\\Results\results.txt
What you are looking is sys.argv
The list of command line arguments passed to a Python script. argv[0]
is the script name (it is operating system dependent whether this is a
full pathname or not). If the command was executed using the -c
command line option to the interpreter, argv[0] is set to the string
'-c'. If no script name was passed to the Python interpreter, argv[0]
is the empty string.
To loop over the standard input, or the list of files given on the
command line, see the fileinput module.
You use it like:
import sys
def main(argv):
# do something with argv.
if __name__ == "__main__":
main(sys.argv[1:]) # the argv[0] is the current filename.
and call it using
python yourfile.py yourargsgohere
Check out a more detailed use here.
You need to use sys.argv to get command line parameters.
in your code it could look like this:
import sys
... # other stuff
if __name__ == '__main__':
tc1(sys.argv[1])
There are many tutorials out there that help you use sys.argv

Passing Argument from Batch File to Python

I am trying to pass argument from batch file to python as following. It seems nothing has passed to 'sample' variable. My questions are
How to get argument properly?
How to check null point error when I am running .bat to execute this python? I may not be able to see the console log in IDE while executing
My batch file (.bat)
start python test.py sample.xml
My python file (test.py)
def main(argv):
sample = argv[1] #How to get argument here?
tree = ET.parse(sample)
tree.write("output.xml")
if __name__ == '__main__':
main(sys.argv[1:])
In your code, you're skipping the first argument twice.
main gets called with sys.argv[1:], skipping the first argument (program name); but then main itself uses argv[1]... skipping its first argument again.
Just pass sys.argv untouched to main and you'll be fine, for example.
Or, perhaps more elegantly, do call main(sys.argv[1:]), but then, in main, use argv[0]!
Use argparse https://docs.python.org/3/library/argparse.html
Eg: In your python file
import argparse
parser = argparse.ArgumentParser(description='Your prog description.')
parser.add_argument('-f','--foo', help='Description for foo argument', required=True)
:
:
args = parser.parse_args()
Inside your bat file
python prog.py -f <foo arg here>

Best way to call a python script from within a python script multiple times

I need to execute a python script from within another python-script multiple times with different arguments.
I know this sounds horrible but there are reasons for it.
Problem is however that the callee-script does not check if it is imported or executed (if __name__ == '__main__': ...).
I know I could use subprocess.popen("python.exe callee.py -arg") but that seems to be much slower then it should be, and I guess thats because Python.exe is beeing started and terminated multiple times.
I can't import the script as a module regularily because of its design as described in the beginning - upon import it will be executed without args because its missing a main() method.
I can't change the callee script either
As I understand it I can't use execfile() either because it doesnt take arguments
Found the solution for you. You can reload a module in python and you can patch the sys.argv.
Imagine echo.py is the callee script you want to call a multiple times :
#!/usr/bin/env python
# file: echo.py
import sys
print sys.argv
You can do as your caller script :
#!/usr/bin/env python
# file: test.py
import sys
sys.argv[1] = 'test1'
import echo
sys.argv[1] = 'test2'
reload(echo)
And call it for example with : python test.py place_holder
it will printout :
['test.py', 'test1']
['test.py', 'test2']

Categories