Python argparse save argument into a variable - python

Im trying to save the argparse argument into a variable.
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('-n', dest='noww', action='store', help="shows noww")
args = parser.parse_args()
print(noww)
but its giving this error.
python c:/Users/rbhuv/Desktop/code/testing.py -n sdad
Traceback (most recent call last):
File "c:/Users/rbhuv/Desktop/code/testing.py", line 8, in <module>
print(noww)
NameError: name 'noww' is not defined

It should be args.noww instead of noww.

When you make the parse_args call, you get back a Namespace object:
>>> args = parser.parse_args(['-n', 'sdad'])
>>> args
Namespace(noww='sdad')
From here you can access the value as an attribute:
>>> args.noww
'sdad'

You need to reformat your argument a bit.
parser.add_argument('-n', '--now', action='store_true', help="shows noww")
args = parser.parse_args()
print(args.now)
When using optional arguments, use -- to define the variable name you will use throughout and then you can call it like such.

Convert the args to a dictionary using vars
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('-n', dest='noww', action='store', help="shows noww")
args = parser.parse_args()
args = vars(args)
print(args["noww"])

Related

Argparse Unable to access optional argument with specific name [duplicate]

I want to have some options in argparse module such as --pm-export however when I try to use it like args.pm-export I get the error that there is not attribute pm. How can I get around this issue? Is it possible to have - in command line options?
As indicated in the argparse docs:
For optional argument actions, the value of dest is normally inferred from the option strings. ArgumentParser generates the value of dest by taking the first long option string and stripping away the initial -- string. Any internal - characters will be converted to _ characters to make sure the string is a valid attribute name
So you should be using args.pm_export.
Unfortunately, dash-to-underscore replacement doesn't work for positional arguments (not prefixed by --).
E.g:
parser = argparse.ArgumentParser(description='Process some integers.')
parser.add_argument('logs-dir',
help='Directory with .log and .log.gz files')
parser.add_argument('results-csv', type=argparse.FileType('w'),
default=sys.stdout,
help='Output .csv filename')
args = parser.parse_args()
print args
# gives
# Namespace(logs-dir='./', results-csv=<open file 'lool.csv', mode 'w' at 0x9020650>)
So, you should use 1'st argument to add_argument() as attribute name and metavar kwarg to set how it should look in help:
parser = argparse.ArgumentParser(description='Process some integers.')
parser.add_argument('logs_dir', metavar='logs-dir',
nargs=1,
help='Directory with .log and .log.gz files')
parser.add_argument('results_csv', metavar='results-csv',
nargs=1,
type=argparse.FileType('w'),
default=sys.stdout,
help='Output .csv filename')
args = parser.parse_args()
print args
# gives
# Namespace(logs_dir=['./'], results_csv=[<open file 'lool.csv', mode 'w' at 0xb71385f8>])
Dashes are converted to underscores:
import argparse
pa = argparse.ArgumentParser()
pa.add_argument('--foo-bar')
args = pa.parse_args(['--foo-bar', '24'])
print args # Namespace(foo_bar='24')
Concise and explicit but probably not always acceptable way would be to use vars():
#!/usr/bin/env python3
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('a-b')
args = vars(parser.parse_args())
print(args['a-b'])
getattr(args, 'positional-arg')
This is another OK workaround for positional arguments:
#!/usr/bin/env python3
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('a-b')
args = parser.parse_args(['123'])
assert getattr(args, 'a-b') == '123'
Tested on Python 3.8.2.
I guess the last option is to change shorten option -a to --a
import argparse
parser = argparse.ArgumentParser(description="Help")
parser.add_argument("--a", "--argument-option", metavar="", help="") # change here
args = parser.parse_args()
option = args.a # And here
print(option)

Argparse: str object has no attribute

