I need to interpret few files (scripts) by embedded python interpreter concurrently (to be more detailed one script executes another script as Popen and my app intercepts it and executes it itself). I've found it's called sub-interpreter and i'm going to use it. But i've read sub-interpreter does not have sys.argv:
The new environment has no sys.argv variable
I need to pass argv anyway so how can i do it?
You might find it easier to modify each of the scripts follow the pattern:
def run(*posargs, **argdict):
"""
This does the work and can be called with:
import scriptname
scriptname.run(someargs)
"""
# Code goes here and uses posargs[n] where it would use sys.argv[n+1]
if __name__ == "__main__":
import sys
run(sys.argv[1:])
Then your main script can just call each of the subscripts in turn by simply calling the run method.
You can use environment variables. Have the parent set them by updating the dict os.environ if it's in Python, or setenv() if in C or C++ etc. Then the children can read os.environ to get whatever strings they need.
Related
I'm working on cloning a Virtual Machine (VM) in vCenter environment using this code. It takes command line arguments for name of the VM, template, datastore, etc. (e.g. $ clone_vm.py -s <host_name> -p < password > -nossl ....)
I have another Python file where I've been able to list the Datastore volumes in descending order of free_storage. I have stored the datastore with maximum available storage in a variable ds_max. (Let's call this ds_info.py)
I would like to use ds_max variable from ds_info.py as a command line argument for datastore command line argument in clone_vm.py.
I tried importing the os module in ds_info.py and running os.system(python clone_vm.py ....arguments...) but it did not take the ds_max variable as an argument.
I'm new to coding and am not confident to change the clone_vm.py to take in the Datastore with maximum free storage.
Thank you for taking the time to read through this.
I suspect there is something wrong in your os.system call, but you don't provide it, so I can't check.
Generally it is a good idea to use the current paradigm, and the received wisdom (TM) is that we use subprocess. See the docs, but the basic pattern is:
from subprocess import run
cmd = ["mycmd", "--arg1", "--arg2", "val_for_arg2"]
run(cmd)
Since this is just a list, you can easily drop arguments into it:
var = "hello"
cmd = ["echo", var]
run(cmd)
However, if your other command is in fact a python script it is more normal to refactor your script so that the main functionality is wrapped in a function, called main by convention:
# script 2
...
def main(arg1, arg2, arg3):
do_the_work
if __name__ == "__main__":
args = get_sys_args() # dummy fn
main(*args)
Then you can simply import script2 from script1 and run the code directly:
# script 1
from script2 import main
args = get_args() # dummy fn
main(*args)
This is 'better' as it doesn't involve spawning a whole new python process just to run python code, and it generally results in neater code. But nothing stops you calling a python script the same way you'd call anything else.
My robot keyword looks like this:
${HW_list} Get_hw_list ${file}
Run process python python_test.py
Inside my python_test.py
from robot.libraries.BuiltIn import BuiltIn
List_of_modules = BuiltIn().get_variable_value("${HW_list}")
Im having an error saying,
robot.libraries.BuiltIn.RobotNotRunningError: Cannot access execution
context
I've tried searching for similar issues but I can't find where I am wrong. I also have RF==3.1.2 since in 1 post, I think there was an issue that was fixed on this version.
Run process will run your module in a separate interpreter. That's why it cannot find the execution context.
Instead, do the following:
Make a custom keyword from your module code:
from robot.libraries.BuiltIn import BuiltIn
def my_custom_keyword():
List_of_modules = BuiltIn().get_variable_value("${HW_list}")
Import the module as a Library in your robot code:
*** Settings ***
Library python_test.py
Use the keyword in your test, instead of Run process:
${HW_list} Get_hw_list ${file}
My Custom Keyword
Since you are running python_test.py as a separate process, you can't directly use robot variables or keywords in the separate process.
If you don't want to pass the value as arguments, you're going to have to use some other method. For example, you could set an environment variable and have your script pick the data up from the environment. This can only be used to pass strings.
Another option would be for your robot script to write the data to a file or database, and have your script read that file or database to get the value.
I'm trying to run tcl script from python,
tcl script requires command line arguments to execute, when I source the tcl file from python, it then shows the error says
tclsh.eval('source "test.tcl"' )
_tkinter.TclError: can't read "::argv": no such variable
I've done many searches, majority of them asks how to pass arguments to python in tcl.
python code
import tkinter
import sys
tclsh.eval('source "test.tcl"' )
if __name__ == '__main__':
print("hi")
tcl code
puts [lindex $::argv 0]
Is there anyway for me pass python arguments to tcl ?
or
not pass arguments and still compile ?
since if I compile tcl script only without arguments, it still compiles
Note:
In tkinter documentation it says tkinter.Tk is
The Tk class is instantiated without arguments
Is there a way to instantiated with arguments ?
Sol:
tclsh.eval('set argv [list]')
tclsh.eval('set argc 0')
I tried to set a global variable and it works for me under python 3.6
The global argv variable is, apart from being set during the startup of a standard Tcl script, not special in any way. You can therefore just set it prior to doing source. In this case, doing so with lappend in a loop is probably best as it builds the structure of the variable correctly. There are two other variables that ought to be set as well (argc and argv0); overall you do it like this (as a convenient function):
def run_tcl_script(script_name, *args):
tclsh.eval('set argv0 {{{}}}'.format(script_name))
tclsh.eval('set argv {}; set argc 0')
for a in args:
tclsh.eval('lappend argv {{{}}}; incr argc'.format(a))
tclsh.eval('source $argv0')
The {{{}}} with Python's str.format results in a single layer of braces being put around the argument, defending against most quoting issues.
Research is at the bottom, read before -1'ing... Thanks.
I have to write a Python script that runs SQL queries. I made a main class and called SQLQuery. Each SQLQuery instance represents a query. The script must be structured like this:
class SQLQuery(object):
def __init___(self, string_myQuery)...
instance1 = SQLQuery(SQLQuery1)...
instance2 = SQLQuery(SQLQuery2)...
As a user requirement, the instances must be in the same file as the class (so I can't just make each instance a main and execute that file separately), and each instance must be executed with Linux console commands. I can execute the entire script with a simple python SQLQuery.py but I need to execute each instance separately. The queries will be executed every day, automatically, so I don't need a terminal UI tree. It should be executed with a command similar to this:
python SQLQuery.py -inst1
will execute instance1.
python SQLQuery.py -inst2
will execute instance2.
I have researched how to execute Python scripts with Linux commands and most of the articles are about calling commands from the Python script. However, I found this article from the Python documentation. It suggests adding -m, so:
python SQLQuery.py -m inst1
This would let me set my main with a console command, but it doesn't work since the instances aren't modules. And since the instances must be in the same file as the class, I can't just import them as a module when I execute SQLQuery.py with a console command.
Ignoring all the irrelevancies, it sounds like your problem is that you have a bunch of global objects named instance1, instance2, instance3, etc., and you want to call some method on one of them based on a command-line parameter whose value will be similar to, but not identical to, the instance names.
That's probably not a good idea… but it's not that hard:
if __name__ == '__main__':
inst = sys.argv[1] # will be 'inst1', 'inst13', etc.
inst_number = inst[5:] # so '1', '13', etc.
inst_name = 'instance' + inst_number
instance = globals()[inst_name]
instance.execute()
A much better way to do the same thing is to put the instance globals into a list or dict that you can index.
For example, let's say instead of instance1, instance2, etc., you've got an instances dict, with instances['1'], instances[2], etc. Now instead of this:
inst_name = 'instance' + inst_number
instance = globals()[inst_name]
instance.execute()
… you just do this:
instances[inst_number].execute()
Also, instead of coming up with a command-line parameter that has extra stuff in it that you have to parse and throw away, and has no more meaning for a human reader than for your code, why not just take a number?
python myscript.py 12
Or, alternatively, use argparse to create an argument that can be used in all of the obvious ways:
python myscript.py --instance=12
python myscript.py --instance 12
python myscript.py -i12
python myscript.py -i 12
Either way, your code gets the string '12', which it can then use to look up the function, as above.
You have the wrong syntax for the -m option. Suppose you have the following file named foo.py:
import sys
print 'First arg is: ', sys.argv[1]
Then you would call it like this:
$ python -m foo bar
First arg is: bar
Note that the ".py" extension is omitted. You can then use the command line argument to decide which object to use or use the argparse or optparse module to handle the argument.
I got two different python script, the first one is using argparse to get some additional argument (I will call it arg.py) and the second one is my main script (main.py).
I want to call arg.py inside main.py but I don't know how to do so. I take a look at the command execfile but I didn't manage to make it work.
I try to put
execfile('arg.py -h')
In main.py but python try to find the file 'arg.py -h' which doesn't exist. Does anyone know how to do that ?
Thanks in advance
You can run it as a separate process using subprocess.call or subprocess.Popen. If you don't want to run it as a child process, then it starts to get more complicated (depending on the structure of your arg.py script.
execfile takes the file you pass to it and includes it in the current script -- Much like a #include pre-processor directive in c/c++ (although this is done dynamically). One really ugly option using execfile would be:
#completely untested.
import sys
def run_script(script_name,*args):
_argv = sys.argv[:]
sys.argv = list(args)
execfile(script_name)
sys.argv = _argv