I am trying to add command line options to my script, using the following code:
import argparse
parser = argparse.ArgumentParser('My program')
parser.add_argument('-x', '--one')
parser.add_argument('-y', '--two')
parser.add_argument('-z', '--three')
args = vars(parser.parse_args())
foo = args['one']
bar = args['two']
cheese = args['three']
Is this the correct way to do this?
Also, how do I run it from the IDLE shell? I use the command
'python myprogram.py -x foo -y bar -z cheese'
and it gives me a syntax error
That will work, but you can simplify it a bit like this:
args = parser.parse_args()
foo = args.one
bar = args.two
cheese = args.three
use args.__dict__
args.__dict__["one"]
args.__dict__["two"]
args.__dict__["three"]
The canonical way to get the values of the arguments that is suggested in the documentation is to use vars as you did and access the argument values by name:
argv = vars(args)
one = argv['one']
two = args['two']
three = argv['three']
Related
I'm developing a game in pygame and I'm trying to use command line arguments.
Here's an example of what I'm trying to do with a description at the top:
# user sets variables with command lines. some options:
# python test.py (all default settings)
# python test.py -f (for fog)
# python test.py -f -m (for fog and multiplayer)
# python test.py -m (for multiplayer)
# default settings
fog = False
mode = 'singleplayer'
if fog == True:
print(1)
else:
print(2)
if mode == 'multiplayer':
print(3)
How do I make it so that the user can type an option as stated in my 4 test cases and it will change the value of my variables?
I've looked at https://docs.python.org/3/library/argparse.html#module-argparse and wasn't able to understand how I can do what I want to do.
See the example in the argparse documentation. You would do something like:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('-f', action='store_true')
parser.add_argument('-m', action='store_true')
args = parser.parse_args()
print(args.f)
print(args.m)
I have an entry point like so:
ENTRYPOINT [ "python" ,"/usr/local/bin/script.py" ]
I want to be able to add multiple arguments to script.py if a particular container has "MY_ENV_VAR" set to TRUE.
So for instance if:
MY_ENV_VAR = true
MY_ENV_VAR2 = true
MY_ENV_VAR3 = false (or anything other than true)
I want to run
/usr/local/bin/script.py --my-env-var --my-env-var2
I can't find a good working example of how to accomplish this
You will not be able to conditionally do this within the Dockerfile, but you can achieve the desired behavior by configuring the Python script script.py as follows:
import argparse
import os
def main():
parser = argparse.ArgumentParser("Arguments")
if os.environ.get("MY_ENV_VAR") is not None:
parser.add_argument("--my-env-var", required=True, action="store_true")
if os.environ.get("MY_ENV_VAR2") is not None:
parser.add_argument("--my-env-var2", required=True, action="store_true")
parser.parse_args()
if __name__ == "__main__":
main()
The logic is that if MY_ENV_VAR or MY_ENV_VAR2, then a required argparse argument is set.
I have a lot of arguments to pass to my main.py. It's easier to store them in a txt file. So, i would like to know best way of using "config" files to pass CL args.
Shell script is not what i need, unfortunatly.
If you plan to use argparse, then fromfile_prefix_chars is designed to solve exactly this problem.
In your launching program, put all of the arguments, one per line, into a file. Pass #file.txt to your child program. In your child program, pass a fromfile_prefix_chars parameter to the ArgumentParser() constructor:
parser = argparse.ArgumentParser(fromfile_prefix_chars='#')
argparse takes care of the rest for you.
Here is an example:
from argparse import ArgumentParser
parser = ArgumentParser(fromfile_prefix_chars='#')
parser.add_argument('-f', '--foo')
parser.add_argument('--bar')
parser.add_argument('q', nargs='*')
ns = parser.parse_args()
print(ns)
The contents of foo.txt:
-f
1
--bar=2
q one
q two
The command line and the output:
$ python zz.py #foo.txt
Namespace(bar='2', foo='1', q=['q one', 'q two'])
Use configparser. It uses .ini files and it's really easy to use.
Config file:
[DEFAULT]
KeepAlive = 45
ForwardX11 = yes
Example Code:
>>> config = configparser.ConfigParser()
>>> config.sections()
[]
>>> config.read('example.ini')
>>> for key in config['bitbucket.org']: print(key)
...
keepalive
forwardx11
>>> default = config['default']
>>> default['keepalive']
'45'
>>> default['ForwardX11']
'yes'
Here is a simple function that converts any #foo argument into the contents of foo, one argument per line. After the conversion, you may use sys.argv in any of the normal ways.
import sys
def expand_arg_files(args):
for arg in args:
if arg.startswith('#'):
with open(arg[1:]) as f:
file_args = f.read().splitlines()
yield from expand_arg_files(file_args)
else:
yield arg
sys.argv[:] = expand_arg_files(sys.argv[:])
print(sys.argv)
Notes:
The generator delegation syntax requires Python3.3 or higher.
You may have # args inside the argument file. The expansion is recursive.
I am using argparse to parse the Python command line which is supposed to look like this:
python script_name.py --sdks=first, second
My script looks like this:
sdk_choises = ['aio','sw']
parser = argparse.ArgumentParser(description='Blah blah')
parser.add_argument('--sdks', action='append', nargs='+', required=True, help='specifies target SDK(s)')
args = parser.parse_args()
if 'aio' in args.sdks:
# do something with aio
if 'sw' in args.sdks:
# do something with sw
When I execute:
python script_name.py --sdks=aio, sw I get error:
"usage: script.py [-h] --sdks SDKS [SDKS ...]
build.py: error: unrecognized arguments: sw"
I'd like to be able to choose one or all choices:
python script_name.py --sdks=first
python script_name.py --sdks=second
python script_name.py --sdks=first, second
Where did I go wrong?
The following works nice:
import argparse
parser = argparse.ArgumentParser(description='Blah blah')
parser.add_argument('--sdks', nargs='+', required=True, help='specifies target SDK(s)')
args = parser.parse_args()
print(args.sdks)
You don't need the = when passing options, just use:
$ python test.py --sdks ai pw
['ai', 'pw']
If you prefer your original form of the comma-separated list, plus check if the argument is valid, then I recommend:
parser.add_argument('--sdks', nargs=1, type=lambda s: [sdk_choises[sdk_choises.index(f)] for f in s.split(',')], ...
Even cleaner way is to define it in a separate function similar to lambda above:
parser.add_argument('--sdks', nargs=1, type=my_parse_function, ...
argparse docs has examples for the parsing function with proper error reporting.
With nargs=1 you'd need to remove one extra list layer.
I've google'd quite a bit, and read the argparse documentation that I think suggests using something with vars(). I get the Namespace violation as expected, I just cant figure out the path around this issue.
Essentially, I would like to take an argparse multi-value argument and create a list from those values so I can run a for-loop through them. This is to interface with our VNX array to reset the data snapshot on all the Developer environments.
When I run the command I can see the argparse is getting the values correctly, but its throwing the Namespace exception and not actually using the values for the argument.
Much appreciation for any guidance, even a link to some better docs that will explain my problem better. I know the issue, and how I want to fix it, I'm just not sure what to even read(or google) to get around this syntax-wise?
This is what I get when i run the code:
[root#robot.lipsum.com tmp]# ./envrestore.py -e dev1 dev2 dev3
Namespace(myenv=['dev1', 'dev2', 'dev3'])
Traceback (most recent call last): File "./envrestore.py", line 43, in
run_create_snap() File "./envrestore.py", line 36, in run_create_snap
for e in myenv: TypeError: 'Namespace' object is not iterable
[root#robot.lipsum.com tmp]#
#!/usr/bin/env python
import pexpect, sys, datetime, argparse, time
from fabric.api import *
parser = argparse.ArgumentParser()
parser.add_argument('-e', '--myenv', nargs='*', type=str)
print parser.parse_args()
array = "vnx.lipsum.com"
seckey = "/opt/Navisphere/blah"
myenv = parser.parse_args()
dbhosts = ['mongo01', 'mysql01']
# !! DO NOT CHANGE IDs !!
lunpnum = "0000000"
mongo_plunid = "3"
mysql_plunid = "4"
def delete_snap(env=myenv, host=dbhosts):
child = pexpect.spawn('naviseccli -secfilepath %s -h %s snap -destroy -id %s-%s-snap' % (seckey, array, host, env))
print child
child.logfile = sys.stdout
child.expect('Are you sure you want to perform this operation\?\(y\/n\):')
child.sendline('n')
def create_snap(env=myenv, host=dbhosts, lunid=''):
print "naviseccli -secfilepath %s -h %s snap -create -res %s -name %s-%s-snap -allowReadWrite yes" % (seckey, array, lunid, host, env)
def run_delete_snap():
for e in myenv:
for h in dbhosts:
delete_snap(env=e, host=h)
def run_create_snap():
for e in myenv:
for h in dbhosts:
if "mysql" in h:
create_snap(env=e, host=h, lunid=mysql_plunid)
elif "mongo" in h:
create_snap(env=e, host=h, lunid=mongo_plunid)
run_create_snap()
I believe the problem is in what you are passing as myenv:
myenv = parser.parse_args()
I think you mean
myenv = parser.parse_args().myenv
Cheers!
myenv is the argparse.Namespace instance itself. To get the values in the option named myenv, use myenv.myenv.
for e in myenv.myenv:
print(e)
Or, to make the code clearer, name the Namespace something else:
args = parser.parse_args()
for e in args.myenv:
...