Not sure what is going on here. Passing 2 arguments to an argparser, getting an error. Am I passing my arguments improperly?
Here is the code I am running.
parser = argparse.ArgumentParser()
parser.add_argument('-dspath', '--datasheet-path', required=True, dest='datasheet_path', type=str, help='path to data')
parser.add_argument('-pname', '--project-name', required=True, dest='project_name', type=str, help='name of project')
args = parser.parse_args("./path_to_project", "name_of_project")
I get the following error:
Traceback (most recent call last):
File "/Users/ayoung/PycharmProjects/pdf_scraper_atul/datasheet_rms_comparator 3.py", line 1320, in <module>
args = parse_args()
File "/Users/ayoung/PycharmProjects/pdf_scraper_atul/datasheet_rms_comparator 3.py", line 26, in parse_args
args = parser.parse_args("./path_to_project", "name_of_project")
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/argparse.py", line 1749, in parse_args
args, argv = self.parse_known_args(args, namespace)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/argparse.py", line 1772, in parse_known_args
setattr(namespace, action.dest, action.default)
AttributeError: 'str' object has no attribute 'datasheet_path'
Thanks!
Since argparse is not taking any positional arguments, you have to include the --flags to tell argparse where to look for the arguments.
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('-dspath', '--datasheet-path', required=True, dest='datasheet_path', type=str, help='path to data')
parser.add_argument('-pname', '--project-name', required=True, dest='project_name', type=str, help='name of project')
args = parser.parse_args(["--datasheet-path", "./path_to_project", "--project-name", "name_of_project"])
print(args)
Running this script gives us...
$ python parseArgs.py
Namespace(datasheet_path='./path_to_project', project_name='name_of_project')
First point: the second argument to parser.parse_args is :
An object to take the attributes. The default is a new empty Namespace object.
Which explains your first error (strings are immutable, you can't set attributes on them).
Second point: by prefixing your arguments names with "-", you make them named arguments, so you have to pass them as such, not as positional arguments.
Yes you're passing them improperly. They should be in a sequence, like a list:
args = parser.parse_args(["./path_to_project", "name_of_project"])
Thanks to Anthony Sottile for pointing this out in a comment
The reason for that error is parse_args is expecting its second argument to be a namespace. From the documentation:
ArgumentParser.parse_args(args=None, namespace=None)
Convert argument strings to objects and assign them as attributes of the namespace.
However, then you get another error:
usage: test.py [-h] -dspath DATASHEET_PATH -pname PROJECT_NAME
test.py: error: the following arguments are required: -dspath/--datasheet-path, -pname/--project-name
Which you can fix by passing the required options:
args = parser.parse_args(["-dspath", "./path_to_project", "-pname", "name_of_project"])
Or by turning your options into positional arguments:
parser.add_argument('datasheet_path', help='path to data')
parser.add_argument('project_name', help='name of project')
args = parser.parse_args(["./path_to_project", "name_of_project"])
print(args)
# Namespace(datasheet_path='./path_to_project', project_name='name_of_project')
BTW type=str is implied and I switched the argument names to have underscores instead of dashes.
replace datasheet_path with datasheet-path

nargs depending on another setting?

I'm trying to write a program that supports arbitrary bitwise opertions: AND, OR, NOT and COUNT for bitmaps. The usage is that you run program.py --and f1.bit f2.bit and it prints you the result to the stdout.
The problem is that I'd like the parser to handle all the caveats. Specifically, I'd like the nargs to depend on the mode that's set - if it's set to COUNT or NOT, exactly one file is expected, if it's set to OR or AND, expect exactly two. Here's some (non-working) example code:
#!/usr/bin/env python
import argparse
def main(mode, fnames):
pass
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('-O', '--or',
nargs=2,
action='store_const', const='or'
)
args = parser.parse_args()
import pprint
pprint.pprint(args.__dict__)
#main(**args.__dict__)
And the error I'm getting:
Traceback (most recent call last):
File "bitmaptool.py", line 12, in <module>
action='store_const', const='or'
File "/usr/lib/python3.7/argparse.py", line 1362, in add_argument
action = action_class(**kwargs)
TypeError: __init__() got an unexpected keyword argument 'nargs'
Commenting out nargs helps, as does leaving nargs out but commenting out action - but I want both. Do I need to implement it manually or is there a trick or another library that would let me get there?
EDIT I wanted to clarify what I'm looking for by showing what code I needed to write manually for the thing to work:
if __name__ == '__main__':
parser = argparse.ArgumentParser(argument_default=argparse.SUPPRESS)
parser.add_argument('-O', '--or', nargs=2)
parser.add_argument('-A', '--and', nargs=2)
parser.add_argument('-M', '--minus', nargs=2)
parser.add_argument('-C', '--count', nargs=1)
parser.add_argument('-N', '--not', nargs=1)
parser.add_argument('-o', '--output', default='/dev/stdout')
args = parser.parse_args().__dict__
mode = None
files = []
for current_mode in ['or', 'and', 'not', 'count']:
if current_mode in args:
if mode is not None:
sys.exit('ERROR: more than one mode was specified')
mode = current_mode
files = args[mode]
if mode is None:
sys.stderr.write('ERROR: no mode was specified\n\n')
parser.print_help()
sys.exit(1)
import pprint
pprint.pprint(args)
Is there a more elegant way to get there?
store_const never gets arguments, it literally stores what you stated as const or None. Because it's a constant, not a variable. From the argparse's action documentation, ephasis mine:
'store_const' - This stores the value specified by the const keyword argument. The 'store_const' action is most commonly used with optional arguments that specify some sort of flag.
You should change the action to something that will actually store the filenames passed. As per argparse's nargs documentation and example, you actually don't need to specify action at all, default (action='store') will suffice.
Example from documentation:
>>> parser = argparse.ArgumentParser()
>>> parser.add_argument('--foo', nargs=2) #this line
>>> parser.add_argument('bar', nargs=1)
>>> parser.parse_args('c --foo a b'.split())
Namespace(bar=['c'], foo=['a', 'b'])
EDIT for the edited version of the question - mutually exclusive group will make sure only one argument (from that group, of course) is specified:
if __name__ == '__main__':
parser = argparse.ArgumentParser(argument_default=argparse.SUPPRESS)
parser.add_argument('-o', '--output', default='/dev/stdout')
group = parser.add_mutually_exclusive_group(required=True)
group.add_argument('-O', '--or', nargs=2)
group.add_argument('-A', '--and', nargs=2)
group.add_argument('-M', '--minus', nargs=2)
group.add_argument('-C', '--count', nargs=1)
group.add_argument('-N', '--not', nargs=1)
args = parser.parse_args().__dict__
import pprint
pprint.pprint(args)

How to access a python argparse argument with a dot in the name

Python's argparse lets me define argument names containing a dot in the name. But how can I access these ?
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("inputfile.txt")
parser.add_argument("outputfile.txt")
args = parser.parse_args(['hello', 'world'])
# now args is:
# Namespace(inputfile.txt='hello', outputfile.txt='world')
# and this does not work
print(args.inputfile.txt)
>>> AttributeError: 'Namespace' object has no attribute 'inputfile'
Obviously attribute names can be created with a dot in their name but how can these be accessed ?
Edit:
My goal was to let argparse display the inputfile.txt name (e.g. with --help) but call the attribute "inputfile".
After trying some of the suggestions the easiest way to accomplish this is using the metavar option:
parser.add_argument("inputfile", metavar="inputfile.txt")
Internally, argparse will add all attributes to the Namespace() instance with setattr. Accordingly, you can access the values with getattr:
getattr(args, 'inputfile.txt')
However, this is not as intuitive and in general attribute names with dots in them should be avoided. It is recommended to use the dest option of argparse.add_argument to define your own variable in which to store the value for that argument, as hd1 suggests in their answer.
Rename the argument to inputfile and use metavar to set the display value for the user.
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("inputfile", metavar = "inputfile.txt")
parser.add_argument("outputfile", metavar = "outputfile.txt")
args = parser.parse_args(['hello', 'world'])
# now args is:
# Namespace(inputfile='hello', outputfile='world')
print(args.inputfile)
Why not use FileType objects instead?
>>> import argparse
>>>
>>> parser = argparse.ArgumentParser()
>>> parser.add_argument('--infile', type=argparse.FileType('r'))
_StoreAction(option_strings=['--infile'], dest='infile', nargs=None, const=None, default=None, type=FileType('r'), choices=None, help=None, metavar=None)
>>> parser.add_argument('--outfile', type=argparse.FileType('w'))
_StoreAction(option_strings=['--outfile'], dest='outfile', nargs=None, const=None, default=None, type=FileType('w'), choices=None, help=None, metavar=None)
>>> parser.parse_args(['--infile', 'input.txt', '--outfile', 'output.txt'])
Namespace(infile=<open file 'input.txt', mode 'r' at 0x100f99e40>, outfile=<open file 'output.txt', mode 'w' at 0x100f99ed0>)
Using the dest option, you can assign it to anything:
parser = argparse.ArgumentParser()
parser.add_argument("inputfile.txt", dest='infile')
parser.add_argument("outputfile.txt", dest='out')
args = parser.parse_args(['hello', 'world'])
# now args is:
# Namespace(infile='hello', out='world')
Hope that helps.
I strongly recommend you to refactor your code to change the argument name.
But, if you won't or can't, this will do the job:
args.__dict__['inputfile.txt']

argparse module How to add option without any argument?

I have created a script using argparse.
The script needs to take a configuration file name as an option, and user can specify whether they need to proceed totally the script or only simulate it.
The args to be passed: ./script -f config_file -s or ./script -f config_file.
It's ok for the -f config_file part, but It keeps asking me for arguments for the -s which is optionnal and should not be followed by any.
I have tried this:
parser = argparse.ArgumentParser()
parser.add_argument('-f', '--file')
#parser.add_argument('-s', '--simulate', nargs = '0')
args = parser.parse_args()
if args.file:
config_file = args.file
if args.set_in_prod:
simulate = True
else:
pass
With the following errors:
File "/usr/local/lib/python2.6/dist-packages/argparse.py", line 2169, in _get_nargs_pattern
nargs_pattern = '(-*%s-*)' % '-*'.join('A' * nargs)
TypeError: can't multiply sequence by non-int of type 'str'
And same errror with '' instead of 0.
As #Felix Kling suggested use action='store_true':
>>> from argparse import ArgumentParser
>>> p = ArgumentParser()
>>> _ = p.add_argument('-f', '--foo', action='store_true')
>>> args = p.parse_args()
>>> args.foo
False
>>> args = p.parse_args(['-f'])
>>> args.foo
True
To create an option that needs no value, set the action [docs] of it to 'store_const', 'store_true' or 'store_false'.
Example:
parser.add_argument('-s', '--simulate', action='store_true')

Categories

Resources