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)
Related
This question already has answers here:
Argparse optional argument with different default if specified without a value
(2 answers)
Closed last month.
Here is my code:
from argparse import ArgumentParser, RawTextHelpFormatter
example_text = "test"
parser = ArgumentParser(description='my script.',
epilog=example_text,
formatter_class=RawTextHelpFormatter)
parser.add_argument('host', type=str, default="10.10.10.10",
help="Device IP address or Hostname.")
parser.add_argument('-j','--json_output', type=str, default="s", nargs='?',choices=["s", "l"],
help="Print GET statement in json form.")
#mutally exclusive required settings supplying the key
settingsgroup = parser.add_mutually_exclusive_group(required=True)
settingsgroup.add_argument('-k', '--key', type=str,
help="the api-key to use. WARNING take care when using this, the key specified will be in the user's history.")
settingsgroup.add_argument('--config', type=str,
help="yaml config file. All parameters can be placed in the yaml file. Parameters provided from form command line will take priority.")
args = parser.parse_args()
print(args.json_output)
my output:
None
Everything I am reading online says this should work, but it doesn't. Why?
You could use the const= parameter. const stores its value when the option is present but have no values
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('-j', '--json-output', nargs='?', choices=['s', 'l'], const='s')
args = parser.parse_args()
However design wise, it might be better to use the following:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('-o', '--output-type', choices=['json-s', 'json-l', 'normal'], default='normal')
args = parser.parse_args()
def main(argv):
parser = argparse.ArgumentParser()
parser.add_argument('p', 'projectType', type=str, help = 'c or c++ project type', choices=['c', 'c++'])
parser.add_argument('i', 'inputfile', type=pathlib.Path, help = 'the input file path')
parser.add_argument('o',"outputfile",type=pathlib.Path, help= 'the output file path')
parser.add_argument
args = parser.parse_args()
when i run this code on command prompt, and enter the inputfile first for example.. it gives me an error. does Argparse have an option like getopt (where i call something with a letter before inputting it so no mix up ex, '-i ...input...'). Here this option is just for optional arguments.
Is there a way for positional arguments to do that?
As per the argparse documentation you would define it as an "optional" argument but with the required flag set to true, e.g.:
parser.add_argument('-i', '--inputfile', required=True, type=pathlib.Path, help='the input file path')
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)
I am in the bit of a weird situation where I need a Python function to run from within a script, with the script then called from my main code.
I wanted to use the subprocess module, and know how to use it to pass arguments to a pure script, but the thing is, I need to pass the arguments to the nested Python function within, most of which are optional and have default values.
I thought arparse would help me do this somehow.
Here is an example of what I am trying:
## Some Argparse, which will hopefully help
import argparse
parser = argparse.ArgumentParser()
## All arguments, with only "follow" being required
parser.add_argument('file_name', help='Name of resulting csv file')
parser.add_argument('sub_name', help='Sub-name of resulting csv file')
parser.add_argument('follow', help='Account(s) to follow', required=True)
parser.add_argument('locations', help='Locations')
parser.add_argument('languages', help='Languages')
parser.add_argument('time_limit', help='How long to keep stream open')
args = parser.parse_args()
## Actual Function
def twitter_stream_listener(file_name=None,
sub_name='stream_',
auth = api.auth,
filter_track=None,
follow=None,
locations=None,
languages=None,
time_limit=20):
... function code ...
... more function code ...
...
...
## End of script
If you are passing arguments to functions all you need to do is feed them into the function when you're executing them:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("-o", "--output_file_name", help="Name of resulting csv file")
parser.add_argument("-s", "--sub_name", default="stream_", help="Sub-name of resulting csv file")
parser.add_argument("-f", "--follow", help="Account(s) to follow", required=True)
parser.add_argument("-loc", "--locations", default=None, help="Locations")
parser.add_argument("-lan", "--languages", default=None, help="Languages")
parser.add_argument("-t", "--time_limit", default=20, help="How long to keep stream open")
options = parser.parse_args()
# then just pass in the arguments when you run the function
twitter_stream_listener(file_name=options.output_file_name,
sub_name=options.sub_name,
auth=api.auth,
filter_track=None,
follow=options.follow,
locations=options.locations,
languages=options.languages,
time_limit=options.time_limit)
# or, pass the arguments into the functions when defining your function
def twitter_stream_listener_with_args(file_name=options.output_file_name,
sub_name=options.sub_name,
auth=api.auth,
filter_track=None,
follow=options.follow,
locations=options.locations,
languages=options.languages,
time_limit=options.time_limit):
# does something
pass
# then run with default parameters
twitter_stream_listener_with_args()
You can specify defaults in the argparse section (if that is what you are trying to achieve):
#!/usr/bin/python
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('--argument', default = 'something', type = str, help = 'not helpful')
parser.add_argument('--arg2', default = None, type = str, help = 'not helpful')
args = parser.parse_args()
def foo(arg , arg2 ):
print(arg)
if not arg2 is None:
print(arg2)
foo(args.argument, args.arg2)
Then calling:
$ ./test.py
something
$ ./test.py --argument='somethingelse'
somethingelse
$ ./test.py --arg2=123
something
123
$ ./test.py --arg2='ipsum' --argument='lorem'
lorem
ipsum
Is this helpful?
You can do it like that:
import argparse
## Actual Function
def twitter_stream_listener(file_name=None,
sub_name='stream_',
auth=api.auth,
filter_track=None,
follow=None,
locations=None,
languages=None,
time_limit=20):
# Your content here
if __name__ == '__main__':
parser = argparse.ArgumentParser()
## All arguments, with only "follow" being required
parser.add_argument('follow', help='Account(s) to follow')
parser.add_argument('--file_name', help='Name of resulting csv file')
parser.add_argument('--sub_name', help='Sub-name of resulting csv file')
parser.add_argument('--locations', help='Locations')
parser.add_argument('--languages', help='Languages')
parser.add_argument('--time_limit', help='How long to keep stream open')
args = parser.parse_args()
twitter_stream_listener(file_name=args.file_name, sub_name=args.sub_name, follow=args.follow,
locations=args.locations, languages=args.languages, time_limit=args.time_limit)
follow will be the only required argument and the rest optional. Optional ones have to be provided with -- at the beginning. You can easily use the module with subprocess if you need it.
Example call using command line:
python -m your_module_name follow_val --file_name sth1 --locations sth2
I am using Python argparse to take in parameters through the CLI. I have tried using the following but when I don't give any one of the arguments, it gives the output as None. I want then default ones to be the ones provided in const=. Please take a look.
parser = argparse.ArgumentParser()
parser.add_argument('--input', nargs='?', const='testInput')
parser.add_argument('--target', nargs='?', const='testTarget')
parser.add_argument('--msg', nargs='?', const='helloFromTheOtherSide')
args = parser.parse_args()
print args.input
If I don't give input, it prints it as None as I said. I want it to print TestInput instead..
Use the default argument:
parser = argparse.ArgumentParser()
parser.add_argument('--input', nargs='?', default='testInput')
parser.add_argument('--target', nargs='?', default='testTarget')
parser.add_argument('--msg', nargs='?', default='helloFromTheOtherSide')
args = parser.parse_args()
print args.input
With
parser.add_argument('--input', nargs='?', default='testInput', const='aConst')
you have a 3 way choice
prog # input='testInput'
prog --input # input='aConst'
prog --input myfile # input='myfile'
If you don't need that aConst option, omit the nargs='?'. Since it is a flagged argument it is already optional. It doesn't need the `?'.
parser.add_argument('--input', default='testInput